当服务器不在东八区时,处理时区问题有时可能比较烦, 特别是当客户端是北京时间,跟服务器有时差时。
因为自己项目遇到了类似的问题,自己写了个包来解决这问题。见~
yarn add china-time
if you prefer npm:
npm i china-time
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
1
zhengxiaowai 2018-02-08 19:11:57 +08:00 1
moment().utcOffset(8);
|
2
i730 2018-02-08 19:39:41 +08:00 via Android
直接把服务器改成+8 的时间即可
|
3
slion 2018-02-08 20:28:26 +08:00 2
let date = new Date();
date.setHours(date.getHours() + 8); |
4
mdluo 2018-02-08 20:55:40 +08:00 2
多时区之间通信,一般用 ISO 8601 的 UTC 时间,像这样的格式:2018-02-08T12:51:00.936Z
统一用这个时间对应的 GMT +0 (格林威治时间)的时间来存储和传输,AWS 和 Azure 都是这么做的。 JavaScript 里把一个 date 对象转换成 ISO 8601 的时间,一个 toISOString() 就行了,然后把一个 ISO 8601 的时间转换成 date 对象的时候也会自动作用当前机器的时区。 |
5
lzvezr 2018-02-08 20:57:31 +08:00 via iPhone
我一般这么干
```JavaScript const csttime = Date.now() + 8 * 60 * 60 * 1000 const cst = new Date(csttime) const cstHour = cst.getUTCHours() const cstMin = cst.getUTCMinutes() ``` |
7
toono 2018-02-09 08:39:37 +08:00
moment.js
|
8
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 设备从卫星去获得。 |
10
mdluo 2018-02-09 14:34:30 +08:00 1
@julyclyde #9
GMT 和 UTC 一样都没有夏令时,参考: https://www.timeanddate.com/time/gmt-utc-time.html,有夏令时的是某个地区的本地时间,比如英国的 BST |
11
mingl0280 2018-02-09 14:57:04 +08:00
首先,直接搞 GMT/UTC+8 就完了……
其次,GMT/UTC 法律效力不同是什么鬼,这两个理论上只有精准度差别,实际用起来谁管你 |
12
e8c47a0d 2018-03-07 14:47:06 +08:00
始终使用 ISO8601 的 UTC 格式是个好习惯,永远不要用本地时间。
Js 的日期型在微观上是 UTC,与时区无关。 另外现在没有 GMT,只有 UTC。 |
13
e8c47a0d 2018-03-07 14:50:18 +08:00
无论服务器地理位置在哪里,时区设置成什么,JS 获得的日期都是 UTC。
|
14
e8c47a0d 2018-03-07 15:01:51 +08:00
即,假设美国和中国各有一台服务器,且时钟绝对准确,且网络没有延迟。那么即使两台服务器的时区不同,同一时间用 new Date() 获得的日期时间是完全相同的。
|
15
yifeng1212 OP @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,明显是不对的。 所以,我才需要做个转换。 不知是否有更好的办法? |
16
e8c47a0d 2018-03-07 15:52:06 +08:00 1
let date = new Date('2018-03-07T13:00+08:00')
这样可以生成一个 UTC 为 2018-03-07T05:00:00Z 的日期。不论是储存,还是提取,都不要去转换时区,因为现在几乎所有语言、数据库,都是用 UTC 来保存时间的。你可以直接把这个日期保存到数据库(我这里用 MongoDB )。 |
17
e8c47a0d 2018-03-07 15:55:46 +08:00
服务器的时区只是一个用来决定如何显示时间的属性,任何服务器的时钟都是 UTC,所以:
永!远!不!要!转!换!时!区! |
18
yifeng1212 OP @e8c47a0d #17 感谢大佬耐心解答,受教了~
|
19
dany813 2018-03-29 12:01:26 +08:00
@e8c47a0d 老哥 let now = Date.now();
let date = new Date(now) 把这个 date 存到数据库,那我取出来的展示的时候怎么处理下呢 怎么自动的加下当前时区 比如东八区 自动加八小时 |
20
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() } ``` |