Nodejs 获取北京时间

Nodejs 获取北京时间

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

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

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


22 回复

moment().utcOffset(8);


直接把服务器改成+8 的时间即可

let date = new Date();
date.setHours(date.getHours() + 8);

多时区之间通信,一般用 ISO 8601 的 UTC 时间,像这样的格式:2018-02-08T12:51:00.936Z

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

JavaScript 里把一个 date 对象转换成 ISO 8601 的时间,一个 toISOString() 就行了,然后把一个 ISO 8601 的时间转换成 date 对象的时候也会自动作用当前机器的时区。

我一般这么干
JavaScript<br>const csttime = Date.now() + 8 * 60 * 60 * 1000<br>const cst = new Date(csttime)<br>const cstHour = cst.getUTCHours()<br>const cstMin = cst.getUTCMinutes()<br>

不是用 gmt,而是用 utc
这俩的法律效力不同

moment.js

我说的就是用 UTC 啊,我提 GMT 只是用来解释 toISOString() 的时间是 GMT+0 时区的时间为基准的时间,ISO 8601 格式最后结尾的 Z 也是代表 Zero 也就是 0 时区。

另外 JavaScript 本身的 toGMTString() 和 toUTCString() 输出结果是一毛一样的,而且还带 GMT,可见 toUTCString 这个名字里的 UTC 根本就不是真正的 UTC,应该用 toISOString() 才像是有 UTC 的样子。当然服务器通过网络同步的时间也是不够精确的,更精确的时间应该通过 GPS 设备从卫星去获得。

GMT 自己会变的,有夏令时

首先,直接搞 GMT/UTC+8 就完了……
其次,GMT/UTC 法律效力不同是什么鬼,这两个理论上只有精准度差别,实际用起来谁管你

始终使用 ISO8601 的 UTC 格式是个好习惯,永远不要用本地时间。
Js 的日期型在微观上是 UTC,与时区无关。
另外现在没有 GMT,只有 UTC。

无论服务器地理位置在哪里,时区设置成什么,JS 获得的日期都是 UTC。

即,假设美国和中国各有一台服务器,且时钟绝对准确,且网络没有延迟。那么即使两台服务器的时区不同,同一时间用 new Date() 获得的日期时间是完全相同的。

#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,明显是不对的。

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

不知是否有更好的办法?

let date = new Date(‘2018-03-07T13:00+08:00’)
这样可以生成一个 UTC 为 2018-03-07T05:00:00Z 的日期。不论是储存,还是提取,都不要去转换时区,因为现在几乎所有语言、数据库,都是用 UTC 来保存时间的。你可以直接把这个日期保存到数据库(我这里用 MongoDB )。

服务器的时区只是一个用来决定如何显示时间的属性,任何服务器的时钟都是 UTC,所以:
永!远!不!要!转!换!时!区!

#17 感谢大佬耐心解答,受教了~

老哥 let now = Date.now();
let date = new Date(now)
把这个 date 存到数据库,那我取出来的展示的时候怎么处理下呢 怎么自动的加下当前时区 比如东八区 自动加八小时


我通常是在前端页面里面有日期的地方放一个 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<br>function localTime () {<br> let _ = Math.floor<br> let pad = n =&gt; ('00' + n).slice(-2)<br> let localize = () =&gt; {<br> let $times = document.getElementsByTagName('time')<br> for (let i = 0; i &lt; $times.length; i++) { // also for in / for of loop<br> let $time = $times[i]<br> let d = new Date($time.getAttribute('datetime')), // parse ISO 8601<br> dYea = d.getFullYear(),<br> dMon = d.getMonth() + 1, // getMonth returns (0-11)<br> dDay = d.getDate(), // NOT getDay<br> dHou = d.getHours(),<br> dMin = d.getMinutes(),<br> dSec = d.getSeconds()<br> let n = new Date(),<br> nYea = n.getFullYear(),<br> nMon = n.getMonth() + 1,<br> nDay = n.getDate(),<br> nHou = n.getHours(),<br> nMin = n.getMinutes(),<br> nSec = n.getSeconds()<br> let l = null<br> if (nYea - dYea === 0 &amp;&amp; nMon - dMon === 0) {<br> let dayDiff = nDay - dDay<br> if (dayDiff === 0) {<br> let s = (<br> (nHou * 3600 + nMin * 60 + nSec) -<br> (dHou * 3600 + dMin * 60 + dSec)<br> )<br> if (s === 0)<br> l = '现在'<br> else if (s &lt; 60 &amp;&amp; s &gt; 0)<br> l = s + ' 秒前'<br> else if (s &lt; 3600 &amp;&amp; s &gt;= 60)<br> l = _(s / 60) + ' 分钟前'<br> else if (s &gt;= 3600)<br> l = _(s / 3600) + ' 小时前'<br> }<br> else if (dayDiff === 1)<br> l = '昨天 ' + pad(dHou) + ':' + pad(dMin)<br> else if (dayDiff === 2)<br> l = '前天 ' + pad(dHou) + ':' + pad(dMin)<br> }<br> if (l === null)<br> l = (<br> dYea + ' 年 ' + dMon + ' 月 ' + dDay + ' 日 ' +<br> pad(dHou) + ':' + pad(dMin)<br> )<br> $time.innerText = l<br> }<br> }<br> setInterval(localize, 1000)<br> localize()<br>}<br>

看到这个不解:let now = Date.now(); let date = new Date(now) ?直接 let now = new Date() 就可以了啊。Date 类的实例默认就是当前时间。

在 Node.js 中获取北京时间(CST,即中国标准时间,UTC+8)可以通过多种方法实现。最简单和直接的方法是使用内置的 Date 对象,因为 JavaScript 的 Date 对象默认是基于 UTC 的,但你可以通过一些操作将其转换为北京时间。

以下是一个简单的示例代码,展示了如何获取并打印当前的北京时间:

// 获取当前UTC时间
const now = new Date();

// 获取UTC时间的小时数
const utcHours = now.getUTCHours();

// 将UTC时间转换为北京时间(UTC+8)
const beijingHours = utcHours + 8;

// 处理跨天的情况(例如,UTC时间为23:00时,北京时间为次日07:00)
const beijingDate = new Date(now);
if (beijingHours >= 24) {
    beijingDate.setUTCHours(utcHours + 8 - 24);
} else {
    beijingDate.setUTCHours(beijingHours);
}

// 格式化输出北京时间
const beijingTimeString = beijingDate.toLocaleString('zh-CN', {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit'
});

console.log(`当前北京时间是: ${beijingTimeString}`);

此外,你也可以使用一些第三方库如 moment-timezone 来更简便地处理时区转换。以下是一个使用 moment-timezone 的示例:

const moment = require('moment-timezone');
const beijingTime = moment.tz('Asia/Shanghai').format('HH:mm:ss');
console.log(`当前北京时间是: ${beijingTime}`);

这两种方法都可以有效地获取当前的北京时间。

回到顶部