客户端、服务器、数据库之间的时区转换

简介: 做国外的项目经常会遇到时区转换的问题,这里简单针对遇到的时区问题做个记录,也希望对大家有所帮助,少走弯路。(本文设计开发语言为java)

背景


做国外的项目经常会遇到时区转换的问题,这里简单针对遇到的时区问题做个记录,也希望对大家有所帮助,少走弯路。(本文设计开发语言为java)


时区的概念


先说下时区的概念 初中地理好的同学应该还记得,由于地球不停地自西向东旋转,使得昼夜半球和晨昏线也不断自东向西移动。


image.gif


为了照顾到各地区的使用方便,又使其他地方的人容易将本地的时间换算到别的地方时间上去。有关国际会议决定将地球表面按经线从东到西,划成一个个区域(时区),全球一共分为24个时区(东12区+西12区),相邻时区时间相差1个小时。


规定英国(格林尼治天文台旧址)所在区域为零时区,往东分别为东1区、东2区……东11区、东12区,往西分别为西1区、西2区……西11区、西12区,东12区和西12区重合(所属同一个时区)。


16.png


我们国家由于地域广袤辽阔,横跨了5个时区(东5、东6、东7、东8、东9),但建国以后,全国统一采用首都北京所处的东8区的时间。


虽然全世界一共划分了24个时区,同一个时间点,每个时区钟表上显示的时间各不同,但是它们仅仅是同一时刻在不同地区展示的形式,它们代表的仍然是一个时刻/瞬间。


跑题结束,开始正文。



跨境电商下单场景涉及的时区转换


先以跨境电商系统中的下单场景举个栗子,如果该电商系统的【数据库服务器】部署在英国伦敦,【应用服务器】部署在德国柏林,北京时间2020-06-01 10:00:00 有位北京的用户在通过浏览器在该网站上买了一个儿童节礼物。


这个过程就涉及到了时区转换的问题,一般刚给电脑安装操作系统的时候,都会让选择电脑所在时区,系统就是以时区来显示时间的。上面下单的例子涉及到三个设备:客户端(电脑浏览器/手机App)、网站web服务器、网站数据库服务器,都配置了对应的时区,假设这三种设备配置的时区就是所在地区的时区。


在【客户端→web服务器】、【web服务器→数据库】、【数据库→web服务器】、【web服务器→客户端】这几个过程都涉及到了时区的转换。如果不考虑时区转换,北京的用户在2020-06-01 10:00:00下单,web服务器处理的时候认为订单时间是在2020-06-01 03:00:00,然后传给数据库的订单时间也是2020-06-01 03:00:00,数据库保存的时候会保存成2020-06-01 03:00:00。当北京的用户查询订单的时候,数据库返回给应用服务器的订单时间为2020-06-01 03:00:00,最后应用服务器返回给用户的订单时间(用户看到的时间)也就是2020-06-01 03:00:00,如下图:



0.png


但实际上对用户来说是在2020-06-01 10:00:00下的单,应该是这样:

1.png


要解决这个问题,可以通过在客户端和web服务器、web服务器和数据库两两交互的时候添加”时区协议“来自动转换时区。


假如服务端应用是用SpringBoot实现的,可以在配置文件中配置

spring.jackson.time-zone = Asia/Shanghai(注意没有Asia/Beijing哈),这样应用服务器接收到客户端传来的时间后会把这个时间当成是东8区的时间转换成服务器所在时区的时间,也就是会把2020-06-01 10:00:00(UTC+8)转换成2020-06-01 03:00:00(UTC+1)。同样当客户端查询时,服务端会把当前时区的时间2020-06-01 03:00:00(UTC+1)转换成客户端所在时区的时间2020-06-01 10:00:00(UTC+8)。


假如服务端是用JDBC和MySQL交互,可以在MySQL连接中配置 serverTimezone=Europe/London,这样当应用服务器向Mysql发起持久化数据的请求时,会把服务器所在时区的时间2020-06-01 03:00:00(UTC+1)转换成数据库所在时区的时间2020-06-01 02:00:00(UTC)。同样当应用服务器查询数据的时候,会把数据库所在时区的时间2020-06-01 02:00:00(UTC)转换成服务器所在时区的时间2020-06-01 03:00:00(UTC+1)。


题外话


1、修改时区


一般浏览器的时区是默认获取的当前计算机系统的时区;应用服务器中获取的时区默认为当前计算机系统时区,可以在项目启动时设置(java -Duser.timezone=Asia/Shanghai -jar xxx.jar),也可以通过java.util.TimeZone动态设置;数据库时区默认也是取当前计算机系统时区,可以通过命令set global time_zone修改时区,可也以通过修改配置文件等其他方式。


2、Java中Date的时区无关性


Date类中有个fastTime变量,用来存储当前时刻的毫秒数。Date默认构造函数用System.currentTimeMillis()来为这个毫秒数赋值。


如果此刻在北京、柏林、伦敦同时执行如下语句:Date date = new Date();,那这三个date对象里存的毫秒数是相同的吗?答案是这3个Date里的毫秒数是完全一样的。


确切的说,Date对象里存的是自格林威治时间( GMT)1970年1月1日0点至Date对象所表示时刻所经过的毫秒数。所以,如果某一时刻遍布于世界各地的程序员同时执行new Date语句,这些Date对象所存的毫秒数是完全一样的。也就是说,Date里存放的毫秒数是与时区无关的。


相关文章
|
19天前
|
Python
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
使用Python的socket库实现客户端到服务器端的图片传输,包括客户端和服务器端的代码实现,以及传输结果的展示。
90 3
Socket学习笔记(二):python通过socket实现客户端到服务器端的图片传输
|
19天前
|
JSON 数据格式 Python
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
本文介绍了如何使用Python的socket模块实现客户端到服务器端的文件传输,包括客户端发送文件信息和内容,服务器端接收并保存文件的完整过程。
77 1
Socket学习笔记(一):python通过socket实现客户端到服务器端的文件传输
|
17天前
|
网络协议 Unix Linux
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
一个.NET开源、快速、低延迟的异步套接字服务器和客户端库
|
24天前
|
应用服务中间件 PHP Apache
PbootCMS提示错误信息“未检测到您服务器环境的sqlite3数据库扩展...”
PbootCMS提示错误信息“未检测到您服务器环境的sqlite3数据库扩展...”
|
24天前
|
网络协议 Java API
【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法
【网络】TCP回显服务器和客户端的构造,以及相关bug解决方法
51 2
|
24天前
|
存储 网络协议 Java
【网络】UDP回显服务器和客户端的构造,以及连接流程
【网络】UDP回显服务器和客户端的构造,以及连接流程
48 2
|
13天前
|
安全 区块链 数据库
|
24天前
|
SQL 数据库
SQL-serve数据库不能连接本地服务器的解决方案
SQL-serve数据库不能连接本地服务器的解决方案
92 0
|
25天前
|
存储 网络协议 Unix
docker的底层原理一:客户端-服务器架构
本文详细解释了Docker的客户端-服务器架构,包括常驻后台的Docker守护进程、通过命令行接口发送请求的Docker客户端、以及它们之间通过Unix socket或网络接口进行的通信。
13 0
|
13天前
|
弹性计算 网络安全
阿里云国际OpenAPI多接口快速管理ECS服务器教程
阿里云国际OpenAPI多接口快速管理ECS服务器教程