如果我运行以下git log命令(在此仓库中,为https://github.com/rubyaustralia/rubyconfau-2013-cfp):
$ git --no-pager log --reverse --date=raw --pretty='%ad %h'
1344507869 -0700 314b3d4
1344508222 +1000 dffde53
1344510528 +1000 17e7d3b
...
...我得到一个列表,其中包含每次提交的Unix时间戳(距Epoch以来的秒数)和UTC偏移量。我想做的是获取一个时区感知的日期时间,该时间将是:
在第一种情况下,我所拥有的只是一个UTC偏移量,而不是作者的时区-因此,我没有任何关于夏时制可能更改的信息。
在第二种情况下,我的操作系统很可能会设置为某个特定的语言环境,包括(地理)时区,该时区将了解DST的更改;例如,冬季CET时区的UTC偏移为+0100,而夏时制为夏令时,其UTC偏移为+0200(然后称为CEST)
无论如何,我想从UTC时间戳开始,因为“ 1344508222”的纪元秒数与时区无关;偏移量+1000只会帮助我们希望看到笔者看到的可读的输出。
我需要对Python 2.7项目执行此操作,并仔细研究了大量资源(SO帖子),然后我想到了以下示例(该示例试图从上述代码段中解析第二行,“ 1344508222 +1000 dffde53
”)。但是,我真的不确定是否正确。所以最终,我的问题是-这样做的正确方法是什么?
序言:
#!/usr/bin/env python2
# -*- coding: utf-8 -*-
import datetime
import pytz
import dateutil.tz
import time
def getUtcOffsetFromString(in_offset_str): # SO:1101508
offset = int(in_offset_str[-4:-2])*60 + int(in_offset_str[-2:])
if in_offset_str[0] == "-":
offset = -offset
return offset
class FixedOffset(datetime.tzinfo): # SO:1101508
"""Fixed offset in minutes: `time = utc_time + utc_offset`."""
def __init__(self, offset):
self.__offset = datetime.timedelta(minutes=offset)
hours, minutes = divmod(offset, 60)
#NOTE: the last part is to remind about deprecated POSIX GMT+h timezones
# that have the opposite sign in the name;
# the corresponding numeric value is not used e.g., no minutes
self.__name = '<%+03d%02d>%+d' % (hours, minutes, -hours)
def utcoffset(self, dt=None):
return self.__offset
def tzname(self, dt=None):
return self.__name
def dst(self, dt=None):
return datetime.timedelta(0)
def __repr__(self):
return 'FixedOffset(%d)' % (self.utcoffset().total_seconds() / 60)
开始解析:
tstr = "1344508222 +1000 dffde53"
tstra = tstr.split(" ")
unixepochsecs = int(tstra[0])
utcoffsetstr = tstra[1]
print(unixepochsecs, utcoffsetstr) # (1344508222, '+1000')
获取UTC时间戳-首先,我尝试使用1528917616 +0000
解析字符串dateutil.parser.parse
:
justthetstz = " ".join(tstra[:2])
print(justthetstz) # '1344508222 +1000'
#print(dateutil.parser.parse(justthets)) # ValueError: Unknown string format
...但是不幸的是失败了。
这可以获取UTC时间戳:
# SO:12978391: "datetime.fromtimestamp(self.epoch) returns localtime that shouldn't be used with an arbitrary timezone.localize(); you need utcfromtimestamp() to get datetime in UTC and then convert it to a desired timezone"
dtstamp = datetime.datetime.utcfromtimestamp(unixepochsecs).replace(tzinfo=pytz.utc)
print(dtstamp) # 2012-08-09 10:30:22+00:00
print(dtstamp.isoformat()) # 2012-08-09T10:30:22+00:00 # ISO 8601
好的,到目前为止很好-这个UTC时间戳看起来很合理。
现在,尝试获取作者的UTC偏移量中的日期-显然这里需要自定义类:
utcoffset = getUtcOffsetFromString(utcoffsetstr)
fixedtz = FixedOffset(utcoffset)
print(utcoffset, fixedtz) # (600, FixedOffset(600))
dtstampftz = dtstamp.astimezone(fixedtz)
print(dtstampftz) # 2012-08-09 20:30:22+10:00
print(dtstampftz.isoformat()) # 2012-08-09T20:30:22+10:00
这看起来也很合理,UTC的10:30等于+1000的20:30;再说一次,偏移量就是偏移量,这里没有歧义。
现在,我正在尝试导出本地时区中的日期时间-首先,看来我不应该使用.replace
方法:
print(time.tzname[0]) # CET
tzlocal = dateutil.tz.tzlocal()
print(tzlocal) # tzlocal()
dtstamplocrep = dtstamp.replace(tzinfo=tzlocal)
print(dtstamp) # 2012-08-09 10:30:22+00:00
print(dtstamplocrep) # 2012-08-09 10:30:22+02:00 # not right!
这看起来不正确,我得到了完全相同的“时钟字符串”,但偏移量不同。
但是,.astimezone
似乎可以工作:
dtstamploc = dtstamp.astimezone(dateutil.tz.tzlocal())
print(dtstamp) # 2012-08-09 10:30:22+00:00
print(dtstamploc) # 2012-08-09 12:30:22+02:00 # was August -> summer -> CEST: UTC+2h
我得到一个名为pytz.timezone
的东西:
cphtz = pytz.timezone('Europe/Copenhagen')
dtstamploc = dtstamp.astimezone(cphtz)
print(dtstamp) # 2012-08-09 10:30:22+00:00
print(dtstamploc) # 2012-08-09 12:30:22+02:00 # is August -> summer -> CEST: UTC+2h
...但是,我在这里不能使用.localize
,因为我的输入dtstamp
已经具有与其相关的时区,因此不再“天真”:
# dtstamploc = cphtz.localize(dtstamp, is_dst=True) # ValueError: Not naive datetime (tzinfo is already set)
到目前为止,这看起来似乎是正确的,但是我真的不确定-特别是因为我看到了:
pytz.astimezone not accounting for daylight savings?
您不能在datetime构造函数中分配时区,因为它没有给时区对象调整夏时制的机会-日期不可访问。这对于世界的某些地区甚至造成了更多问题,这些地区的时区名称和偏移量多年来一直在变化。
从pytz文档中:
不幸的是,在许多时区中,使用标准日期时间构造函数的tzinfo参数“不起作用”与pytz一起使用。
将本地化方法与原始日期时间结合使用。
...最终使我感到困惑:说我想这样做,并且我已经有了正确的时区时间戳,-我将如何为其得出“原始”日期时间?只是摆脱时区信息?还是正确的“原始”日期时间是从以UTC表示的时间戳版本中得出的(例如2012-08-09 20:30:22+10:00
-> 2012-08-09 10:30:22+00:00
,因此正确的“原始”日期时间将是2012-08-09 10:30:22
)? / p>