新手一枚,以前一直以为时间戳是不带时区的,可今天发现 datetime.now().timestamp()和 datetime.utcnow().timestamp()转出来的时间戳不一样。 那么问题来了,拿到一个外部传进来的时间戳时,我应该用 utcfromtimestamp()呢,还是 fromtimestamp()去转成 datetime 形式
1
explon 2018-04-17 10:28:27 +08:00
你应该先搞清时间戳的概念
|
2
turan12 2018-04-17 10:30:49 +08:00 1
Python 表示这还真不知道
|
3
NoAnyLove 2018-04-17 10:37:23 +08:00 2
看具体情况。理论上,timestamp 是没有时区概念的,所有的 timestamp 都是从 UTC 开始算。datetime.datetime.fromtimestamp 会将 timestamp 转换出来的时间转换到本地时区,但是不添加 tzinfo,所以属于 tz-naive 的本地时区时间;而 utcfromtimestamp 转换出来的 datetime 不进行时区转换,是 tz-naive 的 UTC 时间
|
4
mzmxcvbn OP @explon 我的意思是如果我拿到一个时间戳,我想要一个 datetime 形式的 utc 时间。如果这个时间戳是从 datetime.now 转过来的,我用 utcfromtimestamp()就能拿到正确的值。但如果这个时间戳是从 datetime.utcnow 转过来的,我再用 utcfromtimestamp()就不对了,这种时候用 fromtimestamp()就行了。但只有时间戳应该怎么判断该用 utcfromtimestamp()还是 fromtimestamp()呢
|
5
wwqgtxx 2018-04-17 10:38:13 +08:00 via iPhone 5
我说一个物品的重量是 25,你帮我算算是公斤还是市斤
|
6
tabris17 2018-04-17 10:39:42 +08:00 2
timestamp 是 UTC 时间,你转换出来不一致说明你设置的 timezone 不对
|
7
pimin 2018-04-17 10:39:51 +08:00 via Android
这个问题问得我...
|
8
mzmxcvbn OP @wwqgtxx 你的意思是我是要去问这个时间戳的来源,这个是 now.timestamp()转出来的还是 utcnow.timestamp()转出来的是吗。。。
|
9
laoyur 2018-04-17 10:41:10 +08:00
@mzmxcvbn 上面的 NoAnyLove 哥不是说了嘛,timestamp 本身都是从 UTC 算的
你用 utcfromtimestamp 还是 fromtimestamp 对结果没有差别,只是一个返回的是 utc 0 时区的 datetime object,另一个是 local 时区的 datetime object,两个对象指代的都是同一个时间点啊,有啥问题? |
10
mzmxcvbn OP @laoyur 我的意思是如果我拿到一个时间戳,我想要一个 datetime 形式的 utc 时间。如果这个时间戳是从 datetime.now 转过来的,我用 utcfromtimestamp()就能拿到正确的值。但如果这个时间戳是从 datetime.utcnow 转过来的,我再用 utcfromtimestamp()就不对了,这种时候用 fromtimestamp()就行了。但只有时间戳应该怎么判断该用 utcfromtimestamp()还是 fromtimestamp()呢
|
11
mzmxcvbn OP @laoyur 因为我发现 datetime.now().timestamp()和 datetime.utcnow().timestamp()转出来的时间戳不一样。。。。
|
12
arischow 2018-04-17 10:48:46 +08:00 via iPhone
先去搞清楚 timezone-naive, timezone-aware
|
13
wwqgtxx 2018-04-17 10:50:05 +08:00 via iPhone
@mzmxcvbn 实际上只有 utcnow 的 timestamp 转换出来的才是标准时间戳,直接用 now 的 timestamp 并不是标准 unix 时间戳
|
14
bolide2005 2018-04-17 10:55:18 +08:00
取时间戳为啥不直接用 time.time()? datetime.timestamp 本身是用来做转换的,不是取时间戳;你用哪个时区转换就得用哪个时区反转
|
15
AndyMo 2018-04-17 10:58:12 +08:00 via Android
所以应该问一下那个外部时间戳的来源,问他时间戳用的是不是 utc 时间,不是的话还要问所用时区。不问的话无解。
|
16
mzmxcvbn OP @bolide2005 我刚刚试了一下 time.time()也不是标准 unix 时间戳,有别的取标准时间戳的方法吗
|
17
mzmxcvbn OP @wwqgtxx 万分感谢!我也是今天才知道 datetime.now().timestamp()取出来的不是标准时间戳。
|
18
wwqgtxx 2018-04-17 11:05:27 +08:00 via iPhone
@mzmxcvbn 按照 python 官方文档,time.time()的确是标准时间戳,不过你需要 int 转换一下
还有,java/javascript 中的时间戳是以毫秒为单位的,需要 int(time.time()*1000) |
19
mzmxcvbn OP @NoAnyLove 万分感谢!我整理一下你看对吗:如果确定传过来的是标准 unix 时间戳,我用 datetime.fromtimestamp()就能拿到一个 datetime 形式的 utc 时间。但如果对面不是标准的时间戳,我就要用 datetime.utcfromtimestamp()才能拿到一个 datetime 形式的 utc 时间。
|
20
laoyur 2018-04-17 11:07:22 +08:00
@mzmxcvbn
timestamp()是 py3 才有的吧 你要拿真正的时间戳,首先要保证 datetime 对象是有 tzinfo 的,而你用 datetime.now()或者 datetime.utcnow()生成的都是 naive 的对象,不带 tzinfo,所以你再用 timestamp()获得的自然也可能是不正确的时间戳了 |
21
mzmxcvbn OP @wwqgtxx 啊。。。为什么我 time.time()出来的时间戳是和 datetime.now().timestamp()一样的,
|
22
bolide2005 2018-04-17 11:11:13 +08:00
@mzmxcvbn #16
用 time.gmtime(0)查一下你系统的 epoch,看看是不是标准 utc,可能是你系统配置或者时钟有问题 |
23
mzmxcvbn OP @bolide2005 time.struct_time(tm_year=1970, tm_mon=1, tm_mday=1, tm_hour=0, tm_min=0, tm_sec=0, tm_wday=3, tm_yday=1, tm_isdst=0) 查出来是这个,应该对的吧
|
24
honeycomb 2018-04-17 11:15:46 +08:00 via Android
如果它是一个 ISO8601 格式的时间戳,那么它已经携带了时区信息,或表示它是一个 UTC 时间(即以 UTC+0 处理)
如果已知它是整数且是 Unix 时间戳,那么就隐含了是 UTC 时间的信息 如果什么都没有,就不好说了 |
25
zsdroid 2018-04-17 11:20:32 +08:00
。。。首先时间戳是没有时区的
那么为什么 datetime.now().timestamp()和 datetime.utcnow().timestamp()转出来的时间戳不一样, 因为 datetime.now()和 datetime.utcnow()不一样 |
26
zjsxwc 2018-04-17 11:20:40 +08:00
咦,我 python 里的 datetime 对象怎么没有 timestamp 方法。
|
27
scriptB0y 2018-04-17 11:24:43 +08:00
用个 arrow 或 https://github.com/sdispater/pendulum (推荐后者)
importPython 3.6.4 (default, Mar 9 2018, 23:15:03) Type 'copyright', 'credits' or 'license' for more information IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help. In [1]: import arrow In [2]: arrow.now().timestamp, arrow.utcnow().timestamp Out[2]: (1523935279, 1523935279) |
28
wwqgtxx 2018-04-17 11:25:08 +08:00
@mzmxcvbn 又翻了一下文档,time.time()用的是本地时区,标准的时间戳还是应该用 datetime.utcnow().timestamp()
|
30
mzmxcvbn OP @wwqgtxx 好的,谢谢,辛苦了。我还以为是我电脑有问题呢,看来取标准时间戳只能用 datetime.utcnow().timestamp()了
|
31
bolide2005 2018-04-17 11:35:02 +08:00
@wwqgtxx #28 时间戳没有时区概念
@mzmxcvbn #23 看代码,datetime.timestamp 方法,实际上计算的是你给的那个 datetime 相对于 utc 时间的秒数,但里面默认了使用本地时区 看这里 >>> datetime.utcnow() datetime.datetime(2018, 4, 17, 3, 32, 23, 714844) >>> datetime.utcfromtimestamp(datetime.utcnow().timestamp()) datetime.datetime(2018, 4, 16, 19, 32, 41, 180266) 看到了吗?用这个 utcnow 时间戳是转换不回来正确的 utc 时间的,因为提前了 8 个小时,所以,time.time()才是正确的,用这个网站验证你的时间戳 https://www.unixtimestamp.com/ |
32
ETiV 2018-04-17 11:35:37 +08:00 via iPhone
看你们讨论让我想起几周前我跟我们同事讨论时间戳的问题,也是特别纠结。
当时还说,得叫霍金来帮忙… 每隔几天霍金去世了…… |
33
AndyMo 2018-04-17 11:36:17 +08:00 via Android
@AndyMo 看了 NoAnyLove 的回复,去查了下。时间戳没有时区概念,datetime.datetime.fromtimestamp()和 utcfromtimestamp()区别只是前者将时间转到了当前主机的本地时间。所以用哪个方法转化时间戳都一样……之前我也没理解时间戳的概念啊。但是不问外部传来时间戳的时区,就不知道它原来的本地时间。这个我应该还是没说错。
|
34
wwqgtxx 2018-04-17 11:36:32 +08:00
@bolide2005 时间戳本身的确没有时区的概念,但是按照 unix 标准时间戳的定义是用 utc 时区进行计算的
|
35
incompatible 2018-04-17 11:36:33 +08:00 1
楼主没搞清设计这个接口时的权责划分的问题。
你拿到 datetime 时,你不需要考虑它的来源是 datetime.now()还是 datetime.utcnow(),这是调用你的接口的人应该考虑的问题。你只要按照固定的方法(比如 fromtimestamp())来处理就好了。 如果你真的这么在意 datetime 的时区,那么改一下接口的设计,加上 tzinfo,让调用方把 datetime 和 tzinfo 一并传给你。 |
36
Justkkk 2018-04-17 11:37:51 +08:00
推荐个库 arrow 专解决这些时间转换的破问题
|
37
bolide2005 2018-04-17 11:38:00 +08:00
@wwqgtxx #34 你可以按我给的那个网站验证一下,那个时间戳是正确的
|
38
wwqgtxx 2018-04-17 11:54:08 +08:00
@bolide2005 真的觉得时间是一个值得讨论 N 小时的问题,,我再清清脑子,,
|
39
AndyMo 2018-04-17 12:12:20 +08:00 via Android
@zsdroid 突然想到,既然时间戳没有时区概念,那么转化时间戳的 timestamp()是不应该传入带时区的时间。也就是 datetime.now().timestamp()是错误的用法?
|
40
mzmxcvbn OP @bolide2005
不不不,datetime.utcnow().timestamp()只要用 fromtimestamp()就能换回正确的 utc 时间了。 datetime.now().timestamp()才要用 utcfromtimestamp()才能得到 utc 时间 d1 = datetime.now() d2 = datetime.utcnow() t1 = d1.timestamp() t2 = d2.timestamp() t3 = time.time() nd1 = datetime.utcfromtimestamp(t1) nd2 = datetime.fromtimestamp(t2) nd3 = datetime.utcfromtimestamp(t3) 这里 nd1,nd2,nd3 拿到的都是相同的 utc 时间 另外,你的意思是 time.time()才是 unix 标准时间戳?,那 datetime.utcnow().timestamp()是啥 |
43
lolizeppelin 2018-04-17 12:23:05 +08:00 via Android
用 unix 时间为 0 输出就知道了
|
44
mzmxcvbn OP @bolide2005
@wwqgtxx 找了几个在线的时间戳网站,好像还真是这样: datetime.now().timstamp()和 time.time()出来的就是标准 unix 时间戳。 那么问题来了,datetime.utcnow().timstamp()出来的这个是什么鬼。 |
45
bolide2005 2018-04-17 12:49:08 +08:00
@mzmxcvbn #40 看函数定义啊
Help on built-in function fromtimestamp: fromtimestamp(...) method of builtins.type instance timestamp[, tz] -> tz's local time from POSIX timestamp. fromtimestamp 本来得到应该是你的本地时间,现在得到的却是 utc 时间了 |
46
bolide2005 2018-04-17 12:50:53 +08:00
@mzmxcvbn #44 之前说过了,是把 utc 时间当做本地时间转换的时间戳,可能是 bug 或者是 feature (滑稽
|
47
mzmxcvbn OP @bolide2005
嗯啊,也就是说,datetime.now().timstamp()和 time.time()出来的就是标准 unix 时间戳。 对于外部传来的标准 unix 时间戳,用 fromtimestamp()拿到的就是本地时间的 datetime ;用 utcfromtimestamp()拿到的就是 utc 时间的 datetime。这样总结没问题吧。 |
48
bolide2005 2018-04-17 12:57:04 +08:00 via Android 1
@mzmxcvbn 对的,实际上因为 Python2 里面不存在 datetime.timestamp 方法,一般都是使用 time.time,就不会出现今天你说的这个 utcnow.timestamp 问题
|
49
mzmxcvbn OP |
50
sampeng 2018-04-17 17:43:55 +08:00
搞清楚时间戳,时区,utc,cst,等等时间格式规则,问题迎刃而解。都有专门的 rfc 文档解释,当然,那个很晦涩,直接 google。一大把的教程。。。
只是用第三方库来处理问题,三个月不用。又得踩一次坑 |
51
bomb77 2018-04-17 18:02:57 +08:00
In [52]: datetime.datetime.fromtimestamp?
Docstring: timestamp[, tz] -> tz's local time from POSIX timestamp. Type: builtin_function_or_method In [53]: tz_cn = pytz.timezone('Asia/Shanghai') In [54]: tz_utc = pytz.timezone('utc') In [55]: datetime.datetime.fromtimestamp(0, tz_utc) Out[55]: datetime.datetime(1970, 1, 1, 0, 0, tzinfo=<UTC>) In [56]: datetime.datetime.fromtimestamp(0, tz_cn) Out[56]: datetime.datetime(1970, 1, 1, 8, 0, tzinfo=<DstTzInfo 'Asia/Shanghai' CST+8:00:00 STD>) In [57]: datetime.datetime.fromtimestamp(0) Out[57]: datetime.datetime(1970, 1, 1, 8, 0) |
52
raptor 2018-04-17 22:23:38 +08:00
两个字:约定
最好的方法是所有时间戳都带上时区,再约定下不带时区的情况下默认用哪个时区,一般最好是 UTC |
53
janxin 2018-04-18 09:54:09 +08:00
timestamp 是时区相关的,你只要在同一时区下解决就 ok 了
|