为什么datetime.utcnow()和datetime.now(timezone('UTC'))之间有区别?

时间:2017-09-02 22:58:51

标签: python-3.x datetime timestamp utc

从下面的代码片段中可以看出,两种方法之间存在一小时的差异。是什么原因?

from datetime import datetime
from pytz import timezone
import time

def timestamp2date(timestamp):
    # function converts a UTC timestamp into Europe/Zurich Gregorian date
    DATE_TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
    utcTimeStamp = datetime.fromtimestamp(int(timestamp)).replace(tzinfo=timezone('UTC'))
    return utcTimeStamp.astimezone(timezone('Europe/Zurich')).strftime(DATE_TIME_FORMAT)

timeStampUTC_1 = time.mktime(datetime.utcnow().timetuple())
print(timeStampUTC_1)
print(timestamp2date(timeStampUTC_1))
timeStampUTC_2 = time.mktime(datetime.now(timezone('UTC')).timetuple())
print(timeStampUTC_2)
print(timestamp2date(timeStampUTC_2))
print(timeStampUTC_2 - timeStampUTC_1)

# 1504385450.0
# 2017-09-03 00:50:50   this the right time
# 1504389050.0
# 2017-09-03 01:50:50
# 3600.0

2 个答案:

答案 0 :(得分:1)

原因是,datetime.timetuple()设置dst=-1,如果datetime不能识别偏移,dst=0 or 1设置为tm_isdst

来自文档:

  

结果的dst()标志是根据tzinfo方法设置的:Nonedst()None返回tm_isdst,{ {1}}设置为-1;否则如果dst()返回非零值,则tm_isdst设置为1;其他tm_isdst设置为0

In []:
datetime.utcnow()
Out[]:
datetime.datetime(2017, 9, 2, 23, 9, 12, 715042)

In []:
print(datetime.utcnow().dst())
Out[]:
None

In []:
datetime.now(timezone('UTC'))
Out[]:
datetime.datetime(2017, 9, 2, 23, 9, 15, 856983, tzinfo=<UTC>)

In []:
datetime.now(timezone('UTC')).dst()
Out[]
datetime.timedelta(0)

In []:
datetime(2017, 9, 2, 23, 9, 15, 856983).timetuple()
Out[]:
time.struct_time(tm_year=2017, tm_mon=9, tm_mday=2, tm_hour=23, tm_min=9, 
                 tm_sec=15, tm_wday=5, tm_yday=245, tm_isdst=-1)
                                                             ^^
In []:
datetime(2017, 9, 2, 23, 9, 15, 856983, timezone('UTC')).timetuple()
Out[]:
time.struct_time(tm_year=2017, tm_mon=9, tm_mday=2, tm_hour=23, tm_min=9, 
                 tm_sec=15, tm_wday=5, tm_yday=245, tm_isdst=0)
                                                             ^

这会更改timestamp生成的time.mktime(),因为mktime会将-1视为未知并使用本地时间,因此可能会计算dst=1,因此它们可能是1小时不同(3600s):

In []:
time.mktime(datetime(2017, 9, 2, 23, 9, 15, 856983).timetuple())
Out[]:
1504411755.0

In []:
time.mktime(datetime(2017, 9, 2, 23, 9, 15, 856983, timezone('UTC')).timetuple())
Out[]:
1504415355.0

答案 1 :(得分:0)

这是我进一步探索与夏令时标志相关的时区概念的结果。代码非常简单。

总结结果,有正确的方法来处理日期/时间信息:

  1. 日期/时间对象必须已本地化
  2. 如果本地化正确,日期/时间对象会显示正确的夏令时信息
  3. 当您将本地化的日期/时间对象转换为UTC日期/时间对象(根据定义DST不可知)时,会反映出这一点
  4. 例如,当您访问股票或货币历史分钟率API
  5. 时,所有这些考虑因素都特别相关

    代码:

    from datetime import datetime
    from pytz import timezone
    import time
    
    print("---- Winter time (CET=Central European Time) ----")
    dateStr = "2014-02-28 22:28:15"
    datetimeObjUnlocalized = datetime.strptime(dateStr, "%Y-%m-%d %H:%M:%S")
    print('UNL: ' + datetimeObjUnlocalized.strftime("%Y-%m-%d %H:%M:%S %Z%z"))
    print('     datetimeObjUnlocalized-->tm_isdst=' + str(datetimeObjUnlocalized.timetuple()[8]))
    datetimeObjZH = timezone('Europe/Zurich').localize(datetimeObjUnlocalized)
    print('ZH:  ' + datetimeObjZH.strftime("%Y-%m-%d %H:%M:%S %Z%z"))
    print('     datetimeObjZH-->tm_isdst=' + str(datetimeObjZH.timetuple()[8]))
    print("UTC: " + datetimeObjZH.astimezone(timezone('UTC')).strftime("%Y-%m-%d %H:%M:%S %Z%z"))
    
    print("\n---- Summer time (CEST=Central European Summer Time) ----")
    dateStr = "2014-06-28 22:28:15"
    datetimeObjUnlocalized = datetime.strptime(dateStr, "%Y-%m-%d %H:%M:%S")
    print('UNL: ' + datetimeObjUnlocalized.strftime("%Y-%m-%d %H:%M:%S %Z%z"))
    print('     datetimeObjUnlocalized-->tm_isdst=' + str(datetimeObjUnlocalized.timetuple()[8]))
    datetimeObjZH = timezone('Europe/Zurich').localize(datetimeObjUnlocalized)
    print('ZH:  ' + datetimeObjZH.strftime("%Y-%m-%d %H:%M:%S %Z%z"))
    print('     datetimeObjZH-->tm_isdst=' + str(datetimeObjZH.timetuple()[8]))
    print("UTC: " + datetimeObjZH.astimezone(timezone('UTC')).strftime("%Y-%m-%d %H:%M:%S %Z%z"))
    

    Console output