背景:项目中电商体系需求出海,在亚太和欧洲站点部署,开放给多个国家访问。每个国家的时区不一样,需求在各个国家前端展示不一样的时刻。
比方现在中国是东8区,日本是东9区,同一时刻两地上网阅读时刻就会相差一个小时。
处理办法
总结成一句话,一切时刻的处理需求带上时区或许转化成肯定时刻UTC时刻来处理
详细如下:
- 后端体系存储统一用 UTC 时刻(包含DB落盘、内部逻辑处理),不应当受用户时区或服务器时区的影响
- 体系间交互(包含rpc接口以及rest接口)有关时刻的处理,统一带上时区。我们是用String类型
yyyyMMddHHmmssz
- 前端输入、展示的时刻,依据详细事务场景进行时区调整(时区从阅读器获取,或许经过国家与时区映射来取),以及精度调整
- 面临不带时刻的日期,要清晰区别「纪念日」与「精度不高的肯定时刻」两种用处,大部分时分你看到的日期是后者,它也应当用“确定时区的 DateTime”来完成
针对后台定时使命比方过期时刻处理或许特定时刻发布的场景,后台最好维护国家和时区的映射联系,按照国家顺次取到特定时刻来逐个处理
java中的时刻表明
jdk8之前
在Java中,在JDK 8之前,时刻表明和时区转化主要运用java.util.Date
、java.util.Calendar
和java.text.SimpleDateFormat
等类进行操作。
-
时刻表明:
-
java.util.Date
:Date
类表明特定的时刻点,准确到毫秒等级。它运用自UTC(协调世界时)的纪元时刻以来的毫秒数来表明时刻。可是,Date
类在规划上存在一些问题,因此在JDK 8中引入了新的日期和时刻API(java.time包)来代替它。 -
java.util.Calendar
:Calendar
类是用来进行日期和时刻核算的抽象类。它供给了处理日期和时刻的各种办法,例如获取年、月、日、时、分、秒等。可是,Calendar
类的运用不太方便,并且在多线程环境下也存在线程安全问题。
-
-
时区转化:
-
java.util.TimeZone
:TimeZone
类用于表明特定的时区。它供给了静态办法来获取体系默许时区或指定时区的实例,以及将日期和时刻转化到指定时区的功用。 -
java.text.SimpleDateFormat
:SimpleDateFormat
类用于将日期和时刻格局化为指定模式的字符串,或许将字符串解析为日期和时刻。它能够指定时区来进行转化操作。
-
相关举例如下:
运用java.util.Date
和java.text.SimpleDateFormat
进行格局化和解析
// 格局化日期为字符串
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String formattedDate = sdf.format(date);
System.out.println("Formatted Date: " formattedDate);
// 解析字符串为日期
String dateString = "2021-09-30 15:30:45";
Date parsedDate = sdf.parse(dateString);
System.out.println("Parsed Date: " parsedDate);
运用java.util.Calendar
进行日期和时刻核算
Calendar calendar = Calendar.getInstance();
// 获取当时年份
int year = calendar.get(Calendar.YEAR);
System.out.println("Current Year: " year);
// 添加一个月
calendar.add(Calendar.MONTH, 1);
int newMonth = calendar.get(Calendar.MONTH);
System.out.println("New Month: " newMonth);
// 设置特定日期
calendar.set(2022, Calendar.MARCH, 15);
int day = calendar.get(Calendar.DAY_OF_MONTH);
System.out.println("Day: " day);
运用java.util.TimeZone
进行时区转化
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
// 设置时区为纽约
TimeZone newYorkTimeZone = TimeZone.getTimeZone("America/New_York");
sdf.setTimeZone(newYorkTimeZone);
String newYorkTime = sdf.format(date);
System.out.println("New York Time: " newYorkTime);
// 设置时区为东京
TimeZone tokyoTimeZone = TimeZone.getTimeZone("Asia/Tokyo");
sdf.setTimeZone(tokyoTimeZone);
String tokyoTime = sdf.format(date);
System.out.println("Tokyo Time: " tokyoTime);
jdk8及以后
在JDK 8及其之后,Java引入了新的日期和时刻API,即java.time
包,以解决旧的日期和时刻类(如java.util.Date
和java.util.Calendar
)存在的问题。新的API供给了更加简练、易用和线程安全的方法来处理日期、时刻和时区的表明和转化。
运用LocalDate
、LocalTime
和LocalDateTime
进行日期和时刻操作
// 获取当时日期
LocalDate currentDate = LocalDate.now();
System.out.println("Current Date: " currentDate);
// 获取当时时刻
LocalTime currentTime = LocalTime.now();
System.out.println("Current Time: " currentTime);
// 创建特定日期和时刻
LocalDate specificDate = LocalDate.of(2022, 3, 15);
LocalTime specificTime = LocalTime.of(12, 30, 0);
LocalDateTime specificDateTime = LocalDateTime.of(specificDate, specificTime);
System.out.println("Specific Date and Time: " specificDateTime);
运用ZoneId
和ZonedDateTime
进行时区转化:
LocalDateTime localDateTime = LocalDateTime.now();
ZoneId newYorkZone = ZoneId.of("America/New_York");
ZoneId tokyoZone = ZoneId.of("Asia/Tokyo");
// 转化到纽约时区
ZonedDateTime newYorkTime = ZonedDateTime.of(localDateTime, newYorkZone);
System.out.println("New York Time: " newYorkTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
// 转化到东京时区
ZonedDateTime tokyoTime = newYorkTime.withZoneSameInstant(tokyoZone);
System.out.println("Tokyo Time: " tokyoTime.format(DateTimeFormatter.ISO_ZONED_DATE_TIME));
mysql中的时刻表明
在MySQL中,有几种不同的时刻类型可用于存储和操作日期和时刻数据。下面是MySQL中常见的时刻类型及其扼要介绍:
- DATE:DATE类型用于存储日期值,格局为’YYYY-MM-DD’。它能够表明从’1000-01-01’到’9999-12-31’之间的日期。
- TIME:TIME类型用于存储时刻值,格局为’HH:MM:SS’。它能够表明从’-838:59:59’到’838:59:59’之间的时刻。
- DATETIME:DATETIME类型用于存储日期和时刻值,格局为’YYYY-MM-DD HH:MM:SS’。它能够表明从’1000-01-01 00:00:00’到’9999-12-31 23:59:59’之间的日期和时刻。
- TIMESTAMP:TIMESTAMP类型用于存储日期和时刻值,格局为’YYYY-MM-DD HH:MM:SS’。它能够表明从’1970-01-01 00:00:01′ UTC到’2038-01-19 03:14:07′ UTC之间的日期和时刻。注意,TIMESTAMP类型还能够自动更新为当时时刻戳,例如在刺进或更新行时。
- YEAR:YEAR类型用于存储年份值,格局为’YYYY’。它能够表明从’1901’到’2155’之间的年份。