0

随意添加您最喜欢的模块,但到目前为止,我们已经有了time, datetime, dateutil, pytz, 和locale处理,因为PEP-431尚未实施,为我们提供了一种统一、具体的方式来处理时区及其相关的怪事比如在夏令时切换期间出现两次的模糊日期时间,或者根本不出现。无论如何,我的问题相当平淡,但我似乎找不到答案。

背景故事:我正在为Sublime Text开发一个小插件,最初将允许用户在当前文档中插入时间戳(以他们指定的格式,回退到默认值)。最终它将在保存时更新时间戳,但这与此处无关。这是我简短的、独立的示例代码:

import sublime_plugin
from datetime import datetime as dt


class TimeStampCommand(sublime_plugin.TextCommand):

    def run(self, edit):
        stamp = dt.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")  # 2013-10-10 22:38:40 UTC
        for r in self.view.sel():
            if r.empty():
                self.view.insert(edit, r.a, stamp)
            else:
                self.view.replace(edit, r, stamp)

格式化选项列表中,我应该能够添加%Z并获取本地时区:

stamp = dt.now().strftime("%Y-%m-%d %H:%M:%S %Z")  # should be 2013-10-10 18:38:40 EDT

或稍微修改它并获得更通用的 UTC 偏移量:

stamp = dt.now().strftime("%Y-%m-%d %H:%M:%S UTC %z")  # should be 2013-10-10 18:38:40 UTC -0400

不幸的是,情况并非如此,因为返回的时间dt.now()是“幼稚的”——它没有附加任何时区信息。我可以使用datetime.tzinfo,但无济于事,这只是一个抽象基类,因为时区混乱而复杂并且变化很大。所以,对于我的问题的根源:我如何创建一个可以利用完整数组的“感知” time///对象datetimedateutilwhateverstrftime()格式化选项?我希望用户能够根据自己的语言环境(我需要以某种方式检测到这一点)或根据提供的语言来随意格式化时间戳。最好我希望它在 Windows、Mac 和 Linux(Sublime Text 支持的平台)上工作。最后,如果 Python 2.6 和 3.3(分别为 ST2 和 ST3 的内置解释器版本)之间存在差异,我想知道它们。

请注意,我并不是要您为我编写所有代码,我想自己学习。我只需要一些好的指示来朝着正确的方向前进,因为我一天中的大部分时间都在旋转我的车轮。至少,弄清楚如何生成2013-10-10 18:38:40 UTC -0400将是一个很好的开始,尽管其他东西也会非常好:)

4

1 回答 1

1

如何创建一个可以利用 strftime() 格式化选项的完整数组的“感知”时间/日期时间/dateutil/任何对象?

好吧,如果你有一个时区,这很容易,使用pytz模块:

>>> mytz = pytz.timezone('America/Los_Angeles')
>>> now = datetime.datetime.now(tz=mytz)
>>> now
datetime.datetime(2013, 10, 10, 16, 34, 3, 113620, tzinfo=<DstTzInfo 'America/Los_Angeles' PDT-1 day, 17:00:00 DST>)

那是一个有意识的时区。如果我把它喂给 %Z?

>>> now.strftime('%Y-%m-%d %H:%M:%S %Z')
'2013-10-10 16:34:03 PDT'

当然,这不是您可以解析回明确的日期时间对象的东西,因为无法判断它是指太平洋还是巴基斯坦。因此,向最终用户显示可能很有用,但除此之外没什么用。即使您只决定美国很重要,“MST”是否意味着 Mountain 与大多数美国 DST 规则中的 -7 一样,或者与亚利桑那州无 DST 规则中的 -7 一样?而且大多数流行的三字母代码比这两个还要糟糕。


但是,更重要的是,您首先如何获得该时区?

你不能。

在某些 POSIX 系统上,您可以从os.environ['TZ']. 但通常不是——或者,如果它可用,除非用户特意将其明确设置为有用的时区标识符,否则它将是一个模棱两可的缩写,如“PST”。

在几乎 POSIX 系统上,您可以这样做:

>>> time.tzset()
>>> time.tzname
('PST', 'PDT')

但这肯定是一个模棱两可的缩写。(而且它仍然无法在 Windows 上运行。)


至少,弄清楚如何生成 2013-10-10 18:38:40 UTC -0400 将是一个很好的开始

这不是微不足道的,但至少很容易,无需任何第三方代码;这很乏味。

首先,如果您可以信任tzset(大多数 POSIX 平台):

>>> time.tzset()
>>> sec = -time.timezone

或者,如果您不能信任tzset

>>> t = time.time()
>>> local = datetime.datetime.fromtimestamp(t)
>>> utc = datetime.datetime.utcfromtimestamp(t)
>>> offset = local - utc
>>> sec = offset.total_seconds()

然后,您只需将其格式化为字符串:

>>> hr, sec = divmod(sec, 3600)
>>> min, sec = divmod(sec, 60)
>>> offstr = '{:+03d}{:02d}'.format(hr, min)

现在,如果你想格式化一个简单的本地时间:

>>> datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " " + offstr
'2013-10-10 16:18:36 -0800'

那么,你应该怎么做?

好吧,显然,对于所有内部和持久性使用,仍然使用 UTC 时间。那么您只需要处理本地时间即可直接输入和输出。而且,由于您正在编写桌面应用程序,而不是 Web 服务,因此只需使用将 naive-local 转换为 UTC 和从 UTC 转换的各种函数,而无需知道“本地”实际上是哪个时区。

在您的用例中,用户的时间戳可以从一个简单的日期时间格式化,如果可能的话,加上您从time模块中得到的名称tzset,如果不是,则回退到偏移量。这不会比建立一个有意识的日期时间更糟糕。

于 2013-10-10T23:19:19.930 回答