Python - Ceil将日期时间提升到下一刻钟

Pie*_*NAY 18 python math datetime ceil

让我们想象一下这个日期时间

>>> import datetime
>>> dt = datetime.datetime(2012, 10, 25, 17, 32, 16)
Run Code Online (Sandbox Code Playgroud)

我想把它提交给下一个四分之一小时,以便获得

datetime.datetime(2012, 10, 25, 17, 45)
Run Code Online (Sandbox Code Playgroud)

我想象的东西

>>> quarter = datetime.timedelta(minutes=15)
>>> import math
>>> ceiled_dt = math.ceil(dt / quarter) * quarter
Run Code Online (Sandbox Code Playgroud)

但当然这不起作用

mgi*_*son 20

这个需要微秒考虑!

import math

def ceil_dt(dt):
    # how many secs have passed this hour
    nsecs = dt.minute*60 + dt.second + dt.microsecond*1e-6  
    # number of seconds to next quarter hour mark
    # Non-analytic (brute force is fun) way:  
    #   delta = next(x for x in xrange(0,3601,900) if x>=nsecs) - nsecs
    # analytic way:
    delta = math.ceil(nsecs / 900) * 900 - nsecs
    #time + number of seconds to quarter hour mark.
    return dt + datetime.timedelta(seconds=delta)

t1 = datetime.datetime(2017, 3, 6, 7, 0)
assert ceil_dt(t1) == t1

t2 = datetime.datetime(2017, 3, 6, 7, 1)
assert ceil_dt(t2) == datetime.datetime(2017, 3, 6, 7, 15)

t3 = datetime.datetime(2017, 3, 6, 7, 15)
assert ceil_dt(t3) == t3

t4 = datetime.datetime(2017, 3, 6, 7, 16)
assert ceil_dt(t4) == datetime.datetime(2017, 3, 6, 7, 30)

t5 = datetime.datetime(2017, 3, 6, 7, 30)
assert ceil_dt(t5) == t5

t6 = datetime.datetime(2017, 3, 6, 7, 31)
assert ceil_dt(t6) == datetime.datetime(2017, 3, 6, 7, 45)

t7 = datetime.datetime(2017, 3, 6, 7, 45)
assert ceil_dt(t7) == t7

t8 = datetime.datetime(2017, 3, 6, 7, 46)
assert ceil_dt(t8) == datetime.datetime(2017, 3, 6, 8, 0)
Run Code Online (Sandbox Code Playgroud)

说明delta:

  • 900秒是15分钟(四分之一小时没有闰秒,我不认为日期时间处理......)
  • nsecs / 900是已发生的四分之一小时块的数量.采取ceil的这轮高达刻钟块的数目.
  • 将四分之一小时块的数量乘以900,以计算自"舍入"后的小时开始以来已经发生了多少秒.


Tim*_*ker 8

def ceil(dt):
    if dt.minute % 15 or dt.second:
        return dt + datetime.timedelta(minutes = 15 - dt.minute % 15,
                                       seconds = -(dt.second % 60))
    else:
        return dt
Run Code Online (Sandbox Code Playgroud)

这给你:

>>> ceil(datetime.datetime(2012,10,25, 17,45))
datetime.datetime(2012, 10, 25, 17, 45)
>>> ceil(datetime.datetime(2012,10,25, 17,45,1))
datetime.datetime(2012, 10, 25, 18, 0)
>>> ceil(datetime.datetime(2012,12,31,23,59,0))
datetime.datetime(2013,1,1,0,0)
Run Code Online (Sandbox Code Playgroud)

  • 这有点时髦,因为你在`dt'上运行,但是你返回它.从API的角度来看,似乎你应该做一个或另一个...(另外,这不需要考虑`微秒') (3认同)

jfs*_*jfs 7

@Mark Dickinson建议到目前为止最好的公式:

def ceil_dt(dt, delta):
    return dt + (datetime.min - dt) % delta
Run Code Online (Sandbox Code Playgroud)

在Python 3中,对于任意时间增量(不仅仅是15分钟):

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

def ceil_dt(dt, delta):
    return datetime.min + math.ceil((dt - datetime.min) / delta) * delta

print(ceil_dt(datetime(2012, 10, 25, 17, 32, 16), timedelta(minutes=15)))
# -> 2012-10-25 17:45:00
Run Code Online (Sandbox Code Playgroud)

为避免中间浮动,divmod()可以使用:

def ceil_dt(dt, delta):
    q, r = divmod(dt - datetime.min, delta)
    return (datetime.min + (q + 1)*delta) if r else dt
Run Code Online (Sandbox Code Playgroud)

例:

>>> ceil_dt(datetime(2012, 10, 25, 17, 32, 16), timedelta(minutes=15))
datetime.datetime(2012, 10, 25, 17, 45)
>>> ceil_dt(datetime.min, datetime.resolution) 
datetime.datetime(1, 1, 1, 0, 0)
>>> ceil_dt(datetime.min, 2*datetime.resolution)
datetime.datetime(1, 1, 1, 0, 0)
>>> ceil_dt(datetime.max, datetime.resolution)
datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)
>>> ceil_dt(datetime.max, 2*datetime.resolution)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in ceil_dt
OverflowError: date value out of range
>>> ceil_dt(datetime.min+datetime.resolution, datetime.resolution)
datetime.datetime(1, 1, 1, 0, 0, 0, 1)
>>> ceil_dt(datetime.min+datetime.resolution, 2*datetime.resolution)
datetime.datetime(1, 1, 1, 0, 0, 0, 2)
>>> ceil_dt(datetime.max-datetime.resolution, datetime.resolution)
datetime.datetime(9999, 12, 31, 23, 59, 59, 999998)
>>> ceil_dt(datetime.max-datetime.resolution, 2*datetime.resolution)
datetime.datetime(9999, 12, 31, 23, 59, 59, 999998)
>>> ceil_dt(datetime.max-2*datetime.resolution, datetime.resolution)
datetime.datetime(9999, 12, 31, 23, 59, 59, 999997)
>>> ceil_dt(datetime.max-2*datetime.resolution, 2*datetime.resolution)
datetime.datetime(9999, 12, 31, 23, 59, 59, 999998)
>>> ceil_dt(datetime.max-timedelta(1), datetime.resolution)
datetime.datetime(9999, 12, 30, 23, 59, 59, 999999)
>>> ceil_dt(datetime.max-timedelta(1), 2*datetime.resolution)
datetime.datetime(9999, 12, 31, 0, 0)
>>> ceil_dt(datetime.min, datetime.max-datetime.min)
datetime.datetime(1, 1, 1, 0, 0)
>>> ceil_dt(datetime.max, datetime.max-datetime.min)
datetime.datetime(9999, 12, 31, 23, 59, 59, 999999)
Run Code Online (Sandbox Code Playgroud)

  • 如果你限制Python 3,那么更简单的表达式`dt +(d​​atetime.min - dt)%delta`也可以. (3认同)