Nodejs 获取北京时间 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
yifeng1212

Nodejs 获取北京时间

  •  
  •   yifeng1212 2018 年 2 月 8 日 12155 次点击
    这是一个创建于 2997 天前的主题,其中的信息可能已经有所发展或是发生改变。

    当服务器不在东八区时,处理时区问题有时可能比较烦, 特别是当客户端是北京时间,跟服务器有时差时。

    因为自己项目遇到了类似的问题,自己写了个包来解决这问题。见~

    install

    yarn add china-time 

    if you prefer npm:

    npm i china-time 

    usage

    const chinaTime = require('china-time'); console.log(chinaTime()); // 2018-02-07T04:38:00.000Z console.log(chinaTime().getTime()); // 1517978280000 console.log(chinaTime('YYYY-MM-DD HH:mm:ss')); // 2018-02-07 13:08:17 console.log(chinaTime('YY/MM/DD HH:mm')); // 18/02/07 13:08 console.log(chinaTime('YYYY MM DD')); // 2018 02 07 
    21 条回复    2018-06-04 13:59:13 +08:00
    zhengxiaowai
        1
    zhengxiaowai  
       2018 年 2 月 8 日   1
    moment().utcOffset(8);
    i730
        2
    i730  
       2018 年 2 月 8 日 via Android
    直接把服务器改成+8 的时间即可
    slion
        3
    slion  
       2018 年 2 月 8 日   2
    let date = new Date();
    date.setHours(date.getHours() + 8);
    mdluo
        4
    mdluo  
       2018 年 2 月 8 日   2
    多时区之间通信,一般用 ISO 8601 的 UTC 时间,像这样的格式:2018-02-08T12:51:00.936Z

    统一用这个时间对应的 GMT +0 (格林威治时间)的时间来存储和传输,AWS 和 Azure 都是这么做的。

    Javascript 里把一个 date 对象转换成 ISO 8601 的时间,一个 toISOString() 就行了,然后把一个 ISO 8601 的时间转换成 date 对象的时候也会自动作用当前机器的时区。
    lzvezr
        5
    lzvezr  
       2018 年 2 月 8 日 via iPhone
    我一般这么干
    ```Javascript
    const csttime = Date.now() + 8 * 60 * 60 * 1000
    const cst = new Date(csttime)
    const cstHour = cst.getUTCHours()
    const cstMin = cst.getUTCMinutes()
    ```
    julyclyde
        6
    julyclyde  
       2018 年 2 月 9 日
    @mdluo 不是用 gmt,而是用 utc
    这俩的法律效力不同
    toono
        7
    toono  
       2018 年 2 月 9 日
    moment.js
    mdluo
        8
    mdluo  
       2018 年 2 月 9 日
    @julyclyde 我说的就是用 UTC 啊,我提 GMT 只是用来解释 toISOString() 的时间是 GMT+0 时区的时间为基准的时间,ISO 8601 格式最后结尾的 Z 也是代表 Zero 也就是 0 时区。

    另外 Javascript 本身的 toGMTString() 和 toUTCString() 输出结果是一毛一样的,而且还带 GMT,可见 toUTCString 这个名字里的 UTC 根本就不是真正的 UTC,应该用 toISOString() 才像是有 UTC 的样子。当然服务器通过网络同步的时间也是不够精确的,更精确的时间应该通过 GPS 设备从卫星去获得。
    julyclyde
        9
    julyclyde  
       2018 年 2 月 9 日
    @mdluo GMT 自己会变的,有夏令时
    mdluo
        10
    mdluo  
       2018 年 2 月 9 日   1
    mingl0280
        11
    mingl0280  
       2018 年 2 月 9 日
    首先,直接搞 GMT/UTC+8 就完了……
    其次,GMT/UTC 法律效力不同是什么鬼,这两个理论上只有精准度差别,实际用起来谁管你
    e8c47a0d
        12
    e8c47a0d  
       2018 年 3 月 7 日
    始终使用 ISO8601 的 UTC 格式是个好习惯,永远不要用本地时间。
    Js 的日期型在微观上是 UTC,与时区无关。
    另外现在没有 GMT,只有 UTC。
    e8c47a0d
        13
    e8c47a0d  
       2018 年 3 月 7 日
    无论服务器地理位置在哪里,时区设置成什么,JS 获得的日期都是 UTC。
    e8c47a0d
        14
    e8c47a0d  
       2018 年 3 月 7 日
    即,假设美国和中国各有一台服务器,且时钟绝对准确,且网络没有延迟。那么即使两台服务器的时区不同,同一时间用 new Date() 获得的日期时间是完全相同的。
    yifeng1212
        15
    yifeng1212  
    OP
       2018 年 3 月 7 日
    @e8c47a0d #14
    嗯,谢谢解答。

    其实我当时遇到的问题是这样的,我在前端页面上设置了 var str = "2018-03-07 13:00"这个时间(前端是北京时间),然后用 new Date(str) 的时间存到了数据库。所以遇到了问题。

    因为我希望在 3.7 号的 13:00 这个时间做点什么,所以相当于在服务器时间为 2018-03-07 05:00 (假设差 8 个小时)的时候触发。但是上面用 new Date(str) 存的又是服务器的 13:00,明显是不对的。

    所以,我才需要做个转换。

    不知是否有更好的办法?
    e8c47a0d
        16
    e8c47a0d  
       2018 年 3 月 7 日   1
    let date = new Date('2018-03-07T13:00+08:00')
    这样可以生成一个 UTC 为 2018-03-07T05:00:00Z 的日期。不论是储存,还是提取,都不要去转换时区,因为现在几乎所有语言、数据库,都是用 UTC 来保存时间的。你可以直接把这个日期保存到数据库(我这里用 MongoDB )。
    e8c47a0d
        17
    e8c47a0d  
       2018 年 3 月 7 日
    服务器的时区只是一个用来决定如何显示时间的属性,任何服务器的时钟都是 UTC,所以:
    永!远!不!要!转!换!时!区!
    yifeng1212
        18
    yifeng1212  
    OP
       2018 年 3 月 7 日
    @e8c47a0d #17 感谢大佬耐心解答,受教了~
    dany813
        19
    dany813  
       2018 年 3 月 29 日
    @e8c47a0d 老哥 let now = Date.now();
    let date = new Date(now)
    把这个 date 存到数据库,那我取出来的展示的时候怎么处理下呢 怎么自动的加下当前时区 比如东八区 自动加八小时
    e8c47a0d
        20
    e8c47a0d  
       2018 年 6 月 4 日
    @dany813
    我通常是在前端页面里面有日期的地方放一个 time 标签,然后给它一个 datetime 属性,设置为 ISO8601 的格式。
    <time datetime="2018-06-04T04:18:45Z">2018-06-04T04:18:45Z</time>
    Safari 的 JS 引擎不能很好的理解其他日期格式,所以强烈建议 datetime 使用国际标准 ISO8601 格式
    node.js 中,用 日期.toISOString() 可以把日期做成 ISO8601 格式的字符串( UTC+0 )
    php 中,用 date('c', 1528085925) 可以把{以秒为单位的时间戳}整数做成 ISO8601 格式的字符串( UTC+0 )

    以下代码放在前端,网页 onload 的时候调用一次 localTime() 即可,localTime 这个函数可以把页面中所有 time 标签找出,然后设置定时器,每 n 秒根据当前浏览器的时区和时间,去对比 time 标签的 datetime 属性,自动算出时差并以本地时间输出、更新标签的内容。(我知道回复不能用 markdown 不过还是用了,因为用 switch 很乱所以都换成了 if else )

    比如:3 分前、4 小时前、昨天 16:20、2017 年 12 月 31 日 10:09
    注意闰秒在这里被无视,但问题不大。

    ```js
    function localTime () {
    let _ = Math.floor
    let pad = n => ('00' + n).slice(-2)
    let localize = () => {
    let $times = document.getElementsByTagName('time')
    for (let i = 0; i < $times.length; i++) { // also for in / for of loop
    let $time = $times[i]
    let d = new Date($time.getAttribute('datetime')), // parse ISO 8601
    dYea = d.getFullYear(),
    dMon = d.getMonth() + 1, // getMonth returns (0-11)
    dDay = d.getDate(), // NOT getDay
    dHou = d.getHours(),
    dMin = d.getMinutes(),
    dSec = d.getSeconds()
    let n = new Date(),
    nYea = n.getFullYear(),
    nMon = n.getMonth() + 1,
    nDay = n.getDate(),
    nHou = n.getHours(),
    nMin = n.getMinutes(),
    nSec = n.getSeconds()
    let l = null
    if (nYea - dYea === 0 && nMon - dMon === 0) {
    let dayDiff = nDay - dDay
    if (dayDiff === 0) {
    let s = (
    (nHou * 3600 + nMin * 60 + nSec) -
    (dHou * 3600 + dMin * 60 + dSec)
    )
    if (s === 0)
    l = '现在'
    else if (s < 60 && s > 0)
    l = s + '秒前'
    else if (s < 3600 && s >= 60)
    l = _(s / 60) + '分钟前'
    else if (s >= 3600)
    l = _(s / 3600) + '小时前'
    }
    else if (dayDiff === 1)
    l = '昨天 ' + pad(dHou) + ':' + pad(dMin)
    else if (dayDiff === 2)
    l = '前天 ' + pad(dHou) + ':' + pad(dMin)
    }
    if (l === null)
    l = (
    dYea + '年' + dMon + '月' + dDay + '日 ' +
    pad(dHou) + ':' + pad(dMin)
    )
    $time.innerText = l
    }
    }
    setInterval(localize, 1000)
    localize()
    }
    ```
    e8c47a0d
        21
    e8c47a0d  
       2018 年 6 月 4 日
    @dany813 看到这个不解:let now = Date.now(); let date = new Date(now) ?直接 let now = new Date() 就可以了啊。Date 类的实例默认就是当前时间。
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2799 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 64ms UTC 11:39 PVG 19:39 LAX 04:39 JFK 07:39
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86