Ceil a datetime to next quarter of an hour

后端 未结 6 1456
花落未央
花落未央 2020-12-03 07:38

Let\'s imagine this datetime

>>> import datetime
>>> dt = datetime.datetime(2012, 10, 25, 17, 32, 16)

I\'d l

6条回答
  •  慢半拍i
    慢半拍i (楼主)
    2020-12-03 08:15

    The formula proposed here by @Mark Dickinson worked beautifully, but I needed a solution that also handled timezones and Daylight Savings Time (DST).

    Using pytz, I arrived at:

    import pytz
    from datetime import datetime, timedelta
    
    def datetime_ceiling(dt, delta):
        # Preserve original timezone info
        original_tz = dt.tzinfo
        if original_tz:
            # If the original was timezone aware, translate to UTC.
            # This is necessary because datetime math does not take
            # DST into account, so first we normalize the datetime...
            dt = dt.astimezone(pytz.UTC)
            # ... and then make it timezone naive
            dt = dt.replace(tzinfo=None)
        # We only do math on a timezone naive object, which allows
        # us to pass naive objects directly to the function
        dt = dt + ((datetime.min - dt) % delta)
        if original_tz:
            # If the original was tz aware, we make the result aware...
            dt = pytz.UTC.localize(dt)
            # ... then translate it from UTC back its original tz.
            # This translation applies appropriate DST status.
            dt = dt.astimezone(original_tz)
        return dt
    

    A nearly identical floor function can be made by changing one line of code:

    def datetime_floor(dt, delta):
        ...
        dt = dt - ((datetime.min - dt) % delta)
        ...
    

    The following datetime is three minutes before the transition from DST back to Standard Time (STD):

    datetime.datetime(2020, 11, 1, 1, 57, tzinfo=)
    

    Assuming the above as dt, we can round down to the nearest five minute increment using our floor function:

    >>> datetime_floor(dt, timedelta(minutes=5))
    datetime.datetime(2020, 11, 1, 1, 55, tzinfo=)
    

    The timezone and relationship to DST is preserved. (The same would be true for the ceiling function.)

    On this date DST will end at 2 am, at which point the time will "roll back" to 1am STD. If we use our ceiling function to round up from 1:57am DST, we should not end up at 2am DST, but rather at 1:00am STD, which is the result we get:

    >>> datetime_ceiling(dt, timedelta(minutes=5))
    datetime.datetime(2020, 11, 1, 1, 0, tzinfo=)
    

提交回复
热议问题