日付っぽい文字列をアレしたりepochをアレしたりするやつ

Pythonのリハビリがてら車輪の再発明をしてこんなのを書いた。 たまによく、変換するためにわざわざネットでやっていたから再発明した。

$ ./dt.py '2015-02-18 12:34:56'
1424230496
$ ./dt.py '2015-02-18'
1424185200
$ ./dt.py 1424230496
2015-02-18 12:34:56
$ echo "2015-02-18 12:34:56\n2001-07-04 16:07\nhoge\n2072-09-18" | ./dt.py
1424230496
994230420

3241350000
$ echo "1424230496\n994230422\n3241415231" | ./dt.py
2015-02-18 12:34:56
2001-07-04 16:07:02
2072-09-18 18:07:11

そーす

#!/usr/bin/env python

"""
Convert between epoch and datetime string

usage:
    dt.py
    dt.py <epoch_or_datetime>
    dt.py -h | --help

options:
    -h, --help  show this help message and exit
"""

import re
from sys import stdin
from time import localtime, mktime
from datetime import datetime
from docopt import docopt

def epoch2datetime(epoch):
    return datetime(*localtime(epoch)[:6])

def datetime2epoch(match):
    dtstr, space = match.group(0), match.group(1)
    dt = datetime.strptime(dtstr, _parse_format(dtstr, space))
    return int( mktime(dt.timetuple()) )

def _parse_format(dtstr, space):
    length = len(dtstr)
    if length < 13: return '%Y-%m-%d'
    if length < 16: return '%Y-%m-%d' + space + '%H'
    if length < 19: return '%Y-%m-%d' + space + '%H:%M'
    return '%Y-%m-%d' + space + '%H:%M:%S'

def process_line(line):
    match = re.match(r'^\d{4}-\d{2}-\d{2}(?:([T ])\d{2}(?::\d{2}(?::\d{2})?)?)?$', line)
    if match:
        print datetime2epoch(match)
    elif re.match(r'^\d+$', line):
        print epoch2datetime(int(line))
    else:
        print


if __name__ == '__main__':
    args = docopt(__doc__)
    if args['<epoch_or_datetime>']:
        process_line(args['<epoch_or_datetime>'])
    else:
        for line in stdin.readlines():
            process_line(line)

やったこと

  • docoptを使ってみた
  • 日付っぽい文字列を自分が使いそうなパターンで定義した
  • 標準入力から流せるようにした
  • 複数行に対応した
  • _parse_formatを1文で書こうと思ったけど失敗

感想

  • docopt、簡単に書けて便利
  • Pythonのdatetime周り、ちょっと使いにくい感ある
    • hoge2fugaのreturn行が苦しい
  • Pythonは比較的むちゃな書き方ができないなぁ、と再認識した
  • けっこうPython忘れていた
  • また自分用孫の手ツールを作りたい