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
myyou
V2EX  ›  Python

web 开发涉及到时间的是一律使用 utc 时间吗?

  •  1
     
  •   myyou · 2016-07-21 15:26:34 +08:00 · 8288 次点击
    这是一个创建于 2807 天前的主题,其中的信息可能已经有所发展或是发生改变。
    第 1 条附言  ·  2016-07-21 17:38:31 +08:00
    评论下有人建议使用 unix 时间戳,但是 unix 时间日期是 1970~2038 ,不再这个范围的不是会出现问题?
    61 条回复    2016-07-23 11:42:06 +08:00
    julyclyde
        1
    julyclyde  
       2016-07-21 16:31:35 +08:00
    保存的时候应该用 UTC ,但似乎很少有遵守的
    展现的时候当然要本地化了
    haozhang
        2
    haozhang  
       2016-07-21 16:34:04 +08:00 via iPhone
    保存全部使用 utc 我觉得的是最佳方案,取值转换成 local time 即可
    cevincheung
        3
    cevincheung  
       2016-07-21 16:43:03 +08:00
    为什么就不能存时间戳。
    myyou
        4
    myyou  
    OP
       2016-07-21 17:05:35 +08:00
    @julyclyde
    @haozhang
    如果存储字符呢,例如: 2016-07-21 这样的格式,也要存成 utc 吗?
    pubby
        5
    pubby  
       2016-07-21 17:07:16 +08:00 via Android
    一律使用同一个时区,所有机器 NTP 对时,时区设置相同即可
    skydiver
        6
    skydiver  
       2016-07-21 17:08:40 +08:00
    一律使用 unix 时间戳
    myyou
        7
    myyou  
    OP
       2016-07-21 17:20:59 +08:00
    @skydiver 一般不存 datetime 之类的时间吗?
    imnpc
        8
    imnpc  
       2016-07-21 17:23:05 +08:00
    只建议用 unix 时间戳...
    myyou
        9
    myyou  
    OP
       2016-07-21 17:28:11 +08:00
    @imnpc 如果涉及到个人生日呢?
    myyou
        10
    myyou  
    OP
       2016-07-21 17:30:14 +08:00
    @cevincheung 如果涉及到个人生日呢?
    imnpc
        11
    imnpc  
       2016-07-21 17:31:25 +08:00
    @myyou
    个人生日那些随便存啊
    一般按照简单的 datatime 就可以或者纯文本

    时间戳使用在各种计算比较上的 比较方便
    myyou
        12
    myyou  
    OP
       2016-07-21 17:35:00 +08:00
    @cevincheung
    @imnpc
    @skydiver
    还有 unix 时间戳截止日期不是 2038 年吗?
    cevincheung
        13
    cevincheung  
       2016-07-21 17:37:26 +08:00
    @myyou
    date --date='@32472119461'

    看看输出啥。 233333
    myyou
        14
    myyou  
    OP
       2016-07-21 17:40:17 +08:00
    @cevincheung 64 位 ubuntu 14.04 输出这个: Tue Jan 1 01:11:01 CST 2999
    cevincheung
        15
    cevincheung  
       2016-07-21 17:45:43 +08:00
    @myyou 对啊。
    haozhang
        16
    haozhang  
       2016-07-21 18:05:16 +08:00 via iPhone
    @myyou 这肯定不对啊,日期不是同一天的时区怎么办?
    loading
        17
    loading  
       2016-07-21 18:32:58 +08:00 via Android
    unix 时间是从 1970 年 01 月 01 日 0:00:00 起算,用的是 utc 时区,所以也可以理解是另一种 utc 时间。
    2038 年是 32 位长度带来的精度问题,这个问题不同于千年虫问题。千年虫是判断 2000 年是闰年,少了一个判断,是代码错误。
    64 位的 unix 时间够用了,而且现在大家其实都在用了。
    loading
        18
    loading  
       2016-07-21 18:36:15 +08:00 via Android
    @haozhang unix 时间用的是 utc 时间
    haozhang
        19
    haozhang  
       2016-07-21 18:50:23 +08:00
    @loading 我说的东西和 unix 用不用 utc 时间有什么关系...
    loading
        20
    loading  
       2016-07-21 19:22:10 +08:00 via Android
    @haozhang 你不是说时区吗? utc 与格林威治时间 gmt 可以几乎认为相等。
    allenhu
        21
    allenhu  
       2016-07-21 19:23:55 +08:00 via Android   ❤️ 1
    搞清楚你的应用几国人在用,生命周期是多久,就清楚了
    haozhang
        22
    haozhang  
       2016-07-21 19:49:12 +08:00 via iPhone
    @loading 我说的是日期错位啊...
    caixiexin
        23
    caixiexin  
       2016-07-21 19:59:05 +08:00 via Android
    小于 1970 年的 Unix 时间戳,不是负数吗
    kookxiang
        24
    kookxiang  
       2016-07-21 20:02:48 +08:00
    unix 时间戳是到 2038 年?那只是因为你用 32 位的 int 来存而已吧
    lizon
        25
    lizon  
       2016-07-21 20:08:12 +08:00
    64 位的机器会有这个问题吗?
    skydiver
        26
    skydiver  
       2016-07-21 21:39:51 +08:00 via iPad
    @loading 千年虫不是闰年问题,是年份只用了两位整数来存的问题
    skydiver
        27
    skydiver  
       2016-07-21 21:40:15 +08:00 via iPad
    @myyou 用 64 位来存就没有 2038 问题了
    onlyice
        28
    onlyice  
       2016-07-21 22:03:37 +08:00
    expkzb
        29
    expkzb  
       2016-07-21 22:10:21 +08:00
    时间戳的问题在于不能表示时区,遇到航班信息就傻眼了
    loading
        30
    loading  
       2016-07-22 06:17:05 +08:00 via Android
    @skydiver 其实就是闰年问题。
    loading
        31
    loading  
       2016-07-22 06:18:41 +08:00 via Android
    @skydiver 哦,闰年问题是带来的主要问题之一…特别明显。
    tausi0661
        32
    tausi0661  
       2016-07-22 08:34:21 +08:00
    是不是 utc/unix 无所谓, 只要存储的所有时间是统一的时区就好, 并保证各 server 的时区及时间一致.
    lifanxi
        33
    lifanxi  
       2016-07-22 08:53:40 +08:00
    @loading
    重复一下 26 楼的话:千年虫不是闰年问题,是年份只用了两位整数来存的问题。参考老版的 13 位身份证号码来理解。

    2000 年是闰年,而 1900 年不是,如果把 2000 年误作 1900 年,确实会造成 2 月少一天的问题。但这不是通常“千年虫”讨论的范畴,也不是像你说的那样,因为“千年虫是判断 2000 年是闰年,少了一个判断”, 2000 年是闰年没有问题,你说的“少了一个判断”(能否整除 400 )只会造成把 1900 年也判成闰年。
    mengzhuo
        34
    mengzhuo  
       2016-07-22 09:05:43 +08:00 via iPhone

    等你们公司开始做国际化的时候 后面的程序员会感谢你的
    xuboying
        35
    xuboying  
       2016-07-22 09:09:12 +08:00 via Android
    @expkzb 航班时间这种涉及跨时区的不用时间戳才傻了。记录了时间戳用户才能得到不同时区的时间正确表示,特别是还有地方有夏时制冬时制,每次显示都要换算正确
    lifanxi
        36
    lifanxi  
       2016-07-22 09:18:03 +08:00
    时间其实是个很复杂的东西,但是可以把它理解成是个自然流逝的东西,然后人为给每一秒(毫秒也行,单位不重要,取决于你需要精度)进行计数。

    这个计数值在计算机领域通常可以用 Unix 时间戳来表示,在不考虑实现(变量位数)的前提下,这个计数值可以表示任意时间范围。所谓只能表示 1970-2038 是因为假设了只用有符号 32 位整型数的非负数部分对秒计数的原因。

    所以,用一个足够长的有符号整数来表示任意时间是没有问题的。但这个数值本身并不具有“时区”的含义,时区只在把它转换为人类可读的表示方式时才要考虑的问题。

    这个转换工作应该 100%交给操作系统去实现,而不应该自己土法按一年 365/366 年、每天 24 小时、每小时 60 分钟、每分钟 60 秒再加上时间偏移去计算,甚至前一天、后一天这种计算也应该用系统库去完成,而不要自己去做。

    因为时间日期计算里有太多坑了,基本上 99.9%的程序员自己实现的版本不会比系统已有的版本要好。最简单的有闰年、复杂一点的时区和夏时制、再复杂一点有闰秒、更复杂一点是一些历史特殊情况(比如时区变更)。
    yaodong
        37
    yaodong  
       2016-07-22 09:21:56 +08:00
    http://yellerapp.com/posts/2015-01-12-the-worst-server-setup-you-can-make.html


    > TL;DR Use UTC as the only timezone for your servers.
    BlueMeow
        38
    BlueMeow  
       2016-07-22 10:20:05 +08:00
    @lifanxi 对。有时候由于临时增加的闰秒、地区时区调整、夏令时等问题,时间存在处理各种陷阱。比如 http://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result 这个问题就是因为 1927 年上海时区调整引起的,这种细节自己处理的话总会有疏漏。
    bingwenshi
        39
    bingwenshi  
       2016-07-22 11:42:29 +08:00
    做个编程习惯良好的工程师,把时间都存储成 UTC 时间, 只是在展示的时候,根据用户时区再做转换就行了
    julyclyde
        40
    julyclyde  
       2016-07-22 11:58:03 +08:00
    使用 UTC 可以保证时序
    不要忘了所谓弟弟比哥哥先出生的夏令时事故
    julyclyde
        41
    julyclyde  
       2016-07-22 11:58:42 +08:00
    @loading 千年虫是年份只保留两位,不支持 21 世纪;而不是 2000 闰年的问题
    julyclyde
        42
    julyclyde  
       2016-07-22 11:59:03 +08:00
    @loading GMT 没有全球广泛的法律效力,虽然和 UTC 数值基本一致
    julyclyde
        43
    julyclyde  
       2016-07-22 12:00:36 +08:00
    另外 China standard time 据说不支持闰秒,在闰秒时会两次出现 59 秒,有可能发生逆序事故; UTC 是支持的
    loading
        44
    loading  
       2016-07-22 12:04:13 +08:00 via Android
    @julyclyde 嗯,你掌握得很全面。
    expkzb
        45
    expkzb  
       2016-07-22 12:34:56 +08:00
    @xuboying 请看你楼下的回复
    xuboying
        46
    xuboying  
       2016-07-22 13:12:39 +08:00 via Android
    @expkzb 是啊,下面也是表示要用 epoch 。时间戳表示了一个确定的时刻, human 时间只是加上时区 /dst 的时间戳不同表现显示而已
    silver107
        47
    silver107  
       2016-07-22 13:29:48 +08:00
    存时间戳,是不是没有时区问题
    rubyvector
        48
    rubyvector  
       2016-07-22 14:00:25 +08:00
    最近也遇到此问题.如果用户是跨时区的,可得注意了.不然大乱
    Comdex
        49
    Comdex  
       2016-07-22 14:28:16 +08:00
    @rubyvector
    @julyclyde
    @bingwenshi
    @lizon
    @skydiver 请教一下各位,在数据库中保存时间是使用 datetime 或字符串还是使用 int64 类型保存时间截好?现在比较普遍的做法是怎样的?
    quix
        50
    quix  
       2016-07-22 14:49:49 +08:00
    @myyou 生日的话... 并不是时间 只是个几月几日的信息, 连年份都没有
    如果说的是出生日期( dob) 的话则是一个不含时区的日期 因此也不应该是作为时间戳保存而应该作为字符串保存 ( 如果需要查询时进行比较可以存成统一时区的日期, 最好是 utc )
    Mirana
        51
    Mirana  
       2016-07-22 14:51:29 +08:00
    存时间戳也有时间问题啊 主要是是时区的问题
    jybox
        52
    jybox  
       2016-07-22 14:52:05 +08:00
    首先内部表示和物理层面肯定是存 UTC ,几乎所有数据库都是这样的(他们接受任何时区的时间,但会存成 UTC )。但如果你存 UTC 的话,一定要把时区也一起存起来(可能要放到单独的字段,要看数据库支持不支持)。

    因为时区是一个有关时间的重要元信息(和时区相关联的不仅仅是偏移量,还包括夏令时和冬令时之类的东西),当然不应该丢掉它。否则例如一个人在中国发了一个帖子,又去美国发了一个帖子,那么如果服务器不存时区,只依赖客户端时区的话,就可能会发现两个帖子是同一时间,甚至后一个帖子的时间比前一个更早。

    至于客户端和服务器端之间的 API ,我认为双方都要有接受任何时区的时间的能力,现在绝大部分的语言都提供了这样的能力。发送的时候,客户端按照本地时区发送(以便把时区这个信息传递给服务器);服务器在发送时,则以数据库中记录的,客户端的时区来发送。
    cxbig
        54
    cxbig  
       2016-07-22 15:40:43 +08:00
    我司服务器时间和存数据库的各种时间一律用 UTC ,前端根据实际业务时区做转换输出输入。
    mgcnrx11
        55
    mgcnrx11  
       2016-07-22 17:17:08 +08:00
    @julyclyde 请教一下,看了一下 wiki 上 UTC 的介绍, UTC 是会在适当的时候增加闰秒来保持与 GMT 不差超过 1 秒的。那么,对于要做日期转换的工具库(类)来说,岂不是需要针对未来未知的某个闰秒做更新,才能正确转换时间?否则闰秒会造成转换的时候多了一秒这种情况吧?
    dorentus
        56
    dorentus  
       2016-07-22 18:46:53 +08:00 via iPhone
    你的操作系统底层都是用 unix epoch 或者类似 unix epoch 的方式表达时间的。
    owt5008137
        57
    owt5008137  
       2016-07-22 19:08:25 +08:00 via Android
    @myyou 现在 unix 时间戳基本上都用 int64 保存了,除非你强制往 int32 转。所以反正你活着的时候肯定够用了
    janxin
        58
    janxin  
       2016-07-22 20:01:23 +08:00
    UNIX 时间戳用 int64 ,够用了啊
    julyclyde
        59
    julyclyde  
       2016-07-22 22:56:23 +08:00
    @mgcnrx11 首先你要知道 UTC 是根本,闰秒是在 UTC 里做的;到各个行政时区,是 59 秒之后 60 秒,还是 59 秒之后又一个 59 秒,或者做夏令时处理,那是各国政府自己的事了。保存、传输都用 UTC ,直到最后展现的时候才用行政时区,可以做到损失的最小化
    julyclyde
        60
    julyclyde  
       2016-07-22 23:05:44 +08:00
    https://access.redhat.com/articles/1187353
    http://www.cnbeta.com/articles/437413.htm
    https://mm.icann.org/pipermail/tz-announce/2015-August/000033.html
    Changes affecting future time stamps

    North Korea switches to +0830 on 2015-08-15. (Thanks to Steffen Thorsen.)
    The abbreviation remains "KST".
    banxi1988
        61
    banxi1988  
       2016-07-23 11:42:06 +08:00
    首先,支持 UTC, 但是主要的是要统一啊,
    印象中,以前 LeanCloud 是 +8 时间,后来改成统一 UTC 时间了.
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3555 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 04:48 · PVG 12:48 · LAX 21:48 · JFK 00:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.