zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之六 多点触控
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之九 定位
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之七 重力感应
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之五 保存数据的几种方式
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之八 照相机
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之三 Application 配置详解
    Adobe Flash Builder 4.5 Android Air 程序开发系列 之四 打开与关闭应用程序是的保存数据
    ADOBE FLASH BUILDER 4.6 IOS 开发之部署与调试
    [译] 高性能JavaScript 1至5章总结
    页签及盒子的web标准实现
  • 原文地址:https://www.cnblogs.com/xkzhangsanx/p/12331039.html
Copyright © 2011-2022 走看看