数据库时区那些事儿 - MySQL的时区处理

原文地址

当JVM时区和数据库时区不一致的时候,会发生什么?这个问题也许你从来没有注意过,但是当把Java程序容器化的时候,问题就浮现出来了,因为目前几乎所有的Docker Image的时区都是UTC。本文探究了MySQL及其JDBC驱动对于时区的处理方式,并尝试给出最佳实践。

先给总结

  • DATETIME类型不支持时区转换。
  • 对于TIMESTAMP类型,MySQL会正确的根据connection时区(对于JDBC来说就是JVM时区)/服务端时区做转换。

    • JDBC程序不需要特别注意什么事情。只要保证JVM时区和用户所在时区保持一致即可。
  • 不要在服务器端做日期时间的字符串格式化(DATE_FORMAT()),因为返回的结果是服务端的时区,而不是connection的时区(对于JDBC来说就是JVM时区)。
  • CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE()可以安全的使用,返回的结果会转换成connection时区(对于JDBC来说就是JVM时区)。
  • CURRENT_TIME()有一个不知道是不是BUG的Bug #92453。

日期时间类型的时区

MySQL - The DATE, DATETIME, and TIMESTAMP Types:

MySQL converts TIMESTAMP values from the current time zone to UTC for storage, and back from UTC to the
current time zone for retrieval. (This does not occur for other types such as DATETIME.)
By default, the current time zone for each connection is the server's time. The time zone can be set on
a per-connection basis.
As long as the time zone setting remains constant, you get back the same value you store.
If you store a TIMESTAMP value, and then change the time zone and retrieve the value, the retrieved value
is different from the value you stored. This occurs because the same time zone was not used for conversion
in both directions.

简而言之就是两句话:

  1. 查询TIMESTAMP类型所返回的值,会根据connection的时区(对于JDBC来说就是JVM时区)做转换
  2. 在MySQL中只有TIMESTAMP类型会做时区转换

为了验证这个结论,我写了一段程序来实验,这个程序做了三件事情:

  1. 使用Asia/Shanghai时区构造一个日期java.util.Date2018-09-14 10:00:00,然后插入到数据库里(表:test,列:timestamp类型)
  2. 使用Asia/Shanghai时区把这个值再查出来,看看结果。
  3. 使用Asia/Shanghai时区,获得这个字段的格式化字符串(使用DATE_FORMAT()函数)。
  4. 使用Europe/Paris时区重复第2-3步的动作

在运行程序之前,我们先用Docker启动一个MySQL,它所在的MySQL的时区是UTC(除非特别设定,所有Docker Image时区都默认为UTC):

docker run --name mysql-timezone-test \-e MYSQL_RANDOM_ROOT_PASSWORD=yes \-e MYSQL_DATABASE=testdb \-e MYSQL_USER=tz \-e MYSQL_PASSWORD=tz \-p 3306:3306 \-d mysql:8

下面是结果:

Insert data, Time Zone        : 中国标准时间
java.util.Date                : 2018-09-14 10:00:00
Insert into timestamp column  : 2018-09-14 10:00:00
--------------------
Retrieve data, Time Zone      : 中国标准时间
Retrieve java.util.Date       : 2018-09-14 10:00:00
Retrieve formatted string     : 2018-09-14 02:00:00
--------------------
Retrieve data, Time Zone      : 中欧时间
Retrieve java.util.Date       : 2018-09-14 04:00:00
Retrieve formatted string     : 2018-09-14 02:00:00

可以看到Retrieve java.util.Date返回的结果根据JVM时区做了转换的。而Retrieve formatted string返回的结果则是UTC时间。

当前日期时间相关函数

MySQL与"当前日期时间"相关的函数有这么些,MySQL - Date and Time Functions:

The CURRENT_TIMESTAMP(), CURRENT_TIME(), CURRENT_DATE(), and FROM_UNIXTIME() functions return values
in the connection's current time zone, which is available as the value of the time_zone system variable.

而且根据文档所讲,它们返回的结果匹配当前连接所设定的时区。

为了验证这个结论,同样写了一段程序,分别使用Asia/ShanghaiEurope/Paris来调用CURRENT_TIMESTAMP()CURRENT_TIME()CURRENT_DATE()

下面是运行结果:

JVM Time Zone              : 中国标准时间
Test CURRENT_DATE()        : 2018-09-18
Test CURRENT_TIME()        : 10:55:41
Test CURRENT_TIMESTAMP()   : 2018-09-18 10:55:41.0
--------------------
JVM Time Zone              : 中欧时间
Test CURRENT_DATE()        : 2018-09-18
Test CURRENT_TIME()        : 03:56:02
Test CURRENT_TIMESTAMP()   : 2018-09-18 04:56:02.0

可以看到结果是基本符合文档里的说明的,但是要注意,在Europe/Paris时区,CURRENT_TIME()CURRENT_TIMESTAMP()的时间部分相差一小时。
看上去CURRENT_TIMESTAMP()返回的是UTC DST offset结果,而CURRENT_TIME()返回的是UTC offset结果,关于这个我登记了Bug #92453。
关于Europe/Paris的DST信息可以在这里找到Wiki - List of tz database time zones。

在MySQL客户端操作时区

-- 查询系统时区和session时区
SELECT @@global.time_zone, @@session.time_zone;-- 设置session时区
SET time_zone = 'Asia/Shanghai';

详见:MySQL Server Time Zone Support

Docker启动时设定时区

你可以在docker启动的时候设定MySQL容器的时区,比如这样-e TZ=Asia/Shanghai

这个方法有问题,会出现时间错乱,workaround是root用户连接到MySQL,然后执行SET GLOBAL time_zone = 'Asia/Shanghai';

这样客户端连接MySQL时,查询的时间的时区都是Asia/Shanghai了。

参考资料

  • MySQL - The DATE, DATETIME, and TIMESTAMP Types
  • MySQL - Date and Time Functions
  • MySQL Server Time Zone Support
  • Wiki - List of tz database time zones
  • W3C- Working with timezone

相关代码

https://github.com/chanjarste...

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/282109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

全新升级的AOP框架Dora.Interception[2]: 基于约定的拦截器定义方式

Dora.Interception(github地址,觉得不错不妨给一颗星)有别于其他AOP框架的最大的一个特点就是采用针对“约定”的拦截器定义方式。如果我们为拦截器定义了一个接口或者基类,那么拦截方法将失去任意注册依赖服务的灵活性。除此之外…

加快Android Studio的编译速度

从Eclipse切换到Android Studio后,感觉Android Studio的build速度比Eclipse慢很多,以下几个方法可以提高Android Studio的编译速度使用Gradle 2.4Gradle 2.4对执行性能有很大的优化,但Android Studio现在默认使用的是Gradle 2.2,所以我们需要…

PaddleOCR在 Linux下的webAPI部署方案

很多小伙伴在使用OCR时都希望能采用API的方式调用,这样就可以跨端跨平台了。本文将介绍一种基于python的PaddleOCR识别WebAPI部署方案。喜欢的可以关注公众号,获取更多内容。一、 Linux环境下部署1.环境要求操作系统:CenterOS7;主…

影响程序员生涯的三个错误观念,你千万不要犯!

程序员在社会上,到底是怎样一个生活群体?是否能找到自己方向?其实,路一直都在那里,只是你看不到而已! 当初的你,可能一直被一些技术牵着鼻子走,并不是自己在做着自己想做的&#xff…

心电图计算心率公式_心电图到底能反应啥问题,看过之后你也能当“医生”

只要是经历过健康体检的健康人,或者做过手术的患者,基本都做过心电图检查。都说久病成医,所以有些人对血、尿常规等各项检查的结果都门清儿得很,最起码看一眼也能说出个大概齐。偏偏心电图这种常做的检查,不但老病号如…

获取正在运行的服务

手机上安装的App,在后台运行着很多不同功能的服务,最常见的例如消息推送相关的服务。如何查看这些服务?如何判断某个服务是否正在运行?如何停止某一个服务呢?请看下面的方法: package com.example.servicel…

开发composer包

一、初始化&#xff08;生成composer.json文件&#xff09; composer init#输入你要创建的composer包项目命名空间 Package name (<vendor>/<name>) [root/tiny-laravel]: #haveyb/tiny-laravel #输入composer包的描述 Description []:#this is a tiny laravel h…

Linux本地yum源配置以及使用yum源安装gcc编译环境

本文档是图文安装本地yum源的教程&#xff0c;以安装gcc编译环境为例。 适用范围&#xff1a;所有的cetos,红帽,fedroa版本 适用人群&#xff1a;有一点linux基础的小白 范例系统版本&#xff1a;CentOS Linux release 7.3.1611 (Core) 范例环境&#xff1a;vmware 虚拟机 安装…

word如何设置上标形式_如何在word中设置特殊页码

获取更多业界资讯和深度好文● 点击蓝字关注我们 ●在日常工作中&#xff0c;我们编辑的word文档经常需要设置页码&#xff0c;但有时文档的第一页是封面&#xff0c;第二页才是正文&#xff0c;或者第二页是目录&#xff0c;第三页才是正文&#xff0c;如下图所示&#xff0c;…

发布composer包到 Packagist,并设置自动同步(从github到Packagist)

一、发布composer包 1、将我们写好的项目包发布到github上 这一步不赘述&#xff0c;应该都会。 但是需要注意的是&#xff0c;我们一定要为我们的项目包打上tag之后再提交&#xff0c;否则 我们composer require时可能会报错 Could not find a version of package。 # 设置…

教你在CorelDRAW中导入位图

在CorelDRAW软件中不能直接打开位图图像&#xff0c;在实际操作中&#xff0c;用户需要使用导入位图图像的方法进行操作。导入位图图像时&#xff0c;可以导入整幅图像&#xff0c;也可以在导入的过程中对图像进行裁剪&#xff0c;或重新取样图像&#xff0c;导入整幅位图图像时…

.NET 6 中将 ASP.NET Core 注册成 Windows Service

前言使用 Visual Studio 中的 Worker Service项目模板:我们很容易创建出 Windows Service&#xff1a;IHost host Host.CreateDefaultBuilder(args).UseWindowsService().ConfigureServices(services >{services.AddHostedService<Worker>();}).Build();await host.R…

19.12 添加自定义监控项目 配置邮件告警 测试告警

9月12日任务19.12 添加自定义监控项目19.13/19.14 配置邮件告警19.15 测试告警19.16 不发邮件的问题处理19.12 添加自定义监控项目需求&#xff1a;监控某台web的80端口连接数&#xff0c;并出图两步&#xff1a;1&#xff09;zabbix监控中心创建监控项目&#xff1b;2&#xf…

wab框架

http协议 一、http简介 1.HTTP是一个基于TCP/IP通信协议来传递数据&#xff08;HTML 文件, 图片文件, 查询结果等&#xff09;。 2.HTTP是一个属于应用层的面向对象的协议&#xff0c;由于其简捷、快速的方式&#xff0c;适用于分布式超媒体信息系统。它于1990年提出&#xff0…

c++ 二维矩阵 转vector_Python线性代数学习笔记——矩阵的基本运算和基本性质,实现矩阵的基本运算...

当学习完矩阵的定义以后&#xff0c;我们来学习矩阵的基本运算&#xff0c;与基本性质矩阵的基本运算&#xff1a;矩阵的加法&#xff0c;每一个对应元素相加&#xff0c;对应结果的矩阵例子&#xff1a;矩阵A和矩阵B表示的是同学上学期和下学期的课程的成绩&#xff0c;两个矩…

android 4.4以上能够实现的沉浸式状态栏效果

仅仅有android4.4以及以上的版本号才支持状态栏沉浸效果 先把程序执行在4.4下面的手机上,看下效果: 在4.4以上的效果: 当然图片也是能够作为背景的.效果: 代码: if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) {Window window getWindow();window.setFlags(Wind…

为abp vnext生成C#客户端给非abp第三方net程序使用

abp vnext提供了动态C#API客户端和静态C#API客户端来调用abp项目的接口&#xff0c;但是有局限性&#xff1b;要使用动态C#API客户端的项目必须也是ABP vnext的项目。静态C#API客户端也依赖abp的包&#xff0c;如下图为的静态客户端依赖于 Volo.Abp.DependencyInjection、Volo.…

C#项目代码规范

目的 1.方便代码的交流和维护。 2.不影响编码的效率&#xff0c;不与大众习惯冲突。 3.使代码更美观、阅读更方便。 4.使代码的逻辑更清晰、更易于理解。 在C#中通常使用的两种编码方式如下 Camel(驼峰式)&#xff1a; 大小写形式&#xff0d;除了第一个单词&#xff0c;所有单…

.NET MAUI实战 FolderPicker

1.概要最近在迁移 GeneralUpdate.Tool的时候需要用到文件夹选择&#xff0c;在MAUI中可以使用FolderPicker进行选择。注意&#xff0c;和上篇文章的文件选择不一样。因为在.NET MAUI中目前还没有傻瓜式直接可用的FolderPicker供开发者使用所以需要自己动手做一些修改。完整示例…

h5外卖源码php_校园食堂外卖APP走红 更多APP定制开发上一品威客网

近日&#xff0c;西安一高校推出了一款校园食堂外卖APP走红网络。该APP涵盖学校食堂的所有饭菜&#xff0c;并可给该校的师生提供校园食堂饭菜外卖服务。饭菜价格与食堂统一&#xff0c;且仅供该校内的师生使用。 目前开发校园外卖订餐系统可谓是一个较热门的创业项目&#xff…