背景:项目中电商系统需要出海,在亚太和欧洲站点部署,开放给多个国家访问。每个国家的时区不一样,需要在各个国家前端展示不一样的时间。
比如现在中国是东8区,日本是东9区,同一时刻两地上网浏览时间就会相差一个小时。
处理方法
总结成一句话,所有时间的处理需要带上时区或者转换成绝对时间UTC时间来处理
具体如下:
yyyyMMddHHmmssz
针对后台定时任务比如过期时间处理或者特定时间发布的场景,后台最好维护国家和时区的映射关系,按照国家依次取到特定时间来一一处理
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中常见的时间类型及其简要介绍:
参考
Java服务器时区时间转换为中心,实现简单高效的时间转换方案
一文读懂全球化系统中的日期时间处理问题