首页   注册   登录
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python 学习手册
Python Cookbook
Python 基础教程
Python Sites
PyPI - Python Package Index
http://www.simple-is-better.com/
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
V2EX  ›  Python

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

  •  
  •   mzmxcvbn · 92 天前 · 3064 次点击
    这是一个创建于 92 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

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

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

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

    最好的方法是所有时间戳都带上时区,再约定下不带时区的情况下默认用哪个时区,一般最好是 UTC
        53
    janxin   91 天前
    timestamp 是时区相关的,你只要在同一时区下解决就 ok 了
    关于   ·   FAQ   ·   API   ·   我们的愿景   ·   广告投放   ·   鸣谢   ·   实用小工具   ·   1984 人在线   最高记录 3541   ·  
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.1 · 23ms · UTC 12:22 · PVG 20:22 · LAX 05:22 · JFK 08:22
    ♥ Do have faith in what you're doing.
    沪ICP备16043287号-1