如何围绕日期时间对象python的分钟

Luc*_*nco 88 python

我有一个使用strptime()生成的datetime对象.

>>> tm
datetime.datetime(2010, 6, 10, 3, 56, 23)
Run Code Online (Sandbox Code Playgroud)

我需要做的是将分钟缩短到最接近的第10分钟.到目前为止我一直在做的是获取分钟值并使用round().

min = round(tm.minute, -1)
Run Code Online (Sandbox Code Playgroud)

但是,与上面的示例一样,当分钟值大于56时,它会给出无效时间.即:3:60

有什么更好的方法呢?datetime支持这个吗?

Omn*_*ous 122

这将使datetime存储在tm 中的对象的"floor" 四舍五入到之前的10分钟标记tm.

tm = tm - datetime.timedelta(minutes=tm.minute % 10,
                             seconds=tm.second,
                             microseconds=tm.microsecond)
Run Code Online (Sandbox Code Playgroud)

如果您想要经典的舍入到最近的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)
Run Code Online (Sandbox Code Playgroud)

或这个:

tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
                         seconds=tm.second,
                         microseconds=tm.microsecond)
Run Code Online (Sandbox Code Playgroud)


Le *_*oid 85

用于在任何时间以秒为单位舍入日期时间的常规功能:

def roundTime(dt=None, roundTo=60):
   """Round a datetime object to any time lapse 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)
Run Code Online (Sandbox Code Playgroud)

样品进行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
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这不适用于tz-aware datetime.应该使用`dt.replace(hour = 0,minute = 0,second = 0)`而不是`dt.min`. (6认同)
  • @ skoval00 + druska根据您的建议编辑,以支持tz感知日期时间.谢谢! (2认同)

MZA*_*MZA 20

我使用Stijn Nevens代码效果很好(谢谢Stijn)并且有一些小插件可以分享.向上舍入,向下舍入到最近.

import datetime

def round_time(dt=None, date_delta=datetime.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 seconds % round_to == 0 and dt.microsecond == 0:
        rounding = (seconds + round_to / 2) // round_to * round_to
    else:
        if to == 'up':
            # // is a floor division, not a comment on following line (like in javascript):
            rounding = (seconds + dt.microsecond/1000000 + 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 + datetime.timedelta(0, rounding - seconds, - dt.microsecond)

# test data
print(round_time(datetime.datetime(2019,11,1,14,39,00), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,2,14,39,00,1), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,3,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2019,11,4,14,39,29,776980), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2018,11,5,14,39,00,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2018,11,6,14,38,59,776980), date_delta=datetime.timedelta(seconds=30), to='down'))
print(round_time(datetime.datetime(2017,11,7,14,39,15), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2017,11,8,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='average'))
print(round_time(datetime.datetime(2019,11,9,14,39,14,999999), date_delta=datetime.timedelta(seconds=30), to='up'))
print(round_time(datetime.datetime(2012,12,10,23,44,59,7769),to='average'))
print(round_time(datetime.datetime(2012,12,11,23,44,59,7769),to='up'))
print(round_time(datetime.datetime(2010,12,12,23,44,59,7769),to='down',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2011,12,13,23,44,59,7769),to='up',date_delta=datetime.timedelta(seconds=1)))
print(round_time(datetime.datetime(2012,12,14,23,44,59),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,15,23,44,59),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,16,23,44,59),date_delta=datetime.timedelta(hours=1)))
print(round_time(datetime.datetime(2012,12,17,23,00,00),date_delta=datetime.timedelta(hours=1),to='down'))
print(round_time(datetime.datetime(2012,12,18,23,00,00),date_delta=datetime.timedelta(hours=1),to='up'))
print(round_time(datetime.datetime(2012,12,19,23,00,00),date_delta=datetime.timedelta(hours=1)))
Run Code Online (Sandbox Code Playgroud)

  • "向上"四舍五入可能不是大多数人所期望的.即使dt不需要舍入,你也可以舍入到下一个date_delta:例如15:30:00.000,round_to = 60将变为15:31:00.000 (4认同)

Sti*_*ens 12

从我修改的最佳答案到仅使用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)
Run Code Online (Sandbox Code Playgroud)

样品进行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
Run Code Online (Sandbox Code Playgroud)

  • 上面的后续行动:只是指出它不适用于任意时间增量,例如超过1天的时间.这个问题是关于舍入分钟,所以这是一个适当的限制,但它可以更清楚地编写代码的方式. (2认同)

Ero*_*618 8

Pandas 具有日期时间循环功能,但与 Pandas 中的大多数内容一样,它需要采用系列格式。

>>> ts = pd.Series(pd.date_range(Dt(2019,1,1,1,1),Dt(2019,1,1,1,4),periods=8))
>>> print(ts)
0   2019-01-01 01:01:00.000000000
1   2019-01-01 01:01:25.714285714
2   2019-01-01 01:01:51.428571428
3   2019-01-01 01:02:17.142857142
4   2019-01-01 01:02:42.857142857
5   2019-01-01 01:03:08.571428571
6   2019-01-01 01:03:34.285714285
7   2019-01-01 01:04:00.000000000
dtype: datetime64[ns]

>>> ts.dt.round('1min')
0   2019-01-01 01:01:00
1   2019-01-01 01:01:00
2   2019-01-01 01:02:00
3   2019-01-01 01:02:00
4   2019-01-01 01:03:00
5   2019-01-01 01:03:00
6   2019-01-01 01:04:00
7   2019-01-01 01:04:00
dtype: datetime64[ns]
Run Code Online (Sandbox Code Playgroud)

文档- 根据需要更改频率字符串。


ofo*_*ofo 5

这是一个更简单的通用解决方案,没有浮点精度问题和外部库依赖项:

import datetime

def time_mod(time, delta, epoch=None):
    if epoch is None:
        epoch = datetime.datetime(1970, 1, 1, tzinfo=time.tzinfo)
    return (time - epoch) % delta

def time_round(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    if mod < (delta / 2):
       return time - mod
    return time + (delta - mod)
Run Code Online (Sandbox Code Playgroud)

在你的情况下:

>>> tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
>>> time_round(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)
Run Code Online (Sandbox Code Playgroud)


myk*_*hal 4

如果不想使用条件,可以使用modulo运算符:

minutes = int(round(tm.minute, -1)) % 60
Run Code Online (Sandbox Code Playgroud)

更新

你想要这样的东西吗?

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
Run Code Online (Sandbox Code Playgroud)

..如果你想要结果作为字符串。为了获得日期时间结果,最好使用 timedelta - 请参阅其他响应;)