随意添加您喜欢的模块,但到目前为止,我们已经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)
从formatting options列表中,我应该可以添加%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
/ datetime
/ dateutil
/ whatever
对象,可以利用完整的数组strftime()
格式化选项?我希望用户能够根据他们自己的语言环境(不知何故我需要检测到这个)或者根据提供的格式来设置时间戳的格式。我希望它能在Windows,Mac和Linux(Sublime Text支持的平台)上运行。最后,如果Python 2.6和3.3之间存在差异(分别是ST2和ST3的内置解释器版本),我想知道它们。
请注意,我不是要求你为我编写所有代码,我想自己学习。我只是需要一些好的指示才能朝着正确的方向前进,因为我一整天大部分时间都在转动轮子。绝对最低限度,只是弄清楚如何生成2013-10-10 18:38:40 UTC -0400
将是一个很好的开始,虽然其他东西也会非常好:)
答案 0 :(得分:1)
如何创建“感知”时间/日期时间/日期/任何可以利用完整strftime()格式选项的对象?
好吧,如果你有一个时区,这很容易,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”是指具有美国大部分DST规则的-7和-7与亚利桑那州的无DST规则一样?大多数流行的三字母代码甚至比这两个更差。
但是,更重要的是,你如何首先获得那个时区?
你不能。
在某些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服务,因此只需使用各种功能将天真本地转换为UTC,而不必知道“本地”实际上是哪个时区。
在您的使用案例中,用户的时间戳可以从天真的日期时间加上格式化,如果可能的话,还可以在time
之后从tzset
模块中获取的名称,如果不是,则返回到偏移量。这不会比建立一个有意识的日期时间更糟糕。