Nodejs 获取北京时间

2018-02-08 18:58:37 +08:00
 yifeng1212

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

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

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
11388 次点击
所在节点    Node.js
21 条回复
zhengxiaowai
2018-02-08 19:11:57 +08:00
moment().utcOffset(8);
i730
2018-02-08 19:39:41 +08:00
直接把服务器改成+8 的时间即可
slion
2018-02-08 20:28:26 +08:00
let date = new Date();
date.setHours(date.getHours() + 8);
mdluo
2018-02-08 20:55:40 +08:00
多时区之间通信,一般用 ISO 8601 的 UTC 时间,像这样的格式:2018-02-08T12:51:00.936Z

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

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

另外 JavaScript 本身的 toGMTString() 和 toUTCString() 输出结果是一毛一样的,而且还带 GMT,可见 toUTCString 这个名字里的 UTC 根本就不是真正的 UTC,应该用 toISOString() 才像是有 UTC 的样子。当然服务器通过网络同步的时间也是不够精确的,更精确的时间应该通过 GPS 设备从卫星去获得。
julyclyde
2018-02-09 14:18:26 +08:00
@mdluo GMT 自己会变的,有夏令时
mdluo
2018-02-09 14:34:30 +08:00
mingl0280
2018-02-09 14:57:04 +08:00
首先,直接搞 GMT/UTC+8 就完了……
其次,GMT/UTC 法律效力不同是什么鬼,这两个理论上只有精准度差别,实际用起来谁管你
e8c47a0d
2018-03-07 14:47:06 +08:00
始终使用 ISO8601 的 UTC 格式是个好习惯,永远不要用本地时间。
Js 的日期型在微观上是 UTC,与时区无关。
另外现在没有 GMT,只有 UTC。
e8c47a0d
2018-03-07 14:50:18 +08:00
无论服务器地理位置在哪里,时区设置成什么,JS 获得的日期都是 UTC。
e8c47a0d
2018-03-07 15:01:51 +08:00
即,假设美国和中国各有一台服务器,且时钟绝对准确,且网络没有延迟。那么即使两台服务器的时区不同,同一时间用 new Date() 获得的日期时间是完全相同的。
yifeng1212
2018-03-07 15:17:02 +08:00
@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
2018-03-07 15:52:06 +08:00
let date = new Date('2018-03-07T13:00+08:00')
这样可以生成一个 UTC 为 2018-03-07T05:00:00Z 的日期。不论是储存,还是提取,都不要去转换时区,因为现在几乎所有语言、数据库,都是用 UTC 来保存时间的。你可以直接把这个日期保存到数据库(我这里用 MongoDB )。
e8c47a0d
2018-03-07 15:55:46 +08:00
服务器的时区只是一个用来决定如何显示时间的属性,任何服务器的时钟都是 UTC,所以:
永!远!不!要!转!换!时!区!
yifeng1212
2018-03-07 16:00:14 +08:00
@e8c47a0d #17 感谢大佬耐心解答,受教了~
dany813
2018-03-29 12:01:26 +08:00
@e8c47a0d 老哥 let now = Date.now();
let date = new Date(now)
把这个 date 存到数据库,那我取出来的展示的时候怎么处理下呢 怎么自动的加下当前时区 比如东八区 自动加八小时
e8c47a0d
2018-06-04 12:32:55 +08:00
@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()
}
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/429546

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX