应用开发-对时间的关注
时间,在应用软件开发中是一个至关重要的因素。良好的时间一致不仅关乎项目的进度,还直接影响着软件的稳定性和用户体验。
在《时间的来龙去脉 & GMT、UTC、CST、时间戳、NTP》这篇文章中介绍了时间、UTC、GMT、CST、时间戳、时区等概念。
对于服务器系统时间的关注
Linux 系统中的时间主要有以下几种:
- 系统时间(System Time):
- 定义: 系统时间是指计算机内部的时钟,表示当前操作系统内核维护的时间。它通常是从硬件时钟获取的,可以是协调世界时(UTC)或本地时间的形式。
- 特点: 系统时间是动态变化的,会随着操作系统的运行而不断更新。
- 本地时间(Local Time):
- 定义: 本地时间是当前所在时区内的时间,是以系统时间为基础进行时区转换得到的。它是用户通常所看到的时间,考虑了时区的影响。
- 关系: 本地时间的显示和处理通常基于系统时间,通过时区转换来适应用户所在的地理位置。
- UTC 时间(Coordinated Universal Time):
- 定义: UTC 是协调世界时,表示世界标准时间。它是全球通用的时间标准,不考虑时区的影响,通常用于在不同地区和系统之间进行统一的时间表示。
- 关系: 本地时间和 UTC 时间之间的差值通常由系统时钟和时区设置确定。
- 硬件时钟(Hardware Clock / RTC):
- 定义: 硬件时钟是计算机硬件上的一个时钟,通常是一个芯片上的实时时钟。它可以是设置为UTC或本地时间,且通常不受操作系统影响,即使系统关机,硬件时钟仍能持续运行。
- 配置: 硬件时钟的设置可以通过计算机的BIOS或UEFI进行配置,决定其是使用UTC还是本地时间。
- 文件时间(File Time):
- 定义: 文件时间是指文件和目录的创建时间、修改时间等时间戳。在Linux系统中,你可以通过
ls -l
命令查看文件的时间戳信息。 - 应用: 文件时间对于文件的管理和跟踪修改非常有用,可以用于确定文件的版本、修改历史等。
- 定义: 文件时间是指文件和目录的创建时间、修改时间等时间戳。在Linux系统中,你可以通过
截止到本文编写时间结点,中国境内是不使用夏令时这个制度的。
服务器时间的初始设置(思考/建议)
对于服务器的时间上,一般开发默认使用UTC(世界标准时间)为硬件时间,再加上自身所处的时区为本地时间,在国内一般服务器以Asia/Shanghai为时区。
简单来说,初始化服务器时间的步骤如下:
- 将硬件时间设置为UTC格式。
- 设置服务器时区为本地时区(例如,Asia/Shanghai)。
- 使用网络时间协议(NTP)进行同步,或手动进行时间调整。
- 确保本地时间与系统时间保持同步。
这样的设置可以有效避免时区混淆,确保服务器时间的正确性。
查看当前时间和时区设置
timedatectl
设置硬件时钟为 UTC
sudo timedatectl set-local-rtc 0
设置时区为中国东八区
sudo timedatectl set-timezone Asia/Shanghai
这将设置系统时区为中国标准时间(CST,UTC+8)。
查看设置是否生效
timedatectl
###############################
Local time: 二 2024-01-02 13:51:57 CST 当前本地时间,即时区为 Asia/Shanghai(中国标准时间 CST,UTC+8)的时间。
Universal time: 二 2024-01-02 05:51:57 UTC 协调世界时(UTC)时间,表示全球标准时间,与时区无关。
RTC time: 二 2024-01-02 05:48:45 RTC 时间,即硬件时钟(Real-Time Clock)的时间。
Time zone: Asia/Shanghai (CST, +0800) 时区设置,这里是 Asia/Shanghai(中国标准时间 CST,UTC+8)。
NTP enabled: no 是否启用网络时间协议(NTP),这里显示为 "no",表示没有启用 NTP。
NTP synchronized: no 是否与 NTP 服务器同步,这里显示为 "no",表示当前没有与 NTP 服务器同步。
RTC in local TZ: no 是否硬件时钟在本地时区,这里显示为 "no",表示硬件时钟不受本地时区影响,可能是设置为 UTC 时间。
DST active: n/a 夏令时是否激活,这里显示为 "n/a",表示不适用于当前设置。夏令时(Daylight Saving Time)通常在一些地区会在夏季时激活,以调整时钟向前或向后一小时。
确保 “RTC in local TZ” 为 “no”,而 “Time zone” 为 “Asia/Shanghai”。
将系统时间同步到硬件时钟
sudo hwclock --systohc
这个命令将当前系统时间写入硬件时钟。
最后查看时间设置
date
#2024年 01月 02日 星期二 14:00:50 CST
hwclock --show
#2024年01月02日 星期二 14时01分12秒 -0.460377 秒
数据库时间的关注
启动参数&系统变量
在MySQL中,可以通过启动参数和系统变量来配置时区。
-
启动参数: 使用
default-time-zone
参数在MySQL启动时指定时区。# 方法1:在启动命令中添加 mysqld --default-time-zone='+08:00' & # 方法2:在配置文件中添加 [mysqld] default-time-zone='+08:00'
-
系统变量: 通过
time_zone
系统变量控制时区。-- 查看时区配置 mysql> show global variables like '%time%zone%'; +------------------+--------+ | Variable_name | Value | +------------------+--------+ | system_time_zone | CST | | time_zone | +08:00 | +------------------+--------+ 2 rows in set (0.00 sec) -- 修改全局时区,所有已经创建的、新创建的session都会被修改 set global time_zone='+00:00'; -- 修改当前session时区 set session time_zone='+00:00';
可用的时区值包括’SYSTEM’、相对于UTC的偏移(如’+08:00’或’-6:00’)、时区名字(如’Asia/Shanghai’),需要先导入时区信息到mysql库中。
时区影响
时区的设置会影响以下两个方面:
-
NOW()和CURTIME()函数的返回值: 受当前session的时区影响,包括
INSERT
语句和字段的DEFAULT CURRENT_TIMESTAMP
属性。sqlCopy codemysql> set time_zone='+08:00'; mysql> select now(), CURTIME(); mysql> set time_zone='+00:00'; mysql> select now(), CURTIME();
-
timestamp数据类型字段的存储: timestamp会存储当前session的时区信息,读取时根据当前session的时区进行转换,而datetime则不受时区影响。
sqlCopy codemysql> set time_zone='+08:00'; mysql> create table t(ts timestamp, dt datetime); mysql> insert into t values('2021-12-02 16:45:39','2021-12-02 16:45:39'); mysql> set time_zone='+00:00'; mysql> select * from t;
关于时区的建议
- MySQL安装规范: 在my.cnf中写入
default-time-zone='+08:00'
(8.0版),对于其他地区,确认并设置对应的时区。 - 解决Java应用时间差问题: JDBC参数中设置
serverTimezone
属性,确保MySQL全局时区设置为’+08:00’。 - 修改MySQL时区不影响已存储数据: 仅对timestamp数据类型读取有影响,建议在开发规范中使用datetime类型。
- 迁移数据时防止时区错误: 使用mysqldump导出时,确保设置
--skip-tz-utc
参数,或者保持导出和导入时使用相同的时区。
JAVA时间的关注
JAVA应用时间来源
在Java应用程序中,通过JAR文件启动后获取的时间通常是依赖于JVM(Java虚拟机)的时间设置,而不是直接使用Linux的本地时间或硬件时间。(tomcat也是一样,因为该应用在Tomcat中作为一个独立的Java虚拟机进程运行。)
JVM(Java Virtual Machine)的时间通常是从底层操作系统获取的系统时间。JVM利用系统调用获取操作系统的当前时间,这通常涵盖了硬件时钟和操作系统时钟的信息。
JVM时间的设置
Java 虚拟机(JVM)通常会默认使用系统的时区设置。它会通过查找底层操作系统的时区设置来确定默认时区。
1.服务器的时区设置一致,则默认启动
2.在启动参数中携带-Duser.timezone,该系统属性用于设置用户的时区。
java -Duser.timezone=Asia/Shanghai -jar your-application.jar
常见的做法是将JVM的时区设置在启动脚本或配置文件中进行统一配置。
3.sun.util.calendar.ZoneInfoFile
这个系统属性指定了时区信息的文件路径,影响JVM如何加载时区数据。一般情况下,你无需手动设置这个属性,因为JVM会自动查找时区信息。
4.user.country, user.language
这两个系统属性也可能影响某些时间和日期的处理,尽管它们与时区设置关系较小。
总结:
- 服务器系统时间的关注:
- Linux系统中有多种时间概念,包括系统时间、本地时间、UTC时间、硬件时钟、文件时间等。
- 初始设置时,建议将硬件时间设置为UTC格式,时区设置为本地时区(例如,Asia/Shanghai),并使用NTP进行同步。
- 数据库时间的关注:
- MySQL中可以通过启动参数和系统变量配置时区,影响NOW()、CURTIME()函数和timestamp字段的行为。
- 建议在MySQL安装规范中设置默认时区,处理Java应用时间差问题,并在开发规范中使用datetime类型以减少时区影响。
- Java应用时间的关注:
- JVM的时间通常从底层操作系统获取,可以通过启动参数(-Duser.timezone)统一设置时区。
- 常见做法是在启动脚本或配置文件中配置JVM的时区,确保与服务器一致。