2012-10-25 13 views
15

の次の四半期に日時がのは、私がパイソン - 切り上げ時間

datetime.datetime(2012, 10, 25, 17, 45) 

を得るために、時間の次の四半期にそれを切り上げしたい

>>> import datetime 
>>> dt = datetime.datetime(2012, 10, 25, 17, 32, 16) 

この日時を想像してみましょう私は

>>> quarter = datetime.timedelta(minutes=15) 
>>> import math 
>>> ceiled_dt = math.ceil(dt/quarter) * quarter 

のようなものは、しかし、もちろん、これは動作しません想像

答えて

16

これはマイクロ秒を考慮したものです。 delta

import math 

def ceil_dt(dt): 
    # how many secs have passed this hour 
    nsecs = dt.minute*60 + dt.second + dt.microsecond*1e-6 
    # number of seconds to next quarter hour mark 
    # Non-analytic (brute force is fun) way: 
    # delta = next(x for x in xrange(0,3601,900) if x>=nsecs) - nsecs 
    # analytic way: 
    delta = math.ceil(nsecs/900) * 900 - nsecs 
    #time + number of seconds to quarter hour mark. 
    return dt + datetime.timedelta(seconds=delta) 

t1 = datetime.datetime(2017, 3, 6, 7, 0) 
assert ceil_dt(t1) == t1 

t2 = datetime.datetime(2017, 3, 6, 7, 1) 
assert ceil_dt(t2) == datetime.datetime(2017, 3, 6, 7, 15) 

t3 = datetime.datetime(2017, 3, 6, 7, 15) 
assert ceil_dt(t3) == t3 

t4 = datetime.datetime(2017, 3, 6, 7, 16) 
assert ceil_dt(t4) == datetime.datetime(2017, 3, 6, 7, 30) 

t5 = datetime.datetime(2017, 3, 6, 7, 30) 
assert ceil_dt(t5) == t5 

t6 = datetime.datetime(2017, 3, 6, 7, 31) 
assert ceil_dt(t6) == datetime.datetime(2017, 3, 6, 7, 45) 

t7 = datetime.datetime(2017, 3, 6, 7, 45) 
assert ceil_dt(t7) == t7 

t8 = datetime.datetime(2017, 3, 6, 7, 46) 
assert ceil_dt(t8) == datetime.datetime(2017, 3, 6, 8, 0) 

説明:

  • 900秒15分(時間の四半期サンセリフ私はdatetime型のハンドルを考えていないうるう秒...
  • nsecs/900されています出現した四分の一時間のチャンクの数。これのceilを取ると、四半期のチャンク数が切り上げられます。
  • 「四捨五入」後の時間の開始から何秒が経過したかを把握するために、四半時間のチャンクの数に900を掛けます。
+0

うまく働いています。最もシンプルに思える。ありがとう –

+0

私は900の代わりに3600とそれを試して、それは動作していません。時間がすでに丸められていても3600を追加します。 – Anuj

+1

デルタ= math.ceil(nsecs/900.)* 900. – mgilson

7
def ceil(dt): 
    if dt.minute % 15 or dt.second: 
     return dt + datetime.timedelta(minutes = 15 - dt.minute % 15, 
             seconds = -(dt.second % 60)) 
    else: 
     return dt 

これがあなたに与えます:

>>> ceil(datetime.datetime(2012,10,25, 17,45)) 
datetime.datetime(2012, 10, 25, 17, 45) 
>>> ceil(datetime.datetime(2012,10,25, 17,45,1)) 
datetime.datetime(2012, 10, 25, 18, 0) 
>>> ceil(datetime.datetime(2012,12,31,23,59,0)) 
datetime.datetime(2013,1,1,0,0) 
+3

あなたの場所にdt' 'で動作するので、これは少しファンキーですが、あなたはそれを返します。 APIの観点からは、どちらか一方を実行する必要があるようです...(また、これはマイクロ秒を考慮に入れません) – mgilson

+0

@mgilson:コメントをいただきありがとうございます。私は、OPがそれらなしで彼のdatetimesを構築していたので、マイクロ秒を無視しました。しかし、それが彼の実際の使用事例でないならば、もちろんそれは問題かもしれません。 –

+0

うん。私はあなたがAPIのものを修正したので、それで十分満足しています(+1) – mgilson

2

をあなたはそれがすべてのケースのために働くゼロ

import datetime 

def quarter_datetime(dt): 
    minute = (dt.minute//15+1)*15 
    return dt.replace(minute=0, second=0)+datetime.timedelta(minutes=minute) 

for minute in [12, 22, 35, 52]: 
    print quarter_datetime(datetime.datetime(2012, 10, 25, 17, minute, 16)) 

に秒、正しい分を計算し、分を設定した後、DateTimeオブジェクトにそれらを追加する必要があります。

2012-10-25 17:15:00 
2012-10-25 17:30:00 
2012-10-25 17:45:00 
2012-10-25 18:00:00 
+0

これはPyrex 2.xで期待通りに動作することを除いて、Pierre GMの回答を複製したものです'' ''の上に ''/''を使用しているためです。 –

+0

@Lattyware私は同じ時刻に投稿した+今はバグを修正したのと同じではないと彼の解決方法には欠陥がある –

+0

素晴らしいですが、 ''/'' over "' ''はまだ最適ではない。また、他人が回答を投稿したときに通知するので、回答を複製していないことを確認する前に探しておく価値があります。 –

4

@Mark Dickinson suggestedこれまで最高の式:のPython 3で

def ceil_dt(dt, delta): 
    return dt + (datetime.min - dt) % delta 

、任意の時間デルタ(だけでなく、15分間):

#!/usr/bin/env python3 
import math 
from datetime import datetime, timedelta 

def ceil_dt(dt, delta): 
    return datetime.min + math.ceil((dt - datetime.min)/delta) * delta 

print(ceil_dt(datetime(2012, 10, 25, 17, 32, 16), timedelta(minutes=15))) 
# -> 2012-10-25 17:45:00 

中間フロートを避けるためにdivmod()を使用することができる:

def ceil_dt(dt, delta): 
    q, r = divmod(dt - datetime.min, delta) 
    return (datetime.min + (q + 1)*delta) if r else dt 

例:

>>> ceil_dt(datetime(2012, 10, 25, 17, 32, 16), timedelta(minutes=15)) 
datetime.datetime(2012, 10, 25, 17, 45) 
>>> ceil_dt(datetime.min, datetime.resolution) 
datetime.datetime(1, 1, 1, 0, 0) 
>>> ceil_dt(datetime.min, 2*datetime.resolution) 
datetime.datetime(1, 1, 1, 0, 0) 
>>> ceil_dt(datetime.max, datetime.resolution) 
datetime.datetime(9999, 12, 31, 23, 59, 59, 999999) 
>>> ceil_dt(datetime.max, 2*datetime.resolution) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in ceil_dt 
OverflowError: date value out of range 
>>> ceil_dt(datetime.min+datetime.resolution, datetime.resolution) 
datetime.datetime(1, 1, 1, 0, 0, 0, 1) 
>>> ceil_dt(datetime.min+datetime.resolution, 2*datetime.resolution) 
datetime.datetime(1, 1, 1, 0, 0, 0, 2) 
>>> ceil_dt(datetime.max-datetime.resolution, datetime.resolution) 
datetime.datetime(9999, 12, 31, 23, 59, 59, 999998) 
>>> ceil_dt(datetime.max-datetime.resolution, 2*datetime.resolution) 
datetime.datetime(9999, 12, 31, 23, 59, 59, 999998) 
>>> ceil_dt(datetime.max-2*datetime.resolution, datetime.resolution) 
datetime.datetime(9999, 12, 31, 23, 59, 59, 999997) 
>>> ceil_dt(datetime.max-2*datetime.resolution, 2*datetime.resolution) 
datetime.datetime(9999, 12, 31, 23, 59, 59, 999998) 
>>> ceil_dt(datetime.max-timedelta(1), datetime.resolution) 
datetime.datetime(9999, 12, 30, 23, 59, 59, 999999) 
>>> ceil_dt(datetime.max-timedelta(1), 2*datetime.resolution) 
datetime.datetime(9999, 12, 31, 0, 0) 
>>> ceil_dt(datetime.min, datetime.max-datetime.min) 
datetime.datetime(1, 1, 1, 0, 0) 
>>> ceil_dt(datetime.max, datetime.max-datetime.min) 
datetime.datetime(9999, 12, 31, 23, 59, 59, 999999) 
+3

Python 3に制限しているなら、もっと簡単な式 'dt +(d​​atetime.min - dt)%delta'も動作します。 –

+0

@ MarkDickinson:はい。これはCPythonで動作します(答えのすべての例)。答えとして 'def ceil_dt(dt、delta):return dt +(d​​atetime.min - dt)%delta'を投稿してください。 – jfs

関連する問題