将具有UTC偏移量的Unix时间戳转换为不同时区的Python日期时间?

时间:2018-12-25 06:00:41

标签: python datetime timezone

如果我运行以下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时间)
  • 告诉我日期/时间,就像我在当地时区看到的那样

在第一种情况下,我所拥有的只是一个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>

0 个答案:

没有答案