java 时区 mysql 时区:时区在程序和数据库中的作用及其机制

news/2024/5/18 22:22:46 标签: java, 数据库, jdbc, mysql, 时区

时区在程序和数据库中的作用及其机制

    • 时区(Time Zone)
    • GMT(格林尼治标准时间/世界时)
    • UTC(协调世界时)
      • GMT与UTC
      • 关于北京时间
    • CST(时区缩写)
    • DST(夏时制)
    • unix时间戳(Unix timestamp)
      • 时间戳与北京时间
      • 时区与时间戳单位计算公式(!!!)
    • 时区机制导致的程序中的问题
    • 结尾

在这里插入图片描述

时区(Time Zone)

地球是自西向东自转,东边比西边先看到太阳,东边的时间也比西边的早。东边时刻与西边时刻的差值不仅要以时计,而且还要以分和秒来计算,这给人们带来不便。
为了克服时间上的混乱,1884年在华盛顿召开的一次国际经度会议(又称国际子午线会议)上,规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为中时区(零时区)、东1—12区,西1—12区。每个时区横跨经度15度,时间正好是1小时。最后的东、西第12区各跨经度7.5度,以东、西经180度为界。每个时区的中央经线上的时间就是这个时区内统一采用的时间,称为区时,相邻两个时区的时间相差1小时。
例如,中国东8区的时间总比泰国东7区的时间早1小时,而比日本东9区的时间晚1小时。因此,出国旅行的人,必须随时调整自己的手表,才能和当地时间相一致。凡向西走,每过一个时区,就要把表拨慢1小时(比如2点拨到1点);凡向东走,每过一个时区,就要把表拨快1小时(比如1点拨到2点)。并且规定英国(格林尼治天文台旧址)为本初子午线,即零度经线。

在这里插入图片描述

GMT(格林尼治标准时间/世界时)

以本初子午线的平子夜起算的平太阳时

英文:UT(Universal Time)

GMT:Greenwich Mean Time

格林尼治标准时间。这是以英国格林尼治天文台观测结果得出的时间,这是英国格林尼治当地时间,这个地方的当地时间过去被当成世界标准的时间。

也就是说它是世界计算时间和经度的起点。


1960年以前曾作为基本时间计量系统被广泛应用。由于地球自转速度变化的影响,它不是一种均匀的时间系统。后来世界时被原子时所取代,但在日常生活、天文导航、大地测量和宇宙飞行等方面仍属必需;同时,世界时反映地球自转速率的变化,是地球自转参数之一,仍为天文学和地球物理学的基本资料。

UTC(协调世界时)

协调世界时是以原子时秒长为基础,在时刻上尽量接近于世界时的一种时间计量系统。

这套时间系统被应用于许多互联网和万维网的标准中,例如,网络时间协议就是协调世界时在互联网中使用的一种方式。
在军事中,协调世界时区会使用“Z”来表示。又由于Z在无线电联络中使用“Zulu”作代称,协调世界时也会被称为"Zulu time"。

中国大陆、中国香港、中国澳门、中国台湾、蒙古国、新加坡、马来西亚、菲律宾、西澳大利亚州的时间与UTC的时差均为+8,也就是UTC+8。

如今的标准时间——协调世界时(UTC)——由原子钟提供。 自1924年2月5日开始,格林尼治天文台每隔一小时会向全世界发放调时信息。而UTC是基于标准的GMT提供的准确时间。

国际原子时的准确度为每日数纳秒,而世界时的准确度为每日数毫秒。许多应用部门要求时间系统接近世界时UT,对于这种情况,一种称为协调世界时的折中时标于1972年面世。为确保协调世界时与世界时相差不会超过0.9秒,在有需要的情况下会在协调世界时内加上正或负闰秒。因此协调世界时与国际原子时之间会出现若干整数秒的差别,两者之差逐年积累,便采用跳秒(闰秒)的方法使协调时与世界时的时刻相接近,其差不超过1s。它既保持时间尺度的均匀性,又能近似地反映地球自转的变化。

GMT与UTC

为了方便,在不需要精确到秒的情况下,通常将GMT 和UTC 视作等同。但UTC
更加科学更加精确,它是以原子时为基础,在时刻上尽量接近世界时的一种时间计量系统。它的出现是现代社会对于精确计时的需要。

UT:Universal Time 世界时。根据原子钟计算出来的时间。

UTC:Coordinated Universal Time 协调世界时。因为地球自转越来越慢,每年都会比前一年多出零点几秒,每隔几年协调世界时组织都会给世界时+1秒,让基于原子钟的世界时和基于天文学(人类感知)的格林尼治标准时间相差不至于太大。并将得到的时间称为UTC,这是现在使用的世界标准时间。

协调世界时不与任何地区位置相关,也不代表此刻某地的时间,所以在说明某地时间时要加上时区也就是说GMT并不等于UTC,而是等于UTC+0,只是格林尼治刚好在0时区上。

GMT = UTC+0

关于北京时间

地区:中国 北京 Beijing

时区:UTC/GMT +8.00 (东八区)

北京时间又称中国标准时间。

比格林威治时间(Greenwich Mean Time简称GMT)早8小时。

北京时间是由位于陕西西安的中国国家授时中心计算得出。

在这里插入图片描述

时区时差时间换算/世界时区划分时差查询

CST(时区缩写)

CST可以为如下4个不同的时区的缩写:

  • 美国中部时间:Central Standard Time (USA) UT-6:00
  • 澳大利亚中部时间:Central Standard Time (Australia) UT+9:30
  • 中国标准时间:China Standard Time UT+8:00
  • 古巴标准时间:Cuba Standard Time UT-4:00

DST(夏时制)

夏令时,表示为了节约能源,人为规定时间的意思。也叫夏时制,夏时令(Daylight Saving Time:DST),又称“日光节约时制”和“夏令时间”,在这一制度实行期间所采用的统一时间称为“夏令时间”。一般在天亮早的夏季人为将时间调快一小时,可以使人早起早睡,减少照明量,以充分利用光照资源,从而节约照明用电。各个采纳夏时制的国家具体规定不同。全世界有近110个国家每年要实行夏令时。

unix时间戳(Unix timestamp)

unix时间戳是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。

Unix时间戳(英文为Unix epoch, Unix time, POSIX time 或 Unix timestamp)

是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。 UNIX时间戳的0按照ISO 8601规范为 :1970-01-01T00:00:00Z.

一个小时表示为UNIX时间戳格式为:3600秒;一天表示为UNIX时间戳为86400秒,闰秒不计算。

在大多数的UNIX系统中UNIX时间戳存储为32位,这样会引发2038年问题或Y2038。

中文名unix时间戳外文名Unix epoch, Unix time, POSIX time又 称 Unix timestamp时
间1970年1月1日系 统UNIX内核系统

在这里插入图片描述

时间戳与北京时间

在这里插入图片描述

时区与时间戳单位计算公式(!!!)

在这里插入图片描述

时区机制导致的程序中的问题

对于操作DB在两个不同时区的程序去存取同一个Datetime字段的话会出现大问题:
在同一时刻存入的“当前时间”会不一样。

另外一个情况是:在中国存到数据表里的 2020-12-12 13:39:00 在美国的服务器取出来为2020-12-12 13:39:00 看起来没什么问题;可是实际上美国中部现在时间为 2020-12-11 23:39:00 整整差了14个小时。

如果是一个国际秒杀活动的话在中国你可能已经拿到买的东西了而美国那边还在显示活动开始倒计时!

分布在不同时区的两个程序在传递Date类型数据时也可能会有意外的反应,因为同一个时间在传递另一个时区的Date对象中时会根据接收方的时区做相应的转换。


当前mysql默认的连接会话时区为美国中部
UTC-06:00

在这里插入图片描述

同时使用
一个JDBC连接加了东八区时区参数的客户端和
一个没有加JDBC时区参数的客户端查看同一条记录

其中一个客户端连接加了为上海(东八区)的连接参数
在这里插入图片描述

另一个客户端使用默认时区

得到的结果为:

在这里插入图片描述

可以看出来create_time时差了8个小时

这就是时区不同所造成的影响

但这并不是错误,而是数据在时区机制的序列化的正常反应。

如果再有一个客户端设置为美国中部
在这里插入图片描述
在这里插入图片描述
那就会相差13个小时

java_182">java时区设置

默认取系统的时区
我这里为东八区 CST 也就是 GMT+08:00

java">Date now = new Date();

System.out.println(now.toString())
Sat Dec 12 16:08:48 CST 2020

System.out.println(now.toGMTString())
12 Dec 2020 08:08:48 GMT

修改java程序全局默认的时区

这个会影响到Date类型序列化的日期偏移

java">TimeZone.setDefault(TimeZone.getTimeZone("CST"));
java"># 美国中部时区
TimeZone.setDefault(TimeZone.getTimeZone("GMT-06:00"));

javaDate_212">java程序的Date日期序列化方法

Date类型的toString()不只是把自身属性打印出来这么简单

java">    public String toString() {
        // "EEE MMM dd HH:mm:ss zzz yyyy";
        BaseCalendar.Date date = normalize();
        StringBuilder sb = new StringBuilder(28);
        int index = date.getDayOfWeek();
        if (index == BaseCalendar.SUNDAY) {
            index = 8;
        }
        convertToAbbr(sb, wtb[index]).append(' ');                        // EEE
        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 2).append(' '); // dd

        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');   // HH
        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':'); // mm
        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2).append(' '); // ss
        TimeZone zi = date.getZone();
        if (zi != null) {
            sb.append(zi.getDisplayName(date.isDaylightTime(), TimeZone.SHORT, Locale.US)); // zzz
        } else {
            sb.append("GMT");
        }
        sb.append(' ').append(date.getYear());  // yyyy
        return sb.toString();
    }
java">    @Deprecated
    public String toGMTString() {
        // d MMM yyyy HH:mm:ss 'GMT'
        long t = getTime();
        BaseCalendar cal = getCalendarSystem(t);
        BaseCalendar.Date date =
            (BaseCalendar.Date) cal.getCalendarDate(getTime(), (TimeZone)null);
        StringBuilder sb = new StringBuilder(32);
        CalendarUtils.sprintf0d(sb, date.getDayOfMonth(), 1).append(' '); // d
        convertToAbbr(sb, wtb[date.getMonth() - 1 + 2 + 7]).append(' ');  // MMM
        sb.append(date.getYear()).append(' ');                            // yyyy
        CalendarUtils.sprintf0d(sb, date.getHours(), 2).append(':');      // HH
        CalendarUtils.sprintf0d(sb, date.getMinutes(), 2).append(':');    // mm
        CalendarUtils.sprintf0d(sb, date.getSeconds(), 2);                // ss
        sb.append(" GMT");                                                // ' GMT'
        return sb.toString();
    }

我们阅读源代码得知Date类型的序列话是经过时区计算之后的结果。

JVM时区参数

java">-Duser.timezone=CST

tomcat与时区设置

tomcat可以将时区配置写到setenv.sh或者catalina.sh的JAVA_OPTS

java">-Duser.timezone=CST

mysql_281">mysql时区设置

mysql的datetime字段并不存储时区信息

我们的程序在mysql里存取Datetime的时候时间值取决于连接指定的时区

查看数据库会话时区命令

show VARIABLES like '%time_zone%'

在这里插入图片描述
在这里插入图片描述

全局参数system_time_zone

系统时区,在MySQL启动时会检查当前系统的时区并根据系统时区设置全局参数system_time_zone的值。

全局参数time_zone

用来设置每个连接会话的时区,默认为system时,使用全局参数system_time_zone的值。

上面两个配置并不是影响MySql自身的时区,它们指定的是程序连接到mysql的时候用的默认时区

临时修改MySql时区

改为东八区

set time_zone=+8:00;
set global time_zone =+8:00;
flush privileges;

MySql数据库时区连接参数

mysql驱动5.1版本要同时配置下面3个配置项连接服务器时区才会生效

useLegacyDatetimeCode=true
useTimezone=true
serverTimezone=Asia/Shanghai

修改jdbc连接设置,直接把连接的时区固定死,绕开mysql本身的时区

就是在jdbc连接配置上添加以下3个配置即可:

useLegacyDatetimeCode=true&useTimezone=true&serverTimezone=GMT%2B8

分别为启用时区设置和设置连接服务的时区

此时,jdbc操作都会使用自定义时区去进行时间处理。

8.0驱动没有useLegacyDatetimeCode=true,useTimezone=true 这两个配置项了。

Linux查看系统时区

# date -R
Sat, 12 Dec 2020 14:15:06 +0800
# date
Sat Dec 12 14:15:20 CST 2020

表明服务器的时区东八区同时认为CST中国标准时间

后端到前端的时间序列化因为时区导致的时间偏移

springboot 默认的 jackson 序列化到 前端

spring:
  jackson:
    date-format: yyyy-MM-dd HH:mm:ss
    time-zone: GMT+8

(全局) 固定将日期时间按照东八区时区序列化

java">
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss",timezone="GMT+8")
@JsonProperty("start_time")
private Date startTime;

设置单个字段的时区序列化

http调用传递Date类型的时区问题

java程序调用另一个java程序的接口时(或者叫后端接口)

此接口接收的参数有Date类型再序列化过程中会产生时区问题:即参数出现时差。

我们在条件不允许改变JVM的时区设置的时候也可以选择改变接口入参Date类型形参的序列化方案改纠正时区导致的时差问题。

接收入参的字段

java">	// spring mvc 接口注解:指定入参的反序列化方式
	@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
	// 字段的序列化格式
	@JsonFormat(pattern="yyyy-MM-dd HH:mm:ss")
	private Date beginTime;

传参使用SimpleDataFormat将Date字段序列化为指定格式的字符串。

结尾

建议在数据库连接参数上都加上时区参数
建议在后端到前端的接口序列化指定时区

不建议使用CST来做时区,容易造成系统混淆


http://www.niftyadmin.cn/n/1307426.html

相关文章

Java对象校验框架之Oval

编写登录 注册等功能的时候后台经行校验,可以使用oval框架,简单实用 package com.meadin.main.request; import com.meadin.module.base.BaseRequest; import net.sf.oval.constraint.Length; import net.sf.oval.constraint.NotEmpty; import net.sf.oval.constraint.NotNull…

SpringBoot优雅停服 java web tomcat web项目关闭过程概览

SpringBoot web项目优雅停服测试结果结论码代码下面是各个命令下的关闭过程kill -9kill -2kill -15actuator/shutdown 关闭过程和使用SpringBoot shutdown: graceful 优雅停服 停服过程及使用tomcat/bin/shutdown.sh我对优雅停服的要求是: 客户端已经进入的接口访问…

mysql 在select查询语句中使用临时变量累计求和 ; 相同列值的记录中再根据条件取其中最大或最新一条;mysql经纬度求距离并排序

mysql 使用临时变量累计求和 求同存异使用临时变量累计求和我们用的示例表码代码查询结果相同的ID,取最大或者最小的那个 (相同列值的记录中再根据条件取其中最大或最新一条)示例用的表码代码查询结果case when经纬度求距离并排序公式1公式2使…

Matlab中矩阵的分解

1、常见的分解方法 (1)三角分解(LU分解) (2)正交分解(QR) (3)特征值分解(eig分解) (4)奇异值分解&#xf…

java设计模式----创建型

java 设计模式:总体分为三大类 创建型:工厂模式 单例模式 建造者模式 结构型:桥接模式 适配器模式 代理模式 装饰者模式 外观模式 组合模式行为型:工厂模式:创建一个工厂 工厂里是一个生产对象的地方 需要时直接在…

Matlab对角矩阵

1、正对角 >> v [1 2 3 4 5 6 7 8 9]v 1 2 3 4 5 6 7 8 9>> diag(v)ans 1 0 0 0 0 0 0 0 00 2 0 0 0 0 0 0 00 0 3 0 0 0 0 0 …

spring cloud config 高可用配置

spring cloud config spring cloud 的配置管理中心,用来统一管理各个微服务的配置文件的。分为服务端和客户端 ,下面直接上代码为大家建立一个config-server config-client 创建项目 bw-config-server 1.bootstrap.yml server:port: 8084 eureka:cli…

Excel文件导出导入

导出原理分析 文件的导出功能和文件的下载功能类似&#xff0c;都是从服务器读取数据&#xff0c;然后将数据发送到客户端&#xff08;浏览器端&#xff09;&#xff1b;客户端可自动下载&#xff1b; 1.请求的方式必须是同步的&#xff0c;有两种方式可以选择 <a href&q…