如何舍入日期时间对象的分钟

发布于 2024-09-14 15:21:08 字数 367 浏览 12 评论 0原文

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

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

我需要做的是将分钟四舍五入到最接近的第 10 分钟。到目前为止我一直在做的是获取分钟值并对其使用 round() 。

min = round(tm.minute, -1)

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

有什么更好的方法来执行此操作? datetime 支持这个吗?

I have a datetime object produced using strptime().

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

What I need to do is round the minute to the closest 10th minute. What I have been doing up to this point was taking the minute value and using round() on it.

min = round(tm.minute, -1)

However, as with the above example, it gives an invalid time when the minute value is greater than 56. i.e.: 3:60

What is a better way to do this? Does datetime support this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(23

茶花眉 2024-09-21 15:21:08

这将使存储在 tm 中的 datetime 对象的“下限”四舍五入到 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)

This will get the 'floor' of a datetime object stored in tm rounded to the 10 minute mark before tm.

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

If you want classic rounding to the nearest 10 minute mark, do this:

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)

or this:

tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
                         seconds=tm.second,
                         microseconds=tm.microsecond)
只有影子陪我不离不弃 2024-09-21 15:21:08

在任何时间(以秒为单位)舍入日期时间的一般函数:

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)

具有 1 小时舍入和 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

General function to round a datetime at any time lapse in seconds:

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)

Samples with 1 hour rounding & 30 minutes rounding:

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
逆光下的微笑 2024-09-21 15:21:08

从我修改为仅使用日期时间对象的改编版本,这避免了必须转换为秒并使调用代码更具可读性:

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 小时舍入和 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

From the best answer I modified to an adapted version using only datetime objects, this avoids having to do the conversion to seconds and makes the calling code more readable:

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)

Samples with 1 hour rounding & 15 minutes rounding:

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
倚栏听风 2024-09-21 15:21:08

我使用了 Stijn Nevens 代码(谢谢 Stijn),并且有一些附加组件可以分享。向上舍入、向下舍入以及四舍五入到最接近的值。

更新 2019-03-09 = 纳入 Spinxz 评论;谢谢。

更新 2019-12-27 = 纳入 Bart 评论;谢谢。

测试 date_delta 为“X 小时”或“X 分钟”或“X 秒”。

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)))

I used Stijn Nevens code (thank you Stijn) and have a little add-on to share. Rounding up, down and rounding to nearest.

update 2019-03-09 = comment Spinxz incorporated; thank you.

update 2019-12-27 = comment Bart incorporated; thank you.

Tested for date_delta of "X hours" or "X minutes" or "X seconds".

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)))
慢慢从新开始 2024-09-21 15:21:08

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

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)

def time_floor(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    return time - mod

def time_ceil(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    if mod:
        return time + (delta - mod)
    return time

在您的情况下:

>>> tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
>>> time_round(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)
>>> time_floor(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 3, 50)
>>> time_ceil(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)

Here is a simpler generalized solution without floating point precision issues and external library dependencies:

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)

def time_floor(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    return time - mod

def time_ceil(time, delta, epoch=None):
    mod = time_mod(time, delta, epoch)
    if mod:
        return time + (delta - mod)
    return time

In your case:

>>> tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
>>> time_round(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)
>>> time_floor(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 3, 50)
>>> time_ceil(tm, datetime.timedelta(minutes=10))
datetime.datetime(2010, 6, 10, 4, 0)
彻夜缠绵 2024-09-21 15:21:08

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]

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

Pandas has a datetime round feature, but as with most things in Pandas it needs to be in Series format.

>>> 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]

Docs - Change the frequency string as needed.

烟沫凡尘 2024-09-21 15:21:08

如果你不想使用条件,你可以使用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 - 请参阅其他响应;)

if you don't want to use condition, you can use modulo operator:

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

UPDATE

did you want something like this?

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

.. if you want result as string. for obtaining datetime result, it's better to use timedelta - see other responses ;)

∞琼窗梦回ˉ 2024-09-21 15:21:08

我正在用这个。它的优点是可以使用 tz 感知的日期时间。

def round_minutes(some_datetime: datetime, step: int):
    """ round up to nearest step-minutes """
    if step > 60:
        raise AttrbuteError("step must be less than 60")

    change = timedelta(
        minutes= some_datetime.minute % step,
        seconds=some_datetime.second,
        microseconds=some_datetime.microsecond
    )

    if change > timedelta():
        change -= timedelta(minutes=step)

    return some_datetime - change

它的缺点是只能工作少于一小时的时间片。

i'm using this. it has the advantage of working with tz aware datetimes.

def round_minutes(some_datetime: datetime, step: int):
    """ round up to nearest step-minutes """
    if step > 60:
        raise AttrbuteError("step must be less than 60")

    change = timedelta(
        minutes= some_datetime.minute % step,
        seconds=some_datetime.second,
        microseconds=some_datetime.microsecond
    )

    if change > timedelta():
        change -= timedelta(minutes=step)

    return some_datetime - change

it has the disadvantage of only working for timeslices less than an hour.

会傲 2024-09-21 15:21:08

一个简单的方法:

def round_time(dt, round_to_seconds=60):
    """Round a datetime object to any number of seconds
    dt: datetime.datetime object
    round_to_seconds: closest number of seconds for rounding, Default 1 minute.
    """
    rounded_epoch = round(dt.timestamp() / round_to_seconds) * round_to_seconds
    rounded_dt = datetime.datetime.fromtimestamp(rounded_epoch).astimezone(dt.tzinfo)
    return rounded_dt

A straightforward approach:

def round_time(dt, round_to_seconds=60):
    """Round a datetime object to any number of seconds
    dt: datetime.datetime object
    round_to_seconds: closest number of seconds for rounding, Default 1 minute.
    """
    rounded_epoch = round(dt.timestamp() / round_to_seconds) * round_to_seconds
    rounded_dt = datetime.datetime.fromtimestamp(rounded_epoch).astimezone(dt.tzinfo)
    return rounded_dt
萧瑟寒风 2024-09-21 15:21:08

对分钟时间进行舍入的一般函数:

from datetime import datetime
def round_minute(date: datetime = None, round_to: int = 1):
    """
    round datetime object to minutes
    """
    if not date:
        date = datetime.now()
    date = date.replace(second=0, microsecond=0)
    delta = date.minute % round_to
    return date.replace(minute=date.minute - delta)

General Function to round down times of minutes:

from datetime import datetime
def round_minute(date: datetime = None, round_to: int = 1):
    """
    round datetime object to minutes
    """
    if not date:
        date = datetime.now()
    date = date.replace(second=0, microsecond=0)
    delta = date.minute % round_to
    return date.replace(minute=date.minute - delta)
戏剧牡丹亭 2024-09-21 15:21:08

这样就可以了,我认为它使用了 round 的一个非常有用的应用程序。

from typing import Literal
import math

def round_datetime(dt: datetime.datetime, step: datetime.timedelta, d: Literal['no', 'up', 'down'] = 'no'):
    step = step.seconds
    round_f = {'no': round, 'up': math.ceil, 'down': math.floor}
    return datetime.datetime.fromtimestamp(step * round_f[d](dt.timestamp() / step))

date = datetime.datetime(year=2022, month=11, day=16, hour=10, minute=2, second=30, microsecond=424242)#
print('Original:', date)
print('Standard:', round_datetime(date, datetime.timedelta(minutes=5)))
print('Down:    ', round_datetime(date, datetime.timedelta(minutes=5), d='down'))
print('Up:      ', round_datetime(date, datetime.timedelta(minutes=5), d='up'))

结果:

Original: 2022-11-16 10:02:30.424242
Standard: 2022-11-16 10:05:00
Down:     2022-11-16 10:00:00
Up:       2022-11-16 10:05:00

This will do it, I think it uses a very useful application of round.

from typing import Literal
import math

def round_datetime(dt: datetime.datetime, step: datetime.timedelta, d: Literal['no', 'up', 'down'] = 'no'):
    step = step.seconds
    round_f = {'no': round, 'up': math.ceil, 'down': math.floor}
    return datetime.datetime.fromtimestamp(step * round_f[d](dt.timestamp() / step))

date = datetime.datetime(year=2022, month=11, day=16, hour=10, minute=2, second=30, microsecond=424242)#
print('Original:', date)
print('Standard:', round_datetime(date, datetime.timedelta(minutes=5)))
print('Down:    ', round_datetime(date, datetime.timedelta(minutes=5), d='down'))
print('Up:      ', round_datetime(date, datetime.timedelta(minutes=5), d='up'))

The result:

Original: 2022-11-16 10:02:30.424242
Standard: 2022-11-16 10:05:00
Down:     2022-11-16 10:00:00
Up:       2022-11-16 10:05:00
握住我的手 2024-09-21 15:21:08

是的,如果您的数据属于 pandas 系列中的 DateTime 列,您可以使用内置的 pandas.Series.dt.round 函数对其进行舍入。
请参阅此处有关 pandas.Series 的文档。 dt.round
在四舍五入到 10 分钟的情况下,它将是 Series.dt.round('10min') 或 Series.dt.round('600s') ,如下所示:

pandas.Series(tm).dt.round('10min')

编辑以添加示例代码:

import datetime
import pandas

tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
tm_rounded = pandas.Series(tm).dt.round('10min')
print(tm_rounded)

>>> 0   2010-06-10 04:00:00
dtype: datetime64[ns]

yes, if your data belongs to a DateTime column in a pandas series, you can round it up using the built-in pandas.Series.dt.round function.
See documentation here on pandas.Series.dt.round.
In your case of rounding to 10min it will be Series.dt.round('10min') or Series.dt.round('600s') like so:

pandas.Series(tm).dt.round('10min')

Edit to add Example code:

import datetime
import pandas

tm = datetime.datetime(2010, 6, 10, 3, 56, 23)
tm_rounded = pandas.Series(tm).dt.round('10min')
print(tm_rounded)

>>> 0   2010-06-10 04:00:00
dtype: datetime64[ns]
半暖夏伤 2024-09-21 15:21:08

我想出了这个非常简单的函数,可以处理任何时间增量,只要它是 60 秒的倍数或除数即可。它还与时区感知的日期时间兼容。

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

def round_dt_to_delta(dt, delta=timedelta(minutes=30)):
    ref = datetime.min.replace(tzinfo=dt.tzinfo)
    return ref + round((dt - ref) / delta) * delta

输出:

In [1]: round_dt_to_delta(datetime(2012,12,31,23,44,49), timedelta(seconds=15))
Out[1]: datetime.datetime(2012, 12, 31, 23, 44, 45)
In [2]: round_dt_to_delta(datetime(2012,12,31,23,44,49), timedelta(minutes=15))
Out[2]: datetime.datetime(2012, 12, 31, 23, 45)

I came up with this very simple function, working with any timedelta as long as it's either a multiple or divider of 60 seconds. It's also compatible with timezone-aware datetimes.

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

def round_dt_to_delta(dt, delta=timedelta(minutes=30)):
    ref = datetime.min.replace(tzinfo=dt.tzinfo)
    return ref + round((dt - ref) / delta) * delta

Output:

In [1]: round_dt_to_delta(datetime(2012,12,31,23,44,49), timedelta(seconds=15))
Out[1]: datetime.datetime(2012, 12, 31, 23, 44, 45)
In [2]: round_dt_to_delta(datetime(2012,12,31,23,44,49), timedelta(minutes=15))
Out[2]: datetime.datetime(2012, 12, 31, 23, 45)
耳钉梦 2024-09-21 15:21:08

这些看起来过于复杂

def round_down_to():
    num = int(datetime.utcnow().replace(second=0, microsecond=0).minute)
    return num - (num%10)

Those seem overly complex

def round_down_to():
    num = int(datetime.utcnow().replace(second=0, microsecond=0).minute)
    return num - (num%10)
海夕 2024-09-21 15:21:08
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)
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)
七度光 2024-09-21 15:21:08

基于 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')

Based on Stijn Nevens and modified for Django use to round current time to the nearest 15 minute.

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

if you need full date and time just remove the .strftime('%H:%M:%S')

随波逐流 2024-09-21 15:21:08

当捕获异常时,速度不是最好的,但是这可以工作。

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

Not the best for speed when the exception is caught, however this would work.

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

Timings

%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
酒几许 2024-09-21 15:21:08

对于 datetime 对象 t ,四舍五入到给定时间单位(这里是秒)的两行直观解决方案:

format_str = '%Y-%m-%d %H:%M:%S'
t_rounded = datetime.strptime(datetime.strftime(t, format_str), format_str)

如果您希望四舍五入到不同的单位,只需更改 格式_str

这种方法不会像上面的方法那样舍入到任意时间量,而是一种很好的 Pythonic 方法,可以舍入到给定的小时、分钟或秒。

A two line intuitive solution to round to a given time unit, here seconds, for a datetime object t:

format_str = '%Y-%m-%d %H:%M:%S'
t_rounded = datetime.strptime(datetime.strftime(t, format_str), format_str)

If you wish to round to a different unit simply alter format_str.

This approach does not round to arbitrary time amounts as above methods, but is a nicely Pythonic way to round to a given hour, minute or second.

终止放荡 2024-09-21 15:21:08

其他解决方案:

def round_time(timestamp=None, lapse=0):
    """
    Round a timestamp to a lapse according to specified minutes

    Usage:

    >>> import datetime, math
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 0)
    datetime.datetime(2010, 6, 10, 3, 56)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 1)
    datetime.datetime(2010, 6, 10, 3, 57)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), -1)
    datetime.datetime(2010, 6, 10, 3, 55)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3)
    datetime.datetime(2019, 3, 11, 9, 24)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3*60)
    datetime.datetime(2019, 3, 11, 12, 0)
    >>> round_time(datetime.datetime(2019, 3, 11, 10, 0, 0), 3)
    datetime.datetime(2019, 3, 11, 10, 0)

    :param timestamp: Timestamp to round (default: now)
    :param lapse: Lapse to round in minutes (default: 0)
    """
    t = timestamp or datetime.datetime.now()  # type: Union[datetime, Any]
    surplus = datetime.timedelta(seconds=t.second, microseconds=t.microsecond)
    t -= surplus
    try:
        mod = t.minute % lapse
    except ZeroDivisionError:
        return t
    if mod:  # minutes % lapse != 0
        t += datetime.timedelta(minutes=math.ceil(t.minute / lapse) * lapse - t.minute)
    elif surplus != datetime.timedelta() or lapse < 0:
        t += datetime.timedelta(minutes=(t.minute / lapse + 1) * lapse - t.minute)
    return t

希望这有帮助!

Other solution:

def round_time(timestamp=None, lapse=0):
    """
    Round a timestamp to a lapse according to specified minutes

    Usage:

    >>> import datetime, math
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 0)
    datetime.datetime(2010, 6, 10, 3, 56)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), 1)
    datetime.datetime(2010, 6, 10, 3, 57)
    >>> round_time(datetime.datetime(2010, 6, 10, 3, 56, 23), -1)
    datetime.datetime(2010, 6, 10, 3, 55)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3)
    datetime.datetime(2019, 3, 11, 9, 24)
    >>> round_time(datetime.datetime(2019, 3, 11, 9, 22, 11), 3*60)
    datetime.datetime(2019, 3, 11, 12, 0)
    >>> round_time(datetime.datetime(2019, 3, 11, 10, 0, 0), 3)
    datetime.datetime(2019, 3, 11, 10, 0)

    :param timestamp: Timestamp to round (default: now)
    :param lapse: Lapse to round in minutes (default: 0)
    """
    t = timestamp or datetime.datetime.now()  # type: Union[datetime, Any]
    surplus = datetime.timedelta(seconds=t.second, microseconds=t.microsecond)
    t -= surplus
    try:
        mod = t.minute % lapse
    except ZeroDivisionError:
        return t
    if mod:  # minutes % lapse != 0
        t += datetime.timedelta(minutes=math.ceil(t.minute / lapse) * lapse - t.minute)
    elif surplus != datetime.timedelta() or lapse < 0:
        t += datetime.timedelta(minutes=(t.minute / lapse + 1) * lapse - t.minute)
    return t

Hope this helps!

夏雨凉 2024-09-21 15:21:08

我知道的最短路线

min = tm.分钟 // 10 * 10

The shortest way I know

min = tm.minute // 10 * 10

柠栀 2024-09-21 15:21:08

对于这样一个简单的问题来说,大多数答案似乎都太复杂了。

假设 your_time 是您拥有的日期时间对象,接下来的轮次(实际上是楼层)以分钟为单位定义的所需分辨率。

from math import floor

your_time = datetime.datetime.now() 

g = 10  # granularity in minutes
print(
datetime.datetime.fromtimestamp(
floor(your_time.timestamp() / (60*g)) * (60*g)
))

Most of the answers seem to be too complicated for such a simple question.

Assuming your_time is the datetime object your have, the following rounds (actually floors) it at a desired resolution defined in minutes.

from math import floor

your_time = datetime.datetime.now() 

g = 10  # granularity in minutes
print(
datetime.datetime.fromtimestamp(
floor(your_time.timestamp() / (60*g)) * (60*g)
))
别念他 2024-09-21 15:21:08

下面的函数只需最少的导入就可以完成这项工作。您可以通过设置参数unit、rnd 和frm 舍入到您想要的任何值。尝试一下这个函数,您就会发现它是多么容易。

def toNearestTime(ts, unit='sec', rnd=1, frm=None):
    ''' round to nearest Time format
    param ts = time string to round in '%H:%M:%S' or '%H:%M' format :
    param unit = specify unit wich must be rounded 'sec' or 'min' or 'hour', default is seconds :
    param rnd = to which number you will round, the default is 1 :
    param frm = the output (return) format of the time string, as default the function take the unit format'''
    from time import strftime, gmtime

    ts = ts + ':00' if len(ts) == 5 else ts
    if 'se' in unit.lower():
        frm = '%H:%M:%S' if frm is None else frm
    elif 'm' in unit.lower():
        frm = '%H:%M' if frm is None else frm
        rnd = rnd * 60
    elif 'h' in unit.lower():
        frm = '%H' if frm is None else frm
        rnd = rnd * 3600
    secs = sum(int(x) * 60 ** i for i, x in enumerate(reversed(ts.split(':'))))
    rtm = int(round(secs / rnd, 0) * rnd)
    nt = strftime(frm, gmtime(rtm))
    return nt

调用函数如下:
使用默认输出格式 = hh:mm 舍入到最近的 5 分钟,如下

ts = '02:27:29'
nt = toNearestTime(ts, unit='min', rnd=5)
print(nt)
output: '02:25'

或使用输出格式 hh:mm:ss 舍入到最近的小时,如下

ts = '10:30:01'
nt = toNearestTime(ts, unit='hour', rnd=1, frm='%H:%M:%S')
print(nt)
output: '11:00:00'

最后更新版本

The function below with minimum of import will do the job. You can round to anything you want by setting te parameters unit, rnd, and frm. Play with the function and you will see how easy it will be.

def toNearestTime(ts, unit='sec', rnd=1, frm=None):
    ''' round to nearest Time format
    param ts = time string to round in '%H:%M:%S' or '%H:%M' format :
    param unit = specify unit wich must be rounded 'sec' or 'min' or 'hour', default is seconds :
    param rnd = to which number you will round, the default is 1 :
    param frm = the output (return) format of the time string, as default the function take the unit format'''
    from time import strftime, gmtime

    ts = ts + ':00' if len(ts) == 5 else ts
    if 'se' in unit.lower():
        frm = '%H:%M:%S' if frm is None else frm
    elif 'm' in unit.lower():
        frm = '%H:%M' if frm is None else frm
        rnd = rnd * 60
    elif 'h' in unit.lower():
        frm = '%H' if frm is None else frm
        rnd = rnd * 3600
    secs = sum(int(x) * 60 ** i for i, x in enumerate(reversed(ts.split(':'))))
    rtm = int(round(secs / rnd, 0) * rnd)
    nt = strftime(frm, gmtime(rtm))
    return nt

Call function as follow:
Round to nearest 5 minutes with default ouput format = hh:mm as follow

ts = '02:27:29'
nt = toNearestTime(ts, unit='min', rnd=5)
print(nt)
output: '02:25'

Or round to nearest hour with ouput format hh:mm:ss as follow

ts = '10:30:01'
nt = toNearestTime(ts, unit='hour', rnd=1, frm='%H:%M:%S')
print(nt)
output: '11:00:00'

last updated version

情泪▽动烟 2024-09-21 15:21:08

MZA 提出的https://stackoverflow.com/a/32547090/4417769,但更简单。

我本来会保留 date_delta,但同事将其修改为使用 round_to,所以这就是现在的样子。请随意提出修改以使用原始 date_delta 参数。

应该与时区一起工作,尚未彻底测试。

还没有实现平均,无论那是什么。无论如何,我们的代码中没有使用它。

def round_time(
    dt: Optional[datetime.datetime] = None,
    round_to: int = 60,
    to: str = "down",
) -> datetime.datetime:
    """
    Round a datetime object to a multiple of the given number of seconds
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    """
    if dt is None:
        dt = datetime.datetime.now()

    divided = dt.timestamp() / round_to

    if to == 'down':
        rounded = math.floor(divided)
    else:
        rounded = math.ceil(divided)

    return datetime.datetime.fromtimestamp(rounded * round_to, tz=dt.tzinfo)
assert round_time(datetime.datetime(2019,11,1,14,39,00), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-01 14:39:00')
assert round_time(datetime.datetime(2019,11,2,14,39,00,1), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-02 14:39:30')
assert round_time(datetime.datetime(2019,11,3,14,39,00,776980), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-03 14:39:30')
assert round_time(datetime.datetime(2019,11,4,14,39,29,776980), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-04 14:39:30')
assert round_time(datetime.datetime(2018,11,5,14,39,00,776980), round_to=30, to='down') == datetime.datetime.fromisoformat('2018-11-05 14:39:00')
assert round_time(datetime.datetime(2018,11,6,14,38,59,776980), round_to=30, to='down') == datetime.datetime.fromisoformat('2018-11-06 14:38:30')
assert round_time(datetime.datetime(2019,11,9,14,39,14,999999), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-09 14:39:30')
assert round_time(datetime.datetime(2012,12,11,23,44,59,7769),to='up') == datetime.datetime.fromisoformat('2012-12-11 23:45:00')
assert round_time(datetime.datetime(2010,12,12,23,44,59,7769),to='down',round_to=1) == datetime.datetime.fromisoformat('2010-12-12 23:44:59')
assert round_time(datetime.datetime(2011,12,13,23,44,59,7769),to='up',round_to=1) == datetime.datetime.fromisoformat('2011-12-13 23:45:00')
assert round_time(datetime.datetime(2012,12,14,23,44,59),round_to=3600,to='down') == datetime.datetime.fromisoformat('2012-12-14 23:00:00')
assert round_time(datetime.datetime(2012,12,15,23,44,59),round_to=3600,to='up') == datetime.datetime.fromisoformat('2012-12-16 00:00:00')
assert round_time(datetime.datetime(2012,12,17,23,00,00),round_to=3600,to='down') == datetime.datetime.fromisoformat('2012-12-17 23:00:00')
assert round_time(datetime.datetime(2012,12,18,23,00,00),round_to=3600,to='up') == datetime.datetime.fromisoformat('2012-12-18 23:00:00')

What MZA proposed https://stackoverflow.com/a/32547090/4417769, but way simpler.

I would have kept date_delta, but it was modified by colleagues to use round_to, so this is what this is now. Feel free to propose an edit to use the original date_delta parameter.

Should work with timezones, haven't thoroughly tested that yet.

haven't implemented average, whatever that is. Wasn't in use in our code anyway.

def round_time(
    dt: Optional[datetime.datetime] = None,
    round_to: int = 60,
    to: str = "down",
) -> datetime.datetime:
    """
    Round a datetime object to a multiple of the given number of seconds
    dt : datetime.datetime object, default now.
    dateDelta : timedelta object, we round to a multiple of this, default 1 minute.
    """
    if dt is None:
        dt = datetime.datetime.now()

    divided = dt.timestamp() / round_to

    if to == 'down':
        rounded = math.floor(divided)
    else:
        rounded = math.ceil(divided)

    return datetime.datetime.fromtimestamp(rounded * round_to, tz=dt.tzinfo)
assert round_time(datetime.datetime(2019,11,1,14,39,00), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-01 14:39:00')
assert round_time(datetime.datetime(2019,11,2,14,39,00,1), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-02 14:39:30')
assert round_time(datetime.datetime(2019,11,3,14,39,00,776980), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-03 14:39:30')
assert round_time(datetime.datetime(2019,11,4,14,39,29,776980), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-04 14:39:30')
assert round_time(datetime.datetime(2018,11,5,14,39,00,776980), round_to=30, to='down') == datetime.datetime.fromisoformat('2018-11-05 14:39:00')
assert round_time(datetime.datetime(2018,11,6,14,38,59,776980), round_to=30, to='down') == datetime.datetime.fromisoformat('2018-11-06 14:38:30')
assert round_time(datetime.datetime(2019,11,9,14,39,14,999999), round_to=30, to='up') == datetime.datetime.fromisoformat('2019-11-09 14:39:30')
assert round_time(datetime.datetime(2012,12,11,23,44,59,7769),to='up') == datetime.datetime.fromisoformat('2012-12-11 23:45:00')
assert round_time(datetime.datetime(2010,12,12,23,44,59,7769),to='down',round_to=1) == datetime.datetime.fromisoformat('2010-12-12 23:44:59')
assert round_time(datetime.datetime(2011,12,13,23,44,59,7769),to='up',round_to=1) == datetime.datetime.fromisoformat('2011-12-13 23:45:00')
assert round_time(datetime.datetime(2012,12,14,23,44,59),round_to=3600,to='down') == datetime.datetime.fromisoformat('2012-12-14 23:00:00')
assert round_time(datetime.datetime(2012,12,15,23,44,59),round_to=3600,to='up') == datetime.datetime.fromisoformat('2012-12-16 00:00:00')
assert round_time(datetime.datetime(2012,12,17,23,00,00),round_to=3600,to='down') == datetime.datetime.fromisoformat('2012-12-17 23:00:00')
assert round_time(datetime.datetime(2012,12,18,23,00,00),round_to=3600,to='up') == datetime.datetime.fromisoformat('2012-12-18 23:00:00')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文