Python 如何舍入日期时间对象的分钟
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3463930/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to round the minute of a datetime object
提问by Lucas Manco
I have a datetime object produced usingstrptime().
I have a datetime object produced using时间()。
>>> 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.
我需要做的是将分钟四舍五入到最接近的第 10 分钟。到目前为止,我一直在做的是获取分钟值并在其上使用 round()。
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
但是,与上面的示例一样,当分钟值大于 56 时,它给出了无效时间。即:3:60
What is a better way to do this? Does datetimesupport this?
有什么更好的方法可以做到这一点?是否datetime支持呢?
回答by mykhal
if you don't want to use condition, you can use modulooperator:
如果不想使用条件,可以使用modulo运算符:
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 ;)
.. 如果你想要结果作为字符串。要获得日期时间结果,最好使用 timedelta - 请参阅其他回复;)
回答by Omnifarious
This will get the 'floor' of a datetimeobject stored in tm rounded to the 10 minute mark before tm.
这将使datetime存储在 tm中的对象的“地板”四舍五入到 10 分钟之前的标记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:
如果您希望经典四舍五入到最接近的 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)
or this:
或这个:
tm += datetime.timedelta(minutes=5)
tm -= datetime.timedelta(minutes=tm.minute % 10,
seconds=tm.second,
microseconds=tm.microsecond)
回答by Le Droid
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:
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
回答by JulienV
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)
回答by Stijn Nevens
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:
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
回答by WayBehind
Based on Stijn Nevens and modified for Django use to round current time to the nearest 15 minute.
基于 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
if you need full date and time just remove the .strftime('%H:%M:%S')
如果您需要完整的日期和时间,只需删除 .strftime('%H:%M:%S')
回答by MZA
I used Stijn Nevens code (thank you Stijn) and have a little add-on to share. Rounding up, down and rounding to nearest.
我使用了 Stijn Nevens 代码(谢谢 Stijn)并且有一些附加组件可以分享。向上、向下和四舍五入到最接近的值。
update 2019-03-09 = comment Spinxz incorporated; thank you.
更新 2019-03-09 = 评论 Spinxz 已合并;谢谢你。
update 2019-12-27 = comment Bart incorporated; thank you.
更新 2019-12-27 = 评论 Bart 合并;谢谢你。
Tested for date_delta of "X hours" or "X minutes" or "X seconds".
测试了“X 小时”或“X 分钟”或“X 秒”的 date_delta。
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)))
回答by James
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
回答by barnhillec
A two line intuitive solution to round to a given time unit, here seconds, for a datetimeobject t:
两线直观的解决方案,以圆到一个给定的时间单位,这里秒,对于一个datetime物体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.
如果您希望四舍五入到不同的单位,只需改变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.
这种方法不像上述方法那样四舍五入到任意时间量,而是一种很好的 Pythonic 方法来四舍五入到给定的小时、分钟或秒。
回答by David Chan
i'm using this. it has the advantage of working with tz aware datetimes.
我正在使用这个。它具有使用 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
it has the disadvantage of only working for timeslices less than an hour.
它的缺点是只能工作不到一个小时的时间片。

