背景:项目中电商体系需求出海,在亚太和欧洲站点部署,开放给多个国家访问。每个国家的时区不一样,需求在各个国家前端展示不一样的时刻。
比方现在中国是东8区,日本是东9区,同一时刻两地上网阅读时刻就会相差一个小时。

处理办法

总结成一句话,一切时刻的处理需求带上时区或许转化成肯定时刻UTC时刻来处理
详细如下:

  1. 后端体系存储统一用 UTC 时刻(包含DB落盘、内部逻辑处理),不应当受用户时区或服务器时区的影响
  2. 体系间交互(包含rpc接口以及rest接口)有关时刻的处理,统一带上时区。我们是用String类型 yyyyMMddHHmmssz
  3. 前端输入、展示的时刻,依据详细事务场景进行时区调整(时区从阅读器获取,或许经过国家与时区映射来取),以及精度调整
  4. 面临不带时刻的日期,要清晰区别「纪念日」与「精度不高的肯定时刻」两种用处,大部分时分你看到的日期是后者,它也应当用“确定时区的 DateTime”来完成

针对后台定时使命比方过期时刻处理或许特定时刻发布的场景,后台最好维护国家和时区的映射联系,按照国家顺次取到特定时刻来逐个处理

java中的时刻表明

jdk8之前

Java中,在JDK 8之前,时刻表明和时区转化主要运用java.util.Datejava.util.Calendarjava.text.SimpleDateFormat等类进行操作。

  1. 时刻表明:

    • java.util.DateDate类表明特定的时刻点,准确到毫秒等级。它运用自UTC(协调世界时)的纪元时刻以来的毫秒数来表明时刻。可是,Date类在规划上存在一些问题,因此在JDK 8中引入了新的日期和时刻API(java.time包)来代替它。
    • java.util.CalendarCalendar类是用来进行日期和时刻核算的抽象类。它供给了处理日期和时刻的各种办法,例如获取年、月、日、时、分、秒等。可是,Calendar类的运用不太方便,并且在多线程环境下也存在线程安全问题。
  2. 时区转化:

    • java.util.TimeZoneTimeZone类用于表明特定的时区。它供给了静态办法来获取体系默许时区或指定时区的实例,以及将日期和时刻转化到指定时区的功用。
    • java.text.SimpleDateFormatSimpleDateFormat类用于将日期和时刻格局化为指定模式的字符串,或许将字符串解析为日期和时刻。它能够指定时区来进行转化操作。

相关举例如下:
运用java.util.Datejava.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.Datejava.util.Calendar)存在的问题。新的API供给了更加简练、易用和线程安全的方法来处理日期、时刻和时区的表明和转化。

运用LocalDateLocalTimeLocalDateTime进行日期和时刻操作

         // 获取当时日期
        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);

运用ZoneIdZonedDateTime进行时区转化:

        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中常见的时刻类型及其扼要介绍:

  1. DATE:DATE类型用于存储日期值,格局为’YYYY-MM-DD’。它能够表明从’1000-01-01’到’9999-12-31’之间的日期。
  2. TIME:TIME类型用于存储时刻值,格局为’HH:MM:SS’。它能够表明从’-838:59:59’到’838:59:59’之间的时刻。
  3. DATETIME:DATETIME类型用于存储日期和时刻值,格局为’YYYY-MM-DD HH:MM:SS’。它能够表明从’1000-01-01 00:00:00’到’9999-12-31 23:59:59’之间的日期和时刻。
  4. TIMESTAMP:TIMESTAMP类型用于存储日期和时刻值,格局为’YYYY-MM-DD HH:MM:SS’。它能够表明从’1970-01-01 00:00:01′ UTC到’2038-01-19 03:14:07′ UTC之间的日期和时刻。注意,TIMESTAMP类型还能够自动更新为当时时刻戳,例如在刺进或更新行时。
  5. YEAR:YEAR类型用于存储年份值,格局为’YYYY’。它能够表明从’1901’到’2155’之间的年份。

参阅

Java服务器时区时刻转化为中心,完成简单高效的时刻转化计划
一文读懂全球化体系中的日期时刻处理问题