• Java日期时间API系列19-----Jdk8中java.time包中的新的日期时间API类,ZonedDateTime与ZoneId和LocalDateTime的关系,ZonedDateTime格式化和时区转换等。


      通过Java日期时间API系列6-----Jdk8中java.time包中的新的日期时间API类中时间范围示意图:可以很清晰的看出ZonedDateTime相当于LocalDateTime+ZoneId。

      

      ZonedDateTime是用来处理时区相关的时间,它的各种计算都离不开ZoneId。先看ZoneId。

    1. ZoneId 为时区ID,比如Europe/Paris,表示欧洲巴黎时区

    1.1 时区相关知识,时区,UTC时间,GMT时间,Unix时间戳

    时区

    地球自西向东旋转,东边比西边先看到太阳,东边的时间也比西边的早。为了统一世界的时间,1884年的国际经度会议规规定将全球划分为24个时区(东、西各12个时区)。规定英国(格林尼治天文台旧址)为零时区(GMT+00),东1-12区,西1-12区,中国北京处于东8区(GMT+08)。

    若英国时间为6点整,则GMT时间为6点整,则北京时间为14点整。

    GMT和UTC

    GMT,即格林尼治标准时间,也就是世界时。GMT的正午是指当太阳横穿格林尼治子午线(本初子午线)时的时间。但由于地球自转不均匀不规则,导致GMT不精确,现在已经不再作为世界标准时间使用。

    UTC,即协调世界时。UTC是以原子时秒长为基础,在时刻上尽量接近于GMT的一种时间计量系统。为确保UTC与GMT相差不会超过0.9秒,在有需要的情况下会在UTC内加上正或负闰秒。UTC现在作为世界标准时间使用。

    所以,UTC与GMT基本上等同,误差不超过0.9秒。

    UNIX时间戳

    计算机中的UNIX时间戳,是以GMT/UTC时间「1970-01-01T00:00:00」为起点,到具体时间的秒数,不考虑闰秒。这么做当然是为了简化计算机对时间操作的复杂度。

    比如我的电脑现在的系统时间为2015年2月27日15点43分0秒,因为我的电脑默认时区为东8区,则0时区的时间为2015年2月27日7点43分0秒,则UNIX时间戳为1425022980秒。

    1.2  常用时区名称和缩写如下:

    package com.xkzhangsan.time.enums;
    
    /**
     * 常用时区枚举 包含中文名称,比如:"Asia/Shanghai","亚洲/上海"
     * 
     * @ClassName: ZoneIdEnum
     * @Description: ZoneIdEnum
     * @author xkzhangsan
     * @date 2020年02月18日
     * @version 0.1 ,初版,试用
     */
    public enum ZoneIdEnum {
    
        /**
         * "Australia/Darwin","澳洲/达尔文"
         */
        ACT("Australia/Darwin", "澳洲/达尔文"),
    
        /**
         * "Australia/Sydney","澳洲/悉尼"
         */
        AET("Australia/Sydney", "澳洲/悉尼"),
    
        /**
         * "America/Argentina/Buenos_Aires","美洲/阿根廷/布宜诺斯艾利斯"
         */
        AGT("America/Argentina/Buenos_Aires", "美洲/阿根廷/布宜诺斯艾利斯"),
    
        /**
         * "Africa/Cairo","非洲/开罗"
         */
        ART("Africa/Cairo", "非洲/开罗"),
    
        /**
         * "America/Anchorage","美洲/安克雷奇"
         */
        AST("America/Anchorage", "美洲/安克雷奇"),
    
        /**
         * "America/Sao_Paulo","美洲/圣保罗"
         */
        BET("America/Sao_Paulo", "美洲/圣保罗"),
    
        /**
         * "Asia/Dhaka","亚洲/达卡"
         */
        BST("Asia/Dhaka", "亚洲/达卡"),
    
        /**
         * "Africa/Harare","非洲/哈拉雷"
         */
        CAT("Africa/Harare", "非洲/哈拉雷"),
    
        /**
         * "America/St_Johns","美洲/圣约翰"
         */
        CNT("America/St_Johns", "美洲/圣约翰"),
    
        /**
         * "America/Chicago","美洲/芝加哥"
         */
        CST("America/Chicago", "美洲/芝加哥"),
    
        /**
         * "Asia/Shanghai","亚洲/上海"
         */
        CTT("Asia/Shanghai", "亚洲/上海"),
    
        /**
         * "Africa/Addis_Ababa","非洲/亚的斯亚贝巴"
         */
        EAT("Africa/Addis_Ababa", "非洲/亚的斯亚贝巴"),
    
        /**
         * "Europe/Paris","欧洲/巴黎"
         */
        ECT("Europe/Paris", "欧洲/巴黎"),
    
        /**
         * "America/Indiana/Indianapolis","美洲/印第安纳州/印第安纳波利斯"
         */
        IET("America/Indiana/Indianapolis", "美洲/印第安纳州/印第安纳波利斯"),
    
        /**
         * "Asia/Kolkata","亚洲/加尔各答"
         */
        IST("Asia/Kolkata", "亚洲/加尔各答"),
    
        /**
         * "Asia/Tokyo","亚洲/东京"
         */
        JST("Asia/Tokyo", "亚洲/东京"),
    
        /**
         * "Pacific/Apia","太平洋/阿皮亚"
         */
        MIT("Pacific/Apia", "太平洋/阿皮亚"),
    
        /**
         * "Asia/Yerevan","亚洲/埃里温"
         */
        NET("Asia/Yerevan", "亚洲/埃里温"),
    
        /**
         * "Pacific/Auckland","太平洋/奥克兰"
         */
        NST("Pacific/Auckland", "太平洋/奥克兰"),
    
        /**
         * "Asia/Karachi","亚洲/卡拉奇"
         */
        PLT("Asia/Karachi", "亚洲/卡拉奇"),
    
        /**
         * "America/Phoenix","美洲/凤凰城"
         */
        PNT("America/Phoenix", "美洲/凤凰城"),
    
        /**
         * "America/Puerto_Rico","美洲/波多黎各"
         */
        PRT("America/Puerto_Rico", "美洲/波多黎各"),
    
        /**
         * "America/Los_Angeles","美洲/洛杉矶"
         */
        PST("America/Los_Angeles", "美洲/洛杉矶"),
    
        /**
         * "Pacific/Guadalcanal","太平洋/瓜达尔卡纳尔岛"
         */
        SST("Pacific/Guadalcanal", "太平洋/瓜达尔卡纳尔岛"),
    
        /**
         * "Asia/Ho_Chi_Minh","亚洲/胡志明市"
         */
        VST("Asia/Ho_Chi_Minh", "亚洲/胡志明市"),
    
        /**
         * "-05:00","东部标准时间"(纽约、华盛顿)
         */
        EST("-05:00", "东部标准时间"),
    
        /**
         * "-07:00","山地标准时间"
         */
        MST("-07:00", "山地标准时间"),
    
        /**
         * "-10:00","夏威夷-阿留申标准时区"
         */
        HST("-10:00", "夏威夷-阿留申标准时区"),;
    
        private final String zoneIdName;
        private final String zoneIdNameCn;
    
        public String getZoneIdName() {
            return zoneIdName;
        }
    
        public String getZoneIdNameCn() {
            return zoneIdNameCn;
        }
    
        private ZoneIdEnum(String zoneIdName, String zoneIdNameCn) {
            this.zoneIdName = zoneIdName;
            this.zoneIdNameCn = zoneIdNameCn;
        }
    }

    1.3  更多时区id

      可以通过 java.time.ZoneId.getAvailableZoneIds()获取到。

    2. ZonedDateTime,ISO-8601日历系统中带有时区的日期时间,例如:2007-12-03T10:15:30+01:00 Europe/Paris

    2.1 创建ZonedDateTime

            ZonedDateTime.now();
    
            ZonedDateTime.now(ZoneId.systemDefault());
            
            ZonedDateTime.of(LocalDateTime.now(), ZoneId.systemDefault());

    2.2 ZonedDateTime与其他时间类的转换

        /**
         * 注意时间对应的时区和默认时区差异
         * @param zonedDateTime
         * @return
         */
        public static Date toDate(ZonedDateTime zonedDateTime) {
            Objects.requireNonNull(zonedDateTime, "zonedDateTime");
            return Date.from(zonedDateTime.toInstant());
        }
        
        /**
         * 注意时间对应的时区和默认时区差异
         * @param zonedDateTime
         * @return
         */
        public static LocalDateTime toLocalDateTime(ZonedDateTime zonedDateTime) {
            Objects.requireNonNull(zonedDateTime, "zonedDateTime");
            return zonedDateTime.toLocalDateTime();
        }
        
        /**
         * 注意时间对应的时区和默认时区差异
         * @param zonedDateTime
         * @return
         */
        public static LocalDate toLocalDate(ZonedDateTime zonedDateTime) {
            Objects.requireNonNull(zonedDateTime, "zonedDateTime");
            return zonedDateTime.toLocalDate();
        }
        
        /**
         * 注意时间对应的时区和默认时区差异
         * @param zonedDateTime
         * @return
         */
        public static LocalTime toLocalTime(ZonedDateTime zonedDateTime) {
            Objects.requireNonNull(zonedDateTime, "zonedDateTime");
            return zonedDateTime.toLocalTime();
        }
        
        /**
         * 注意时间对应的时区和默认时区差异
         * @param zonedDateTime
         * @return
         */
        public static Instant toInstant(ZonedDateTime zonedDateTime) {
            Objects.requireNonNull(zonedDateTime, "zonedDateTime");
            return zonedDateTime.toInstant();
        }
    
        /**
         * 转换为ZonedDateTime,时区为系统默认时区
         * @param date
         * @return
         */
        public static ZonedDateTime toZonedDateTime(Date date) {
            Objects.requireNonNull(date, "date");
            return Instant.ofEpochMilli(date.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime()
                    .atZone(ZoneId.systemDefault());
        }
        
        /**
         * 转换为ZonedDateTime,时区为系统默认时区
         * @param localDateTime
         * @return
         */
        public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime) {
            Objects.requireNonNull(localDateTime, "localDateTime");
            return localDateTime.atZone(ZoneId.systemDefault());
        }
    /** * LocalDateTime转ZonedDateTime,时区为zoneId对应时区 * 注意,需要保证localDateTime和zoneId是对应的,不然会出现错误 * * @param localDateTime * @param zoneId * @return */ public static ZonedDateTime toZonedDateTime(LocalDateTime localDateTime, String zoneId) { Objects.requireNonNull(localDateTime, "localDateTime"); Objects.requireNonNull(zoneId, "zoneId"); return localDateTime.atZone(ZoneId.of(zoneId)); }
    /** * 转换为ZonedDateTime,时区为系统默认时区 * @param localDate * @return */ public static ZonedDateTime toZonedDateTime(LocalDate localDate) { Objects.requireNonNull(localDate, "localDate"); return localDate.atStartOfDay().atZone(ZoneId.systemDefault()); } /** * 以当天的日期+LocalTime组成新的ZonedDateTime,时区为系统默认时区 * @param localTime * @return */ public static ZonedDateTime toZonedDateTime(LocalTime localTime) { Objects.requireNonNull(localTime, "localTime"); return LocalDate.now().atTime(localTime).atZone(ZoneId.systemDefault()); } /** * 转换为ZonedDateTime,时区为系统默认时区 * @param instant * @return */ public static ZonedDateTime toZonedDateTime(Instant instant) { return LocalDateTime.ofInstant(instant, ZoneId.systemDefault()).atZone(ZoneId.systemDefault()); }

    ===================================================================================

    测试代码:

        @Test
        public void zonedDateTimeConverterTest(){
            System.out.println("===================zonedDateTimeConverterTest=====================");
            System.out.println("===================ToOther=====================");
            ZonedDateTime zonedDateTime = ZonedDateTime.now();
            System.out.println(zonedDateTime);
            System.out.println(DateTimeConverterUtil.toDate(zonedDateTime));
            System.out.println(DateTimeConverterUtil.toLocalDateTime(zonedDateTime));
            System.out.println(DateTimeConverterUtil.toLocalDate(zonedDateTime));
            System.out.println(DateTimeConverterUtil.toLocalTime(zonedDateTime));
            System.out.println(DateTimeConverterUtil.toInstant(zonedDateTime));
            System.out.println("===================toZonedDateTime=====================");
            System.out.println(zonedDateTime);
            System.out.println(DateTimeConverterUtil.toZonedDateTime(new Date()));
            System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalDateTime.now()));
            System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalDate.now()));
            System.out.println(DateTimeConverterUtil.toZonedDateTime(LocalTime.now()));
            System.out.println(DateTimeConverterUtil.toZonedDateTime(Instant.now()));
        }

    输出:

    ===================zonedDateTimeConverterTest=====================
    ===================ToOther=====================
    2020-02-19T13:33:03.130+08:00[Asia/Shanghai]
    Wed Feb 19 13:33:03 CST 2020
    2020-02-19T13:33:03.130
    2020-02-19
    13:33:03.130
    2020-02-19T05:33:03.130Z
    ===================toZonedDateTime=====================
    2020-02-19T13:33:03.130+08:00[Asia/Shanghai]
    2020-02-19T13:33:03.150+08:00[Asia/Shanghai]
    2020-02-19T13:33:03.150+08:00[Asia/Shanghai]
    2020-02-19T00:00+08:00[Asia/Shanghai]
    2020-02-19T13:33:03.150+08:00[Asia/Shanghai]
    2020-02-19T13:33:03.150+08:00[Asia/Shanghai]

    由于  public static ZonedDateTime toZonedDateTime(LocalDate localDate),LocalDate只包含日期,所以,转换后显示为:2020-02-19T00:00+08:00[Asia/Shanghai]

    2.3 常用时区时间创建和时区转换计算

    常用时间,如北京时间,巴黎时间,纽约时间,东京时间等。

        /**
         * 获取当前系统当前时区时间
         * @param zoneId
         * @return
         */
        public static ZonedDateTime getZonedDateTimeNowOfDefault(){
            return ZonedDateTime.now(ZoneId.systemDefault());
        }
        
        /**
         * 获取当前上海时区时间(北京时间)
         * @param zoneId
         * @return
         */
        public static ZonedDateTime getZonedDateTimeNowOfShanghai(){
            return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.CTT.getZoneIdName()));
        }
        
        /**
         * 获取当前巴黎时区时间
         * @param zoneId
         * @return
         */
        public static ZonedDateTime getZonedDateTimeNowOfParis(){
            return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.ECT.getZoneIdName()));
        }
        
        /**
         * 获取当前美国东部标准时区(纽约、华盛顿)
         * @param zoneId
         * @return
         */
        public static ZonedDateTime getZonedDateTimeNowOfEST(){
            return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.EST.getZoneIdName()));
        }
        
        /**
         * 获取当前东京时区时间
         * @param zoneId
         * @return
         */
        public static ZonedDateTime getZonedDateTimeNowOfTokyo(){
            return ZonedDateTime.now(ZoneId.of(ZoneIdEnum.JST.getZoneIdName()));
        }    
        
        /**
         * 获取时区当前时间
         * @param zoneId
         * @return
         */
        public static ZonedDateTime getZonedDateTimeNow(String zoneId){
            Objects.requireNonNull(zoneId, "zoneId");
            return ZonedDateTime.now(ZoneId.of(zoneId));
        }
        
        /**
         * 时区转换计算
         * @param zonedDateTime
         * @param zoneId 例如 Asia/Shanghai
         * @return
         */
        public static ZonedDateTime transform(ZonedDateTime zonedDateTime, String zoneId){
            Objects.requireNonNull(zoneId, "zoneId");
            return transform(zonedDateTime, ZoneId.of(zoneId));
        }
        
        /**
         * 时区转换计算
         * @param zonedDateTime
         * @param zone
         * @return
         */
        public static ZonedDateTime transform(ZonedDateTime zonedDateTime, ZoneId zone){
            Objects.requireNonNull(zonedDateTime, "zonedDateTime");
            Objects.requireNonNull(zone, "zone");
            return zonedDateTime.withZoneSameInstant(zone);
        }

    测试代码:

        /**
         * 时区时间计算
         */
        @Test
        public void zonedDateTimeTest(){
            //系统默认时区
            System.out.println(DateTimeCalculatorUtil.getZonedDateTimeNowOfDefault());
            //系统上海时区
            ZonedDateTime shanghaiZonedDateTime = DateTimeCalculatorUtil.getZonedDateTimeNowOfShanghai();
            System.out.println(shanghaiZonedDateTime);
            //系统巴黎时区
            ZonedDateTime parisZonedDateTime = DateTimeCalculatorUtil.getZonedDateTimeNowOfParis();
            System.out.println(parisZonedDateTime);
            //系统美国东部时区纽约时间
            System.out.println(DateTimeCalculatorUtil.getZonedDateTimeNowOfEST());
            //系统东京时区
            System.out.println(DateTimeCalculatorUtil.getZonedDateTimeNowOfTokyo());
            
            //上海时区,转换为巴黎时区
            System.out.println("============transform 时区转换=============");
            System.out.println("shanghaiZonedDateTime: "+shanghaiZonedDateTime);
            ZonedDateTime transformZonedDateTime = DateTimeCalculatorUtil.transform(shanghaiZonedDateTime,
                    ZoneIdEnum.ECT.getZoneIdName());
            System.out.println("transformZonedDateTime: "+transformZonedDateTime);
            
        }

    输出:

    2020-02-19T13:40:49.638+08:00[Asia/Shanghai]
    2020-02-19T13:40:49.640+08:00[Asia/Shanghai]
    2020-02-19T06:40:49.642+01:00[Europe/Paris]
    2020-02-19T00:40:49.653-05:00
    2020-02-19T14:40:49.653+09:00[Asia/Tokyo]
    ============transform 时区转换=============
    shanghaiZonedDateTime: 2020-02-19T13:40:49.640+08:00[Asia/Shanghai]
    transformZonedDateTime: 2020-02-19T06:40:49.640+01:00[Europe/Paris]

    2.4 时区时间格式化与解析

    (1)时区时间格式化和ISO常用格式化,比如:yyyy-MM-dd'T'HH:mm:ssZ

        /**
         * 时区时间格式化和ISO常用格式化
         * YYYY_MM_DD_T_HH_MM_SS_Z = "yyyy-MM-dd'T'HH:mm:ssZ"
         */
        @Test
        public void zonedDateTimeFormatTest(){
            //默认为系统时区
            ZonedDateTime zonedDateTime = ZonedDateTime.now();
            //2020-02-18T22:37:55+0800
            System.out.println(DateTimeFormatterUtil.format(zonedDateTime, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_Z_FMT));
            
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_DATE_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_DATE_TIME_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_INSTANT_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_LOCAL_DATE_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_LOCAL_DATE_TIME_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_LOCAL_TIME_FMT));
            
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_TIME_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_WEEK_DATE_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.ISO_ZONED_DATE_TIME_FMT));
            System.out.println(zonedDateTime.format(DateTimeFormatterUtil.BASIC_ISO_DATE_FMT));
        }

    输出:

    2020-02-19T13:47:13+0800
    2020-02-19+08:00
    2020-02-19T13:47:13.271+08:00[Asia/Shanghai]
    2020-02-19T05:47:13.271Z
    2020-02-19
    2020-02-19T13:47:13.271
    13:47:13.271
    13:47:13.271+08:00
    2020-W08-3+08:00
    2020-02-19T13:47:13.271+08:00[Asia/Shanghai]
    20200219+0800

    (2)时区时间解析

        /**
         * 时区时间解析
         * YYYY_MM_DD_T_HH_MM_SS_Z = "yyyy-MM-dd'T'HH:mm:ssZ"
         */
        @Test
        public void parseToZonedDateTimeTest(){
            String text = "2020-02-18T22:37:55+0800";
            ZonedDateTime zonedDateTime = DateTimeFormatterUtil.parseToZonedDateTime(text, DateTimeFormatterUtil.YYYY_MM_DD_T_HH_MM_SS_Z_FMT);
            System.out.println(zonedDateTime);
            
            String text2 = "2020-02-19T12:30:25.121+08:00[Asia/Shanghai]";
            ZonedDateTime zonedDateTime2 = DateTimeFormatterUtil.parseToZonedDateTime(text2, DateTimeFormatterUtil.ISO_ZONED_DATE_TIME_FMT);
            System.out.println(zonedDateTime2);
            
            ZonedDateTime zonedDateTime3 = ZonedDateTime.parse(text2);
            System.out.println(zonedDateTime3);
        }

    输出:

    2020-02-18T22:37:55+08:00
    2020-02-19T12:30:25.121+08:00[Asia/Shanghai]
    2020-02-19T12:30:25.121+08:00[Asia/Shanghai]

    源代码地址:https://github.com/xkzhangsan/xk-time

    部分参考:

    https://www.cnblogs.com/xwdreamer/p/8761825.html

  • 相关阅读:
    链表栈
    双链表
    Linux sar命令查看系统资源使用情况
    Linux 命令(w/who/whoami/who am i)
    shell脚本引用expect
    expect 免交互配置互信
    expect 远程传输文件
    expect 远程执行命令-02
    expect 远程执行命令-01
    expect 脚本自定义变量和位置变量
  • 原文地址:https://www.cnblogs.com/xkzhangsanx/p/12331039.html
Copyright © 2020-2023  润新知