2010-08-12 49 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 
相关问题