如何在 Django 中舍入一个时区感知日期
How to round a timezone-aware date in Django
我正在尝试将默认时区 datetime
转换为 localtime
并将时间舍入到 Django 视图中的 15 分钟时隙。我有以下 roundTime 函数:
def roundTime(dt=None, dateDelta=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.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)
这是我目前尝试过的方法:
mytime = roundTime(datetime.now(),timedelta(minutes=15)).strftime('%H:%M:%S') #works OK
mytime = datetime.strptime(str(mytime), '%H:%M:%S') #works OK
mytime = timezone.localtime(mytime)
但是最后一行给我这个错误:
error: astimezone() cannot be applied to a naive datetime
当我使用时:
local_time = timezone.localtime(timezone.now())
我确实得到了正确的当地时间,但由于某些原因我无法通过以下方式计算时间:
mytime = roundTime(local_time,timedelta(minutes=15)).strftime('%H:%M:%S')
与上面的 datetime.now()
一起使用。
我想出了这个不漂亮但可以工作的代码:
mytime = timezone.localtime(timezone.now())
mytime = datetime.strftime(mytime, '%Y-%m-%d %H:%M:%S')
mytime = datetime.strptime(str(mytime), '%Y-%m-%d %H:%M:%S')
mytime = roundTime(mytime,timedelta(minutes=15)).strftime('%H:%M:%S')
mytime = datetime.strptime(str(mytime), '%H:%M:%S')
有更好的解决方案吗?
您使用的 roundTime
函数不适用于时区感知日期。
要支持它,您可以这样修改它:
def roundTime(dt=None, dateDelta=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.now()
#Make sure dt and datetime.min have the same timezone
tzmin = dt.min.replace(tzinfo=dt.tzinfo)
seconds = (dt - tzmin).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)
通过这种方式,该函数既适用于原始日期,也适用于 TZ 感知日期。
然后您可以像第二次尝试一样继续:
local_time = timezone.localtime(timezone.now())
mytime = roundTime(local_time, timedelta(minutes=15))
要舍入可识别时区的日期时间对象,make it a naive datetime object, round it, and attach the correct time zone info for the rounded time:
from datetime import timedelta
from django.utils import timezone
def round_time(dt=None, delta=timedelta(minutes=1)):
if dt is None:
dt = timezone.localtime(timezone.now()) # assume USE_TZ=True
tzinfo, is_dst = dt.tzinfo, bool(dt.dst())
dt = dt.replace(tzinfo=None)
f = delta.total_seconds()
rounded_ordinal_seconds = f * round((dt - dt.min).total_seconds() / f)
rounded_dt = dt.min + timedelta(seconds=rounded_ordinal_seconds)
localize = getattr(tzinfo, 'localize', None)
if localize:
rounded_dt = localize(rounded_dt, is_dst=is_dst)
else:
rounded_dt = rounded_dt.replace(tzinfo=tzinfo)
return rounded_dt
为避免浮点问题,所有计算都可以使用整数微秒 (dt.resolution
) 重写。
示例:
>>> round_time(delta=timedelta(minutes=15))
我正在尝试将默认时区 datetime
转换为 localtime
并将时间舍入到 Django 视图中的 15 分钟时隙。我有以下 roundTime 函数:
def roundTime(dt=None, dateDelta=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.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)
这是我目前尝试过的方法:
mytime = roundTime(datetime.now(),timedelta(minutes=15)).strftime('%H:%M:%S') #works OK
mytime = datetime.strptime(str(mytime), '%H:%M:%S') #works OK
mytime = timezone.localtime(mytime)
但是最后一行给我这个错误:
error: astimezone() cannot be applied to a naive datetime
当我使用时:
local_time = timezone.localtime(timezone.now())
我确实得到了正确的当地时间,但由于某些原因我无法通过以下方式计算时间:
mytime = roundTime(local_time,timedelta(minutes=15)).strftime('%H:%M:%S')
与上面的 datetime.now()
一起使用。
我想出了这个不漂亮但可以工作的代码:
mytime = timezone.localtime(timezone.now())
mytime = datetime.strftime(mytime, '%Y-%m-%d %H:%M:%S')
mytime = datetime.strptime(str(mytime), '%Y-%m-%d %H:%M:%S')
mytime = roundTime(mytime,timedelta(minutes=15)).strftime('%H:%M:%S')
mytime = datetime.strptime(str(mytime), '%H:%M:%S')
有更好的解决方案吗?
您使用的 roundTime
函数不适用于时区感知日期。
要支持它,您可以这样修改它:
def roundTime(dt=None, dateDelta=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.now()
#Make sure dt and datetime.min have the same timezone
tzmin = dt.min.replace(tzinfo=dt.tzinfo)
seconds = (dt - tzmin).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)
通过这种方式,该函数既适用于原始日期,也适用于 TZ 感知日期。 然后您可以像第二次尝试一样继续:
local_time = timezone.localtime(timezone.now())
mytime = roundTime(local_time, timedelta(minutes=15))
要舍入可识别时区的日期时间对象,make it a naive datetime object, round it, and attach the correct time zone info for the rounded time:
from datetime import timedelta
from django.utils import timezone
def round_time(dt=None, delta=timedelta(minutes=1)):
if dt is None:
dt = timezone.localtime(timezone.now()) # assume USE_TZ=True
tzinfo, is_dst = dt.tzinfo, bool(dt.dst())
dt = dt.replace(tzinfo=None)
f = delta.total_seconds()
rounded_ordinal_seconds = f * round((dt - dt.min).total_seconds() / f)
rounded_dt = dt.min + timedelta(seconds=rounded_ordinal_seconds)
localize = getattr(tzinfo, 'localize', None)
if localize:
rounded_dt = localize(rounded_dt, is_dst=is_dst)
else:
rounded_dt = rounded_dt.replace(tzinfo=tzinfo)
return rounded_dt
为避免浮点问题,所有计算都可以使用整数微秒 (dt.resolution
) 重写。
示例:
>>> round_time(delta=timedelta(minutes=15))