V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
mzmxcvbn
V2EX  ›  Python

Python 怎么知道一个时间戳是不是 utc 时间转过来的

  •  
  •   mzmxcvbn · 2018-04-17 10:26:02 +08:00 · 7760 次点击
    这是一个创建于 2430 天前的主题,其中的信息可能已经有所发展或是发生改变。

    新手一枚,以前一直以为时间戳是不带时区的,可今天发现 datetime.now().timestamp()和 datetime.utcnow().timestamp()转出来的时间戳不一样。 那么问题来了,拿到一个外部传进来的时间戳时,我应该用 utcfromtimestamp()呢,还是 fromtimestamp()去转成 datetime 形式

    53 条回复    2018-04-18 09:54:09 +08:00
    explon
        1
    explon  
       2018-04-17 10:28:27 +08:00
    你应该先搞清时间戳的概念
    turan12
        2
    turan12  
       2018-04-17 10:30:49 +08:00   ❤️ 1
    Python 表示这还真不知道
    NoAnyLove
        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 时间
    mzmxcvbn
        4
    mzmxcvbn  
    OP
       2018-04-17 10:37:30 +08:00
    @explon 我的意思是如果我拿到一个时间戳,我想要一个 datetime 形式的 utc 时间。如果这个时间戳是从 datetime.now 转过来的,我用 utcfromtimestamp()就能拿到正确的值。但如果这个时间戳是从 datetime.utcnow 转过来的,我再用 utcfromtimestamp()就不对了,这种时候用 fromtimestamp()就行了。但只有时间戳应该怎么判断该用 utcfromtimestamp()还是 fromtimestamp()呢
    wwqgtxx
        5
    wwqgtxx  
       2018-04-17 10:38:13 +08:00 via iPhone   ❤️ 5
    我说一个物品的重量是 25,你帮我算算是公斤还是市斤
    tabris17
        6
    tabris17  
       2018-04-17 10:39:42 +08:00   ❤️ 2
    timestamp 是 UTC 时间,你转换出来不一致说明你设置的 timezone 不对
    pimin
        7
    pimin  
       2018-04-17 10:39:51 +08:00 via Android
    这个问题问得我...
    mzmxcvbn
        8
    mzmxcvbn  
    OP
       2018-04-17 10:40:59 +08:00
    @wwqgtxx 你的意思是我是要去问这个时间戳的来源,这个是 now.timestamp()转出来的还是 utcnow.timestamp()转出来的是吗。。。
    laoyur
        9
    laoyur  
       2018-04-17 10:41:10 +08:00
    @mzmxcvbn 上面的 NoAnyLove 哥不是说了嘛,timestamp 本身都是从 UTC 算的
    你用 utcfromtimestamp 还是 fromtimestamp 对结果没有差别,只是一个返回的是 utc 0 时区的 datetime object,另一个是 local 时区的 datetime object,两个对象指代的都是同一个时间点啊,有啥问题?
    mzmxcvbn
        10
    mzmxcvbn  
    OP
       2018-04-17 10:43:07 +08:00
    @laoyur 我的意思是如果我拿到一个时间戳,我想要一个 datetime 形式的 utc 时间。如果这个时间戳是从 datetime.now 转过来的,我用 utcfromtimestamp()就能拿到正确的值。但如果这个时间戳是从 datetime.utcnow 转过来的,我再用 utcfromtimestamp()就不对了,这种时候用 fromtimestamp()就行了。但只有时间戳应该怎么判断该用 utcfromtimestamp()还是 fromtimestamp()呢
    mzmxcvbn
        11
    mzmxcvbn  
    OP
       2018-04-17 10:44:07 +08:00
    @laoyur 因为我发现 datetime.now().timestamp()和 datetime.utcnow().timestamp()转出来的时间戳不一样。。。。
    arischow
        12
    arischow  
       2018-04-17 10:48:46 +08:00 via iPhone
    先去搞清楚 timezone-naive, timezone-aware
    wwqgtxx
        13
    wwqgtxx  
       2018-04-17 10:50:05 +08:00 via iPhone
    @mzmxcvbn 实际上只有 utcnow 的 timestamp 转换出来的才是标准时间戳,直接用 now 的 timestamp 并不是标准 unix 时间戳
    bolide2005
        14
    bolide2005  
       2018-04-17 10:55:18 +08:00
    取时间戳为啥不直接用 time.time()? datetime.timestamp 本身是用来做转换的,不是取时间戳;你用哪个时区转换就得用哪个时区反转
    AndyMo
        15
    AndyMo  
       2018-04-17 10:58:12 +08:00 via Android
    所以应该问一下那个外部时间戳的来源,问他时间戳用的是不是 utc 时间,不是的话还要问所用时区。不问的话无解。
    mzmxcvbn
        16
    mzmxcvbn  
    OP
       2018-04-17 10:59:28 +08:00
    @bolide2005 我刚刚试了一下 time.time()也不是标准 unix 时间戳,有别的取标准时间戳的方法吗
    mzmxcvbn
        17
    mzmxcvbn  
    OP
       2018-04-17 11:01:05 +08:00
    @wwqgtxx 万分感谢!我也是今天才知道 datetime.now().timestamp()取出来的不是标准时间戳。
    wwqgtxx
        18
    wwqgtxx  
       2018-04-17 11:05:27 +08:00 via iPhone
    @mzmxcvbn 按照 python 官方文档,time.time()的确是标准时间戳,不过你需要 int 转换一下
    还有,java/javascript 中的时间戳是以毫秒为单位的,需要 int(time.time()*1000)
    mzmxcvbn
        19
    mzmxcvbn  
    OP
       2018-04-17 11:06:53 +08:00
    @NoAnyLove 万分感谢!我整理一下你看对吗:如果确定传过来的是标准 unix 时间戳,我用 datetime.fromtimestamp()就能拿到一个 datetime 形式的 utc 时间。但如果对面不是标准的时间戳,我就要用 datetime.utcfromtimestamp()才能拿到一个 datetime 形式的 utc 时间。
    laoyur
        20
    laoyur  
       2018-04-17 11:07:22 +08:00
    @mzmxcvbn
    timestamp()是 py3 才有的吧
    你要拿真正的时间戳,首先要保证 datetime 对象是有 tzinfo 的,而你用 datetime.now()或者 datetime.utcnow()生成的都是 naive 的对象,不带 tzinfo,所以你再用 timestamp()获得的自然也可能是不正确的时间戳了
    mzmxcvbn
        21
    mzmxcvbn  
    OP
       2018-04-17 11:09:24 +08:00
    @wwqgtxx 啊。。。为什么我 time.time()出来的时间戳是和 datetime.now().timestamp()一样的,
    bolide2005
        22
    bolide2005  
       2018-04-17 11:11:13 +08:00
    @mzmxcvbn #16
    用 time.gmtime(0)查一下你系统的 epoch,看看是不是标准 utc,可能是你系统配置或者时钟有问题
    mzmxcvbn
        23
    mzmxcvbn  
    OP
       2018-04-17 11:14:45 +08:00
    @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) 查出来是这个,应该对的吧
    honeycomb
        24
    honeycomb  
       2018-04-17 11:15:46 +08:00 via Android
    如果它是一个 ISO8601 格式的时间戳,那么它已经携带了时区信息,或表示它是一个 UTC 时间(即以 UTC+0 处理)

    如果已知它是整数且是 Unix 时间戳,那么就隐含了是 UTC 时间的信息

    如果什么都没有,就不好说了
    zsdroid
        25
    zsdroid  
       2018-04-17 11:20:32 +08:00
    。。。首先时间戳是没有时区的
    那么为什么 datetime.now().timestamp()和 datetime.utcnow().timestamp()转出来的时间戳不一样,
    因为 datetime.now()和 datetime.utcnow()不一样
    zjsxwc
        26
    zjsxwc  
       2018-04-17 11:20:40 +08:00
    咦,我 python 里的 datetime 对象怎么没有 timestamp 方法。
    scriptB0y
        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)
    wwqgtxx
        28
    wwqgtxx  
       2018-04-17 11:25:08 +08:00
    @mzmxcvbn 又翻了一下文档,time.time()用的是本地时区,标准的时间戳还是应该用 datetime.utcnow().timestamp()
    wwqgtxx
        29
    wwqgtxx  
       2018-04-17 11:28:44 +08:00
    @scriptB0y 你那个还是按照 GMT+8 时区算的时间戳
    mzmxcvbn
        30
    mzmxcvbn  
    OP
       2018-04-17 11:29:07 +08:00
    @wwqgtxx 好的,谢谢,辛苦了。我还以为是我电脑有问题呢,看来取标准时间戳只能用 datetime.utcnow().timestamp()了
    bolide2005
        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/
    ETiV
        32
    ETiV  
       2018-04-17 11:35:37 +08:00 via iPhone
    看你们讨论让我想起几周前我跟我们同事讨论时间戳的问题,也是特别纠结。
    当时还说,得叫霍金来帮忙…

    每隔几天霍金去世了……
    AndyMo
        33
    AndyMo  
       2018-04-17 11:36:17 +08:00 via Android
    @AndyMo 看了 NoAnyLove 的回复,去查了下。时间戳没有时区概念,datetime.datetime.fromtimestamp()和 utcfromtimestamp()区别只是前者将时间转到了当前主机的本地时间。所以用哪个方法转化时间戳都一样……之前我也没理解时间戳的概念啊。但是不问外部传来时间戳的时区,就不知道它原来的本地时间。这个我应该还是没说错。
    wwqgtxx
        34
    wwqgtxx  
       2018-04-17 11:36:32 +08:00
    @bolide2005 时间戳本身的确没有时区的概念,但是按照 unix 标准时间戳的定义是用 utc 时区进行计算的
    incompatible
        35
    incompatible  
       2018-04-17 11:36:33 +08:00   ❤️ 1
    楼主没搞清设计这个接口时的权责划分的问题。
    你拿到 datetime 时,你不需要考虑它的来源是 datetime.now()还是 datetime.utcnow(),这是调用你的接口的人应该考虑的问题。你只要按照固定的方法(比如 fromtimestamp())来处理就好了。

    如果你真的这么在意 datetime 的时区,那么改一下接口的设计,加上 tzinfo,让调用方把 datetime 和 tzinfo 一并传给你。
    Justkkk
        36
    Justkkk  
       2018-04-17 11:37:51 +08:00
    推荐个库 arrow 专解决这些时间转换的破问题
    bolide2005
        37
    bolide2005  
       2018-04-17 11:38:00 +08:00
    @wwqgtxx #34 你可以按我给的那个网站验证一下,那个时间戳是正确的
    wwqgtxx
        38
    wwqgtxx  
       2018-04-17 11:54:08 +08:00
    @bolide2005 真的觉得时间是一个值得讨论 N 小时的问题,,我再清清脑子,,
    AndyMo
        39
    AndyMo  
       2018-04-17 12:12:20 +08:00 via Android
    @zsdroid 突然想到,既然时间戳没有时区概念,那么转化时间戳的 timestamp()是不应该传入带时区的时间。也就是 datetime.now().timestamp()是错误的用法?
    mzmxcvbn
        40
    mzmxcvbn  
    OP
       2018-04-17 12:12:21 +08:00
    @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()是啥
    rrfeng
        41
    rrfeng  
       2018-04-17 12:16:08 +08:00   ❤️ 1
    看我之前发的,还有人不信。
    /t/346227
    mzmxcvbn
        42
    mzmxcvbn  
    OP
       2018-04-17 12:22:18 +08:00
    @rrfeng 最后的结论是啥,就是用第三方模块吗。。
    lolizeppelin
        43
    lolizeppelin  
       2018-04-17 12:23:05 +08:00 via Android
    用 unix 时间为 0 输出就知道了
    mzmxcvbn
        44
    mzmxcvbn  
    OP
       2018-04-17 12:46:22 +08:00
    @bolide2005
    @wwqgtxx
    找了几个在线的时间戳网站,好像还真是这样:
    datetime.now().timstamp()和 time.time()出来的就是标准 unix 时间戳。
    那么问题来了,datetime.utcnow().timstamp()出来的这个是什么鬼。
    bolide2005
        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 时间了
    bolide2005
        46
    bolide2005  
       2018-04-17 12:50:53 +08:00
    @mzmxcvbn #44 之前说过了,是把 utc 时间当做本地时间转换的时间戳,可能是 bug 或者是 feature (滑稽
    mzmxcvbn
        47
    mzmxcvbn  
    OP
       2018-04-17 12:54:04 +08:00
    @bolide2005
    嗯啊,也就是说,datetime.now().timstamp()和 time.time()出来的就是标准 unix 时间戳。

    对于外部传来的标准 unix 时间戳,用 fromtimestamp()拿到的就是本地时间的 datetime ;用 utcfromtimestamp()拿到的就是 utc 时间的 datetime。这样总结没问题吧。
    bolide2005
        48
    bolide2005  
       2018-04-17 12:57:04 +08:00 via Android   ❤️ 1
    @mzmxcvbn 对的,实际上因为 Python2 里面不存在 datetime.timestamp 方法,一般都是使用 time.time,就不会出现今天你说的这个 utcnow.timestamp 问题
    mzmxcvbn
        49
    mzmxcvbn  
    OP
       2018-04-17 13:04:19 +08:00
    @bolide2005 真是万分感谢,帮忙解决了这个疑惑,不然以后很容易采坑。

    @wwqgtxx 总结在 47 楼了,应该是没错了。

    另外谢谢所有参与讨论和提供第三方库解决方法的朋友们
    sampeng
        50
    sampeng  
       2018-04-17 17:43:55 +08:00
    搞清楚时间戳,时区,utc,cst,等等时间格式规则,问题迎刃而解。都有专门的 rfc 文档解释,当然,那个很晦涩,直接 google。一大把的教程。。。
    只是用第三方库来处理问题,三个月不用。又得踩一次坑
    bomb77
        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)
    raptor
        52
    raptor  
       2018-04-17 22:23:38 +08:00
    两个字:约定

    最好的方法是所有时间戳都带上时区,再约定下不带时区的情况下默认用哪个时区,一般最好是 UTC
    janxin
        53
    janxin  
       2018-04-18 09:54:09 +08:00
    timestamp 是时区相关的,你只要在同一时区下解决就 ok 了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   2614 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 14:47 · PVG 22:47 · LAX 06:47 · JFK 09:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.