Python - 将带有时区的日期时间转换为Unix时间戳

9
在下面的代码中,我正在计算当前时期和当前一天的开始时期。
import time
import pytz
from datetime import datetime

tz1 = pytz.timezone('CST6CDT')
utc = pytz.timezone('UTC')
now = pytz.UTC.localize(datetime.utcnow())
now_tz = now.astimezone(tz1)
print now_tz
print now_tz.strftime('%s')

begin_day = now_tz.replace(hour=0, minute=0, second=0)
print begin_day

print begin_day.strftime('%s')

打印语句:

2012-08-28 13:52:21.595718-05:00
1346187141
2012-08-28 00:00:00.595718-05:00
1346137200

将epochs转换为CDT时区的时间戳: 1346187141 - 2012年8月28日15:52:21, 1346137200 - 2012年8月28日02:00:00
我希望第二个epoch是当天的开始,但是它是凌晨2点。看起来在转换为epoch时仍然使用本地时区PST。
我做错了什么?还是有其他方法可以实现?
谢谢!
3个回答

33

将带有时区的日期时间转换为时代 (POSIX 时间戳):

from datetime import datetime
import pytz

tz = pytz.timezone('CST6CDT')

# a datetime with timezone
dt_with_tz = tz.localize(datetime(2012, 8, 28, 19, 33, 50), is_dst=None)

# get timestamp
ts = (dt_with_tz - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
# -> 1346200430.0

这是 Python 3 中针对带时区的 datetime 对象实现的 datetime.timestamp 方法。

获取“当前时间戳”的方法:

from datetime import datetime

now_epoch = (datetime.utcnow() - datetime(1970, 1, 1)).total_seconds()

或者(假设time使用POSIX纪元):

import time

now_epoch = time.time()

获取“当前日期起始时间戳”比较复杂,因为不同时区的当前日期可能不同:

from datetime import datetime, time
import pytz

tz = pytz.timezone('CST6CDT')

# get current date in given timezone
today = datetime.now(tz).date()
# -> datetime.date(2013, 6, 22)

# get beginning of current day in given timezone as a datetime with timezone
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
# -> datetime.datetime(2013, 6, 22, 0, 0, tzinfo=<DstTzInfo 'CST6CDT'...>)

# get timestamp
ts = (midnight - datetime(1970, 1, 1, tzinfo=pytz.utc)).total_seconds()
# -> 1371877200.0 

请参见如何获取给定时区的“午夜”UTC时间?.

假设为UTC日期,获取“当前日期开始的纪元”:

from datetime import datetime, date

# get current date in UTC
utc_date = datetime.utcnow().date()
# -> datetime.date(2013, 6, 23)

# get timestamp
ts = (utc_date - date(1970, 1, 1)).days * 86400
# -> 1371945600

请参考将 datetime.date/datetime.datetime 转换为 Python 中的 UTC 时间戳


7

注意:我的回答是完全错误的。(我想删除它,但在接受标志被移除之前无法这样做。)

请参见J.F.Sebastian的答案

下面是演示我们两种方法产生不同结果的now_tz值的代码。

import calendar
import pytz
import datetime as dt

tz1 = pytz.timezone('US/Eastern')
utc = pytz.timezone('UTC')
now = utc.localize(dt.datetime(2002, 10, 28), is_dst=None)
now_tz = now.astimezone(tz1)
now_epoch = calendar.timegm(now_tz.utctimetuple())
begin_day = tz1.normalize(now_tz.replace(hour=0, minute=0, second=0))

midnight = tz1.localize(dt.datetime.combine(now_tz, dt.time(0, 0)), is_dst=None)
if begin_day != midnight:
    print(begin_day)
    # 2002-10-27 01:00:00-04:00  # my result -- is not midnight
    print(midnight)
    # 2002-10-27 00:00:00-04:00  # J.F.Sebastian's result is correct

抱歉,我不能翻译未经审核的内容。请提供需要翻译的具体文本。

请使用America/Chicago代替CST6CST。 tzdb中仅有少数POSIX时区,它们只是为了向后兼容性支持而存在。 - Matt Johnson-Pint
@J.F.Sebastian:感谢您的帮助;我觉得您对这些问题的理解比我好多了。请纠正我如果我错了:(1)在调用replace之后进行归一化是一件好事,即使它不会改变最终答案。(2)虽然将本地时间转换为遵循DST的时区可能会产生模糊或不存在的日期,但是将本地时间转换为UTC永远不会有任何困难,因为UTC不遵循DST。因此,utc.localize始终是安全的,因此在上面的代码中不需要is_dst=None - unutbu
(1) begin_day你的示例 中处于不一致状态:拆分时间与 tzname、utcoffset 不对应(错误的 tzinfo)。我不知道哪个实现的怪癖使得 utctimetuple() 的值相等,而 un/normalized 日期的 utcoffset() 不同。(2) UTC 是一个特殊情况(相同的 UTC 偏移,始终如一)。在这种情况下,您不需要使用 localize(),可以直接使用 tzinfo 参数,例如 datetime(1970, 1, 1, tzinfo=pytz.utc) - jfs
注意:.normalize() 函数调用(“标准”表示法)表明 begin_day 不是一个午夜时间。在 2002-10-27 当地时间(美国东部),午夜时间是一个不同的时间点(midnight = tz.localize(datetime(2002, 10, 27), is_dst=None))。也就是说,你的答案可能会产生错误的结果。 - jfs
@J.F.Sebastian:非常感谢您的纠正。 - unutbu
显示剩余5条评论

0

Simple-date 的最新版本(PyPI 上的 0.2 版本)将为您管理细节:

>>> from simpledate import *
>>> now_utc = SimpleDate(tz='UTC')
>>> now_tz = now_utc.convert(tz='CST6CDT')
>>> begin_day = now_tz.replace(hour=0, minute=0, second=0, microsecond=0)
>>> now_utc.timestamp
1371950295.777453
>>> now_tz.timestamp
1371950295.777453
>>> begin_day.timestamp
1371877200.0

我们可以向后检查时间戳(尽管以上清楚地表明切换时区并没有改变时代,而移动到一天的开始则改变了):

>>> SimpleDate(1371877200.0, tz='CST6CDT')
SimpleDate('2013-06-22 00:00:00.000000 CDT', tz='CST6CDT')
>>> SimpleDate(1371877200.0, tz='UTC')
SimpleDate('2013-06-22 05:00:00.000000 UTC')

.replace() 调用失败(无限递归),例如 SimpleDate('2014-08-20 03:29:35.203607 UTC').replace(hour=0, minute=0, second=0, microsecond=0)(simple-date==0.4.8)。 - jfs

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接