2010-08-12 80 views
61

我有一個使用strptime()生成的日期時間對象。如何繞一個日期時間對象的分鐘python

>>> tm 
datetime.datetime(2010, 6, 10, 3, 56, 23) 

我需要做的是圍繞分鐘到最近的第10分鐘。到目前爲止,我一直在做的是採用分鐘值並使用round()。

min = round(tm.minute, -1) 

然而,與上面的例子中,它提供了一個無效的時候分鐘值大於56,即:3:60

什麼是更好的方式來做到這一點?日期時間是否支持這個?

回答

3

,如果你不想使用情況,您可以使用modulo操作:

minutes = int(round(tm.minute, -1)) % 60 

UPDATE

你要這樣呢?

def timeround10(dt): 
    a, b = divmod(round(dt.minute, -1), 60) 
    return '%i:%02i' % ((dt.hour + a) % 24, b) 

timeround10(datetime.datetime(2010, 1, 1, 0, 56, 0)) # 0:56 
# -> 1:00 

timeround10(datetime.datetime(2010, 1, 1, 23, 56, 0)) # 23:56 
# -> 0:00 

..如果你想要結果爲字符串。爲獲得日期時間結果,最好使用timedelta - 查看其他響應;)

+0

啊,但是那麼這裏的問題是,必須時刻提高以及 – 2010-08-12 01:10:35

+1

@Lucas曼喬 - 我的解決辦法也工作正常,我覺得更有意義。 – Omnifarious 2010-08-12 06:03:03

93

這會得到tm中存儲的datetime對象的'floor',並在tm之前舍入到10分鐘的標記。

tm = tm - datetime.timedelta(minutes=tm.minute % 10, 
          seconds=tm.second, 
          microseconds=tm.microsecond) 

如果想經典四捨五入到最接近的10分鐘大關,這樣做:

discard = datetime.timedelta(minutes=tm.minute % 10, 
          seconds=tm.second, 
          microseconds=tm.microsecond) 
tm -= discard 
if discard >= datetime.timedelta(minutes=5): 
    tm += datetime.timedelta(minutes=10) 

或本:

tm += datetime.timedelta(minutes=5) 
tm -= datetime.timedelta(minutes=tm.minute % 10, 
         seconds=tm.second, 
         microseconds=tm.microsecond) 
68

一般功能隨時圈中圓一個日期時間秒:

def roundTime(dt=None, roundTo=60): 
    """Round a datetime object to any time laps in seconds 
    dt : datetime.datetime object, default now. 
    roundTo : Closest number of seconds to round to, default 1 minute. 
    Author: Thierry Husson 2012 - Use it as you want but don't blame me. 
    """ 
    if dt == None : dt = datetime.datetime.now() 
    seconds = (dt.replace(tzinfo=None) - dt.min).seconds 
    rounding = (seconds+roundTo/2) // roundTo * roundTo 
    return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond) 

個樣品用時1小時四捨五入&30分鐘四捨五入:

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=60*60) 
2013-01-01 00:00:00 

print roundTime(datetime.datetime(2012,12,31,23,44,59,1234),roundTo=30*60) 
2012-12-31 23:30:00 
+5

不幸的是,這不適用於tz-aware datetime。應該使用'dt.replace(hour = 0,minute = 0,second = 0)'而不是'dt.min'。 – skoval00 2016-10-15 06:30:14

+1

@ skoval00 + druska根據您的建議進行編輯,以支持tz-aware datetime。謝謝! – 2016-10-18 23:56:31

+0

Thanks @ skoval00 - 我花了一段時間才弄清楚爲什麼該功能不適用於我的數據 – mmeclimate 2016-11-17 10:30:40

0
def get_rounded_datetime(self, dt, freq, nearest_type='inf'): 

    if freq.lower() == '1h': 
     round_to = 3600 
    elif freq.lower() == '3h': 
     round_to = 3 * 3600 
    elif freq.lower() == '6h': 
     round_to = 6 * 3600 
    else: 
     raise NotImplementedError("Freq %s is not handled yet" % freq) 

    # // is a floor division, not a comment on following line: 
    seconds_from_midnight = dt.hour * 3600 + dt.minute * 60 + dt.second 
    if nearest_type == 'inf': 
     rounded_sec = int(seconds_from_midnight/round_to) * round_to 
    elif nearest_type == 'sup': 
     rounded_sec = (int(seconds_from_midnight/round_to) + 1) * round_to 
    else: 
     raise IllegalArgumentException("nearest_type should be 'inf' or 'sup'") 

    dt_midnight = datetime.datetime(dt.year, dt.month, dt.day) 

    return dt_midnight + datetime.timedelta(0, rounded_sec) 
9

從最佳答案我使用,這避免了必須執行轉換到秒僅datetime對象修改爲適於版本並使得調用代碼更易讀:

def roundTime(dt=None, dateDelta=datetime.timedelta(minutes=1)): 
    """Round a datetime object to a multiple of a timedelta 
    dt : datetime.datetime object, default now. 
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute. 
    Author: Thierry Husson 2012 - Use it as you want but don't blame me. 
      Stijn Nevens 2014 - Changed to use only datetime objects as variables 
    """ 
    roundTo = dateDelta.total_seconds() 

    if dt == None : dt = datetime.datetime.now() 
    seconds = (dt - dt.min).seconds 
    # // is a floor division, not a comment on following line: 
    rounding = (seconds+roundTo/2) // roundTo * roundTo 
    return dt + datetime.timedelta(0,rounding-seconds,-dt.microsecond) 

樣品用時1小時四捨五入&15分鐘四捨五入:

print roundTime(datetime.datetime(2012,12,31,23,44,59),datetime.timedelta(hour=1)) 
2013-01-01 00:00:00 

print roundTime(datetime.datetime(2012,12,31,23,44,49),datetime.timedelta(minutes=15)) 
2012-12-31 23:30:00 
+0

也不好:'print roundTime(datetime.datetime(2012,12,20,23,44,49),datetime.timedelta(days = 15))' '2012-12-20 00:00:00' while 'print roundTime(datetime.datetime(2012,12,21,23,44,49),datetime.timedelta(days = 15))' '2012-12-21 00:00:00' – CPBL 2016-12-08 18:53:45

+1

後續行動上面:只是指出它不適用於任意時間增量,例如那些超過1天。這個問題是關於舍入分鐘的,所以這是一個適當的限制,但是它可以在代碼編寫的方式上更清楚。 – CPBL 2016-12-23 12:16:23

0

基於Stijn Nevens和經過修改的Django用於將當前時間舍入爲最接近的15分鐘。

from datetime import date, timedelta, datetime, time 

    def roundTime(dt=None, dateDelta=timedelta(minutes=1)): 

     roundTo = dateDelta.total_seconds() 

     if dt == None : dt = datetime.now() 
     seconds = (dt - dt.min).seconds 
     # // is a floor division, not a comment on following line: 
     rounding = (seconds+roundTo/2) // roundTo * roundTo 
     return dt + timedelta(0,rounding-seconds,-dt.microsecond) 

    dt = roundTime(datetime.now(),timedelta(minutes=15)).strftime('%H:%M:%S') 

dt = 11:45:00 

,如果你需要完整的日期和時間,只是刪除.strftime('%H:%M:%S')

5

我用斯泰恩Nevens代碼有很大的影響(謝謝斯泰恩),並有一個小插件來分享。四捨五入到最近的四捨五入。

def round_time(dt=None, date_delta=timedelta(minutes=1), to='average'): 
    """ 
    Round a datetime object to a multiple of a timedelta 
    dt : datetime.datetime object, default now. 
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute. 
    from: http://stackoverflow.com/questions/3463930/how-to-round-the-minute-of-a-datetime-object-python 
    """ 
    round_to = date_delta.total_seconds() 

    if dt is None: 
     dt = datetime.now() 
    seconds = (dt - dt.min).seconds 

    if to == 'up': 
     # // is a floor division, not a comment on following line (like in javascript): 
     rounding = (seconds + round_to) // round_to * round_to 
    elif to == 'down': 
     rounding = seconds // round_to * round_to 
    else: 
     rounding = (seconds + round_to/2) // round_to * round_to 

return dt + timedelta(0, rounding - seconds, -dt.microsecond) 
+0

這對我有幫助。我想補充一點,如果在PySpark中使用它,將日期時間解析爲字符串而不是日期時間對象。 – Max 2016-09-22 01:24:11

+1

'上'四捨五入也許沒有達到大多數人的期望。即使dt不需要四捨五入,你也可以湊到下一個date_delta。 15:30:00.000與round_to = 60將成爲15:31:00.000 – spinxz 2017-09-18 10:55:55

0

當捕獲到異常時不是速度最好的,但是這會起作用。

def _minute10(dt=datetime.utcnow()): 
    try: 
     return dt.replace(minute=round(dt.minute, -1)) 
    except ValueError: 
     return dt.replace(minute=0) + timedelta(hours=1) 

時序

%timeit _minute10(datetime(2016, 12, 31, 23, 55)) 
100000 loops, best of 3: 5.12 µs per loop 

%timeit _minute10(datetime(2016, 12, 31, 23, 31)) 
100000 loops, best of 3: 2.21 µs per loop 
相關問題