最近在弄需求的接口的时候,添加数据需要比对时间
如果添加的该条数据的时间区间在数据库中已经有重叠的区间,那么就不允许添加,但是在添加的数据的时候,明明添加并没有这个区间,但是一直提示已经存在数据
在确认比较的条件没有问题之后,才发现是 时间转换的问题!!
本地时间和 服务器时间相差了8个小时,具体是服务器时间 比 本地时间 早了8个小时
也就是 本地时间是 16:00,服务器时间是 8:00,查了好久,所以值得记录一下,完善一下时间的知识点
回到正题,本文会分成两个部分
1、原因
2、解决办法
1.原因
简单说,因为本地时区和服务器的时区不一样,差了8个小时导致
1什么是时区
由于地球很大,每个地方经历的昼夜都不一样。
而大家又习惯于时间和昼夜的对应关系,比如正午就是12点
但是如果全球用一个时间,就会完成有一些国家的正午12点是大半夜。这样就不符合人们的作息习惯了。
从而分出了时区的概念,让时间相对统一,而不是绝对统一
2时间分了什么时区
在1884年的华盛顿国际会议上,把全球划分为了24个时区,零时区,东12个区,西12个区,每个区相差1个小时
一般概念是这么按时区去计算时间,但是实际上,有的国家国土通常横跨几个时区,所以最后是以国家为纬度计算,比如大中国横跨5个时区,还是只共用一个时区。即东8区,北京时间
其中有个零时区,他的位置在英国(格林尼治天文台旧址)
3时区的时间标准
因为时间是相对统一的,所有时区的时间都是相对于零时区得出的,那么就需要一个格式去表示
时间标准 有两种, UTC 和 GMT
UTC 是我们现在用的时间标准,GMT是老的时间计量标准。
UTC 是根据原子钟来计算时间,
GMT是英国格林尼治天文台观测太阳每天经过它的时间就是中午12点
所以能看到GMT根据地球自转来计算时间,肯定有误差,并且自转时间不可控,可能快一点可能慢一点,所以我们会采取更加精准的UTC
UTC主要是各个时区相对于零时区加上 时间偏移量
UTC偏移量的表示形式为:±[hh]:[mm]、±[hh][mm]或者±[hh]
比如北京时间比协调世界时(UTC)早八小时,那么表示为:UTC+8
我们的时间 = 零时区时间 + 8个小时
4时间格式
时间格式有两种,RFC-2822标准格式 和 ISO-8601标准格式
RFC-2822标准格式
比如
Tue Jul 06 2021 16:31:45 GMT+0800
GMT+0800 表示 GMT 时间 +8 小时,即是东八区
JavaScript 使用 new Date 返回的也是这个格式
ISO-8601标准格式
比如
2021-07-06T16:31:45+08:00
T 后面表示的是 时分秒,+08:00 也是表示 东八区的意思
如果是零时区,则可以表示成
2021-07-04T16:33:23.400Z
其中 Z 就表示这是 UTC 时间
5怎么知道是什么时区
在JavaScript中当然提供了一个对象 Intl,他可以提供精确的日期格式化,数字格式化 等
今天我们只用他的一个api获取时区
Intl.DateTimeFormat().resolvedOptions().timeZone
在控制台执行一下,可以看到输出
Asia/Shanghai
咦,为什么是上海,不应该是北京吗
原因是1949年以前,中国一共分了5个时区,以哈尔滨 ( Asia/Harbin)、上海(Asia/Shanghai)、重庆(Asia/Chongqing)、乌鲁木齐(Asia/Urumqi)、喀什(Asia/Kashgar)为代表——分别是:长白时区GMT+8:30、中原标准时区 GMT+8、陇蜀时区GMT+7、新藏时区GMT+6和昆仑时区GMT+5:30。它是1912年北京观象台制订,后由内政部批准过。而且从国际标准本身的角度来看,北京和上海处于同一时区,只能保留一个。而作为时区代表上海已经存在,并且足够具有代表性,因此其维护者没有足够的动力做出改变。所以目前还没有Asia/Beijing。
然后我们在服务器打印一下时区,则显示
UTC
好家伙,果然是时区不对,所以时区不同,不能直接计算的
6时间怎么转换时区
比如我当前有一个北京时间,我怎么知道他对应的美国时间是多少呢
同一个时间戳在 不同时区 对应的 时间是不一样的
所以我们需要转换一下
Date.prototype.toLocaleString( [locales [, options] ] )
该方法可以根据你设定的 语言 和 时区 来给你返回对应的 时间
如果是你什么都不传,默认就是你所在的时区
如果你是我大中国时间,想看看对应的美国时间是多少,可以这么设置 timeZone
new Date().toLocaleString("chinese",{
hour12:false,
timeZone:"America/New_York"
})
如下图,可以看到差了12 个小时
相关的时区有
"Asia/Shanghai" ,"Asia/Kolkata", "America/New_York" 等
更多时区可以看
https://www.iana.org/time-zones
2.解决办法
就是要保证 本地 和 服务器通信的 时间 是同一个时区
1、前后端时间字段直接使用 时间戳 ,数据库存时间戳
2、使用同一个时区进行转换
1前端传时间戳,数据库也存时间戳
最简单的处理方式,不用任何转换
因为时间戳都是 前端传的,所以可以保证都是都是同一个时区,可以直接进行计算(如果你应用是国际化的,就不行了,还是要转)
2使用同一个时区进行转换
但是我这次的问题是,前端传的是时间戳,而数据库存的是格式化后的时间
然后我把数据库的数据查出来转成了时间戳 之后,和 前端传的时间戳 进行比较
这个时候才有这个大问题因为 服务器是 UTC 时区,如果我用这个 格式化的时间 转成 时间戳
得到的时间戳 比 实际对应的时间戳 大 8h
因为原本
Local Time= 2021-05-27 14:00:00
Server Time= Local Time - 8 (本地是 东八区,server 是 UTC,所以本地时间比 server 多八个小时)
如果本地时间当做服务器时间直接转换
Server Time= 2021-05-27 14:00:00
那么相当于本地时间比原来传的多了8h
Local Time= ServerTime + 8h = 2021-05-27 22:00:00
如果这样进行比较,肯定是不对的了,所以取出来的时间转成 时间戳必须要设置时区
具体我使用了 dayjs,如下
const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
const timezone = require('dayjs/plugin/timezone');
dayjs.extend(utc);
dayjs.extend(timezone);
function getSvrTimestampTZ(datestring) {
return dayjs.tz(datestring, "Asia/Shanghai").valueOf()
}
然后测试一下
// 服务器运行
getSvrTimestampTZ("2021-7-6 21:00:00") // 1625576400000
// 本地运行
new Date("2021-7-6 21:00:00").getTime() // 1625576400000
可以看到,同一个时间转换得到的时间戳是一样的了,说明现在就对了
都是 1625576400000
如果服务器不设置时区,那么直接转得到的时间戳是 1625605200000
1625605200000 - 1625576400000
= 28800000
= 8 * 60*60*1000
这个问题也是因为对于时间的 概念模糊造成了,排查了很久,不过也算是填了自己知识的一个坑
最后
鉴于本人能力有限,难免会有疏漏错误的地方,请大家多多包涵, 如果有任何描述不当的地方,欢迎后台联系本人
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有