はじめに
みなさま,はじめまして.
株式会社オプティマインドにて,GISエンジニアをしている@tkmbnです.
Qiitaへの初投稿です.
概要
時間枠(日時の組み合わせ,開始日時〜終了日時)のあれやこれをしてくれるライブラリtime-windowの使い方を解説します.
複雑な時間枠をスッキリまとめてくれたりします!←このライブラリを使って一番やりたいこと.
なぜ書いたか
DBから時間枠つきのデータを取得する際に,時間枠に重なりがあればまとめてほしいという依頼がありました.
どうにかこうにか自力で実装しようとしたんですが,混乱しだして,「なんか良いツールないかなぁ...」と探していたところ上記のライブラリに出会いました.
readme以外にもいろいろと便利そうな機能もあったので,自分への覚書も含め,記事にしました.
まるまる解説!というわけではないので,あしからず...
本題
インストール方法
pip install time-window
具体的な使い方
最初の方は,readmeの日本語訳的なものと思ってください笑
TimeWindow オブジェクト
作り方
2020年03月01日12:00:00
から 2020年03月01日15:00:00
のTimeWindowを作りたいときは...
from datetime import datetime
from time_window import TimeWindow
t1 = datetime(2020, 3, 1, 12, 00, 00)
t2 = datetime(2020, 3, 1, 15, 00, 00)
tw1 = TimewWindow(t1, t2)
tw1
-> TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 15, 0))
このとき,時間枠は,[t1, t2)
になることに注意!
また,timedeltaでも作成可能です.
from datetime import datetime, timedelta
from time_window import TimeWindow
t1 = datetime(2020, 3, 1, 12, 00, 00)
delta = timedelta(hours=3)
tw2 = TimeWindow.from_timedelta(t1, delta)
tw2
-> TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 15, 0))
同じ結果が得られました.
delta, middle
時間枠の差分を知りたいときは,
tw1.delta
-> datetime.timedelta(0, 10800)
時間枠の中間の時点を知りたいときは,
tw1.middle
-> datetime.datetime(2020, 3, 1, 13, 30)
overlaps
tw = TimeWindow(datetime(2020, 3, 1, 12, 0), datetime(2020, 3, 1, 15, 0))
tw2 = TimeWindow(datetime(2020, 3, 1, 13, 0), datetime(2020, 3, 1, 18, 0))
tw.overlaps(tw2)
-> True
重なっていれば,True, そうでなければ,False.
contains(readme未掲載)
tw = TimeWindow(datetime(2020, 3, 1, 12, 0), datetime(2020, 3, 1, 15, 0))
tw4 = TimeWindow(datetime(2020, 3, 1, 13, 0), datetime(2020, 3, 1, 14, 0))
tw.contains(tw4)
-> True
含まれていれば,True, そうでなければ,False.
contiguous
tw = TimeWindow(datetime(2020, 3, 1, 12, 0), datetime(2020, 3, 1, 15, 0))
tw3 = TimeWindow(datetime(2020, 3, 1, 15, 0), datetime(2020, 3, 1, 18, 0))
tw.contiguous(tw3)
-> [TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 15, 0)),
TimeWindow(datetime.datetime(2020, 3, 1, 15, 0), datetime.datetime(2020, 3, 1, 18, 0))]
接している場合は,TimeWindowのリストが,接していない場合は,Falseが返ってくる.
set型みたいな事もできる
積集合
tw = TimeWindow(datetime(2020, 3, 1, 12, 0), datetime(2020, 3, 1, 15, 0))
tw2 = TimeWindow(datetime(2020, 3, 1, 13, 0), datetime(2020, 3, 1, 18, 0))
tw.intersection(tw2)
-> TimeWindow(datetime.datetime(2020, 3, 1, 13, 0), datetime.datetime(2020, 3, 1, 15, 0))
和集合
tw.union(tw2)
-> TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 18, 0))
TimeWindowsCollection オブジェクト (readme未掲載)
作り方
from datetime import datetime, timedelta
from time_window import TimeWindow, TimeWindowsCollection
tw = TimeWindow(datetime(2020, 3, 1, 13, 0), datetime(2020, 3, 1, 18, 0))
tw2 = TimeWindow(datetime(2020, 3, 1, 12, 0), datetime(2020, 3, 1, 15, 0))
twc = TimeWindowsCollection([tw, tw2])
twc
-> [TimeWindow(datetime.datetime(2020, 3, 1, 13, 0), datetime.datetime(2020, 3, 1, 18, 0)),
TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 15, 0))]
##開始時刻で並べ替えたい!
twc.time_windows_sorted_by_since
-> [TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 15, 0)),
TimeWindow(datetime.datetime(2020, 3, 1, 13, 0), datetime.datetime(2020, 3, 1, 18, 0))]
複数の時間枠をまとめたい
これで自分のやりたいことは,完璧にできました.
tw = TimeWindow(datetime(2020, 3, 1, 13, 0), datetime(2020, 3, 1, 18, 0))
tw2 = TimeWindow(datetime(2020, 3, 1, 12, 0), datetime(2020, 3, 1, 15, 0))
tw3 = TimeWindow(datetime(2020, 3, 1, 19, 0), datetime(2020, 3, 1, 21, 0))
twc = TimeWindowsCollection([tw, tw2, tw3])
twc
-> [TimeWindow(datetime.datetime(2020, 3, 1, 13, 0), datetime.datetime(2020, 3, 1, 18, 0)),
TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 15, 0)),
TimeWindow(datetime.datetime(2020, 3, 1, 19, 0), datetime.datetime(2020, 3, 1, 21, 0))]
twc.compressed()
-> [TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 18, 0)),
TimeWindow(datetime.datetime(2020, 3, 1, 19, 0), datetime.datetime(2020, 3, 1, 21, 0))]
重なり合っている時間枠はまとまり,重なっていないものは別の時間枠となっています.
しかし,落とし穴がありました.
普通にインデックス指定して,TimeWindowを取り出そうとしたところ,
twc.compressed()[0]
-> Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'TimeWindowsCollection' object does not support indexing
返ってくる形見ると,普通のリストなんですが,どうやら違うみたいです...
TimeWindowsCollectionオブジェクトをTimeWindowのリストに戻してやる必要があるので,
twc.compressed().time_windows
-> [TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 18, 0)),
TimeWindow(datetime.datetime(2020, 3, 1, 19, 0), datetime.datetime(2020, 3, 1, 21, 0))]
twc.compressed().time_windows[0]
TimeWindow(datetime.datetime(2020, 3, 1, 12, 0), datetime.datetime(2020, 3, 1, 18, 0))
無事取り出せることができました!!
参考文献
最後に
最後まで読んでいただきありがとうございます!
なにか疑問点,間違っている点,等ございましたら,コメントお願いいたします.