「daterange」 rangeっぽい連番日付文字列ジェネレータ

[pukiwiki]
Pythonのrange関数っぽい感じで、日付を扱える互換品(?)を作ってみました。
<<追記>>
日付文字列でなく、time型使ったほうがすっきり書けるかも。
記事最後に追記
[/pukiwiki]

クローラで収集したデータなど、ファイル名が日付になっているものを処理するときなどに。
(最初は、日付ごとにコールバック関数を呼び出すようにしてたのですが、それだと処理がややこしくなったので、range関数っぽく書き直してみました。このほうが使いやすー)

詳しくはソースを読んでいただくとして、、、

パラメータの指定のしかたによって、微妙に挙動が、直感と違う場合がありますのでご注意
(特に、stepに負数や小数点以下を使用した場合や、 開始日よりも終了日のほうが前の場合など)

daterange(開始日付文字列, 終了日付文字列, ステップ)

または daterange(開始日付文字列,日数 ,ステップ)

キーワード引数 format=日付形式指定文字列
・%y/%m/%d  09/04/17
・%Y-%m-%d 2009-04-17
・%Y/%m/%d %H:%M 2009/04/17 00:00

timeモジュールを使ってるので、時刻も指定できたりします。

step=3/24.   で3時間ごとの時刻文字列作成、などなど   

動作サンプル



>>> [x for x in daterange("20090417",3)]
['20090417', '20090418', '20090419']

>>> [x for x in daterange("2009/04/17 09:00","2009/04/17 11:30",step=0.5/24.,format="%Y/%m/%d %H:%M")]
['2009/04/17 09:00', '2009/04/17 09:30', '2009/04/17 10:00', '2009/04/17 10:30', '2009/04/17 11:00', '2009/04/17 11:30']


#!/usr/bin/env python
# -*- coding: utf8 -*-
"daterange.py"
import time
import types
        
def sgn(x) : return 1 if x>0 else -1 if x<0 else 0

def daterange(date_start,date_end,step=1,
              format="%Y%m%d",oneday=24*60*60,step_sec=0):
    u"""
・daterange(開始日付文字列, 終了日付文字列, ステップ)
・daterange(開始日付文字列,日数 ,ステップ)
・キーワード引数 format=日付形式指定文字列
    """
    if not step and not step_sec:
        return
    elif not step_sec :
        step_sec=step*oneday
        
    t0=time.strptime(date_start ,format)
    s0=time.mktime(t0)
    t=type(date_end)
    if t == types.StringType :
        t1=time.strptime(date_end ,format)
        s1=time.mktime(t1)
        if sgn(s1-s0)!=sgn(step_sec):
            step_sec*=-1.
        for s in xrange(s0,s1,step_sec):
            yield time.strftime(format,time.localtime(s))
        yield date_end

    else :
                
        if sgn(date_end)!=sgn(step_sec):
            step_sec*=-1.
        for s in xrange(0,oneday*date_end,step_sec):
            yield time.strftime(format,time.localtime(s0+s))


if __name__=="__main__":
    format="%y-%m-%d"
    dt1="20090417"
    dt2="20090423"
    
    date1=[x for x in daterange(dt1,dt2)]    
    date2=[x for x in daterange(dt2,dt1)]
    date3=[x for x in daterange(dt1,7)]
    date4=[x for x in daterange(dt2,-7,1)]
    
    date2.reverse()
    date4.reverse()
    
    assert date1==date2==date3==date4 ,"error\n%s\n%s\n%s\n%s"%(date1,date2,date3,date4)
    print "OK"
    for i,dt in enumerate(daterange(dt1,dt2)) :
        print i,dt

<<追記>>
文字列でなく、timeモジュール使ったほうがスッキリ書けるかも。

import time
oneday=24*60*60
def timedelta(t,x):
    return time.localtime(time.mktime(t)+x)
def timerange(time_start,time_end,
              step=oneday):
    s0=time.mktime(time_start)
    s1=time.mktime(time_end)
    
    for s in xrange(s0,s1,step):
        yield time.localtime(s)
    yield time_end
if __name__=="__main__":
    fmt="%Y/%m/%d"
    t0=time.strptime("2009/04/18",fmt)
    for t in timerange(t0,timedelta(t0,(7-1)*oneday),oneday):
        print time.strftime(fmt,t)

実行例

2009/04/18
2009/04/19
2009/04/20
2009/04/21
2009/04/22
2009/04/23
2009/04/24

コメントを残す

メールアドレスが公開されることはありません。