• Java8日期处理


    Java处理日期、日历和时间的方式一直为社区所诟病,将java.util.Date设定为可变类型,以及SimpleDateFormat的非现场安全使其应用非常受限。
    Java8的新API基于ISO标准的日历系统,java.time包下的所有类都有不可变类型而且线程安全
    编号 类的名称 描述
    1 Instant 以GMT时间为起点的偏移量
    2 Duration 持续时间, 时间差
    3 LocalDate 只包含日期,比如:2021-07-29
    4 LocalTime 只包含时间,比如: “15:24:05”
    5 LocalDateTime 包含日期和时间,比如: “2021-07-29 15:24:05”
    6 Period 时间段
    7 ZoneOffset 时区偏移量,比如 : “+8:00”
    8 ZoneDateTime 带时区的时间
    9 Clock 时钟,比如获取当前北京时间
    10 DateTimeFormatter 时间格式化
    1、Instant类
    Java 8中以Instant类定义为从起点开始的偏移量,起点为格林威治时间(GMT)1970-01-01:00:00(可以理解为Instant类取代了Date类),可以进行时间戳和日期时间的互相转换。Instant.now().toEpochMilli()函数和System.currentTimeMillis()函数效果类似
    示例代码如下:
            System.out.println(" Instant.now() : " + Instant.now()); //当前时间
            System.out.println(" Instant.now().toEpochMilli() : " +           Instant.now().toEpochMilli()); //当前时间的毫秒数
            System.out.println(" System.currentTimeMillis() : " + System.currentTimeMillis());   //当前时间的毫秒数
            System.out.println(" Instant.now().getEpochSecond() : " + Instant.now().getEpochSecond()); //当前时间的秒数
    
    执行结果如下:
     Instant.now() : 2021-07-31T07:19:38.056Z
     Instant.now().toEpochMilli() : 1627715978222
     System.currentTimeMillis() : 1627715978222
     Instant.now().getEpochSecond() : 1627715978
    
    1.1 获取当前时间的时间戳方法(毫秒)如下:
    1) Instant.now().toEpochMilli()函数;
    2) System.currentTimeMillis()函数;
    1.2 获取当前时间的时间戳方法(秒)如下:
    1) Instant.now().getEpochSecond();
    1.3 时间戳和指定格式时间日期的转换:
    1) 第一种方式如下:
        //从1970-01-01T00:00:00Z的纪元中使用毫秒获得Instant的实例。
    Instant instant = Instant.ofEpochMilli(1545195386715L);
    ZoneId zone = ZoneId.systemDefault(); //获取系统的默认时区   
        //方法从Instant和区域ID获取LocalDateTime的实例。
    LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zone);
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String dateStr1 = dateTimeFormatter.format(localDateTime);
    System.out.println("dateStr1 : " + dateStr1);
    
    2) 第二种方式如下:
    Instant instant = Instant.ofEpochMilli(1545195386715L);
    ZonedDateTime zdt = instant.atZone(ZoneId.systemDefault());
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    String dateStr2 = zdt.format(dateTimeFormatter);
    System.out.println("dateStr2 : " + dateStr2);
    
    执行结果如下:
    dateStr1 : 2018-12-19 12:56:26
    dateStr2 : 2018-12-19 12:56:26
    
    2、Duration 持续时间,时间差
    此类以秒和纳秒为单位对数量或时间进行建模。我们可以使用between()方法比较两个时间的时间差
    下面分别采用LocalTime和Instant的方式,示例如下:
    LocalTime start = LocalTime.of(3, 20, 25, 1024);
    LocalTime end = LocalTime.of(3, 22, 27, 1544);
    long timeBetweenS =  Duration.between(start, end).getSeconds();
    long timeBetweenN =  Duration.between(start, end).getNano();
    System.out.println(" timeBetweenS : " + timeBetweenS);
    System.out.println(" timeBetweenN : " + timeBetweenN);
    
    Instant startInstant = Instant.parse("2021-07-29T17:30:30.00Z");
    Instant endInstant = Instant.parse("2021-07-29T17:33:35.00Z");
    long timeBetweenIS =  Duration.between(startInstant, endInstant).getSeconds();
    long timeBetweenIN =  Duration.between(start, end).getNano();
    System.out.println(" timeBetweenIS : " + timeBetweenIS);
    System.out.println(" timeBetweenIN : " + timeBetweenIN);
    
    执行结果如下:
     timeBetweenS : 122
     timeBetweenN : 520
     timeBetweenIS : 185
     timeBetweenIN : 520
    
    3、LocalDate
    1) LocalDate用来表示日期(但不包括时间),例如当前日期可用LocalDate.now(),示例如下:
    LocalDate today = LocalDate.now();
    System.out.println("今天日期是 : " + today);
    
    执行结果如下:
    今天日期是 : 2021-07-31
    
    2) LocalDate不仅可以获取当前日期,也可以获取特定的日期,并设定对应的日期格式,示例如下:
    LocalDate localDate = LocalDate.of(2021,7,29);
    DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
    String dateStr = localDate.format(dateTimeFormatter);
    String dateStr1 = dateTimeFormatter.format(localDate);
    System.out.println("dateStr : " + dateStr);
    System.out.println("dateStr1 : " + dateStr1);
    
    执行结果如下:
    dateStr : 2021-07-29
    dateStr1 : 2021-07-29
    
    3) 获取年月日信息
    获取所在的年份 : LocalDate.now().getYear();
    获取所在的月份 : LocalDate.now().getMonthValue();
    获取所在的天 : LocalDate.now().getDayOfMonth();
    4) 判断两个日期是否相当
    例如: LocalDate.now().equals(LocalDate.of(2021,7,29))
    5) 日期的增减
    例如日期往后推一周: LocalDate.now().plus(1, ChronoUnit.WEEKS);
    6) 检查像生日这种周期性事件,示例如下:
    LocalDate today = LocalDate.now();
    LocalDate dateDay = LocalDate.of(2021,7,15);
    MonthDay birthday = MonthDay.of(dateDay.getMonth(),dateDay.getDayOfMonth());
    MonthDay currentMonthDay = MonthDay.from(today);
    
    LocalDate.now().plus(1, ChronoUnit.WEEKS);
    System.out.println("一周后的时间是 : " + LocalDate.now().plus(1, ChronoUnit.WEEKS));
    if(currentMonthDay.equals(birthday)){
       System.out.println("是你的生日");
    }else if(currentMonthDay.isBefore(birthday)){
       System.out.println("你的生日还没有到");
    }else {
       System.out.println("你的生日已经过了");
    }
    
    执行结果如下:
    一周后的时间是 : 2021-08-07
    你的生日已经过了
    
    7) 检查闰年
    LocalDate中的isLeapYear()函数用来表示是否是闰年,示例如下:
    LocalDate today = LocalDate.now();
    if(today.isLeapYear()) { //判断是否是闰年
    System.out.println("This year is Leap year !");
    } else {
    System.out.println("This year is not Leap year !");
    }
    
    执行结果如下:
    This year is not Leap year !
    
    4、LocalTime
    LocalTime函数用来表示时间(但不包括日期),用法类似于3.
    5、LocalDateTime
    LocalDateTime用来表示日期和时间,用法亦类似于3.
    6、Period
    Period是ISO-8601日历系统中基于日期的时间量,例如“2年、3个月和4天”。此类以年、月和日为单位对数量和时间进行建模。
    1) 使用between()方法获取两个日期之间的差作为Period 对象,isNegative()方法判断日期的先后,任何一个时间如果是负数,则isNegative()方法返回true,因此可以用于判断endDate是否大于startDate
    LocalDate startDate = LocalDate.of(2015, 2, 20);
    LocalDate endDate = LocalDate.of(2017, 1, 15);
    Period period = Period.between(startDate, endDate);
    System.out.println("startDate晚于endDate : " + period.isNegative());
    
    执行结果如下:
    startDate晚于endDate : false
    
    2) Period类通过解析文本序列来创建Period,其格式为“PnYnMnD”,示例如下:
    Period fromCharYears = Period.parse("P2Y3M5D");
    int years = fromCharYears.getYears();
    int months = fromCharYears.getMonths();
    int days = fromCharYears.getDays();
    System.out.println("years : " + years +
    " months : " + months + " days : " + days);
    
    执行结果如下:
    years : 2 months : 3 days : 5
    
    7、ZoneId 指定时区的标识符
    ZoneId类的主要方法如下表7.1所示:
    方法 描述
    String getDisplayName(TextStyle style,Locale locale) 用于获取区域的文本表示形式,例如“北京时间”或者"+08:00"
    abstract String getId() 用于获取唯一的时区ID
    static ZoneId of(String zoneId) 用于从ID中获取ZoneId的实例, 以确保该ID有效并可供使用
    static ZoneId systemDefault() 用于获取系统默认时区
    boolean equals(Object obj) 用于检查该时区ID是否等于另一个时区ID
    1) getDisplayName函数,用于获取区域的文本表示形式,代码如下:
    public class TestMain {
        public static void main(String[] args) {
            ZoneId z = ZoneId.systemDefault();
            System.out.println(z.getDisplayName(TextStyle.FULL, Locale.ROOT));
        }
    }
    
    代码执行结果如下所示:
    China Time
    
    2) getId函数,用于获取唯一的时区ID,代码如下:
    public class TestMain {
        public static void main(String[] args) throws ParseException {
            ZoneId z = ZoneId.systemDefault();
            String s = z.getId();
            System.out.println("时区ID为 : " + s);
        }
    }
    
    结果是:
    时区ID为 : Asia/Shanghai
    
    冷知识了解:
    DST:Daylight Saving Time 中文称作“夏令时”,夏季天亮的早,将时间调快一小时。我国1986-1991年实行夏令时,于1992年废除。
    CST:China Standard Time 中国标准时。
    GMT:Greenwich Mean Time,格林威治标准时,地球每15°经度 被分为一个时区,全球共分为24个时区,相邻时区相差一小时;例: 中国北京位于东八区。
    Java8中已做调整,因此在1986-1991时间段不再存在时间差的问题,Java8之前的还存在此问题,例如:
        public static void main(String[] args) throws ParseException {
            DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern ("yyyy-MM-dd HH:mm:ss");
            ZoneId zA = ZoneId.of("Asia/Shanghai");
            LocalDateTime localDateTimeA = LocalDateTime.of(1988,7,15,15,15,15);
            ZonedDateTime zonedDateTimeA = localDateTimeA.atZone(zA);
            String dateStrA = zonedDateTimeA.format(dateTimeFormatter);
            System.out.println("dateStrA  " + dateStrA);
    
            ZoneId zG = ZoneId.of("GMT+8");
            LocalDateTime localDateTimeG = LocalDateTime.of(1988,7,15,15,15,15);
            ZonedDateTime zonedDateTimeG = localDateTimeG.atZone(zG);
            String dateStrG = zonedDateTimeG.format(dateTimeFormatter);
            System.out.println("dateStrG  " + dateStrG);
    
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            Date dateA88 = sdf.parse("1988-07-15 15:15:15");
            System.out.println("dateA88 = " + dateA88.toString());
    
            sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            Date dateG88 = sdf.parse("1988-07-15 15:15:15");
            System.out.println("dateG88 = " + dateG88.toString());
    
            sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
            Date dateA92 = sdf.parse("1992-07-15 15:15:15");
            System.out.println("dateA92 = " + dateA92.toString());
    
            sdf.setTimeZone(TimeZone.getTimeZone("GMT+8"));
            Date dateG92 = sdf.parse("1992-07-15 15:15:15");
            System.out.println("dateG92 = " + dateG92.toString());
        }
    
    结果如下:
    dateStrA  1988-07-15 15:15:15
    dateStrG  1988-07-15 15:15:15
    dateA88 = Fri Jul 15 15:15:15 CDT 1988
    dateG88 = Fri Jul 15 16:15:15 CDT 1988
    dateA92 = Wed Jul 15 15:15:15 CST 1992
    dateG92 = Wed Jul 15 15:15:15 CST 1992
    
    3) of函数,用于从ID中获取ZoneId的实例,以确保该ID有效并可供使用
    示例代码如下:
            ZoneId zoneS = ZoneId.of("Asia/Shanghai");
            ZoneId zoneC = ZoneId.of("Asia/Chongqing");
            ZoneId zoneH = ZoneId.of("Hongkong");
            LocalTime TimeS = LocalTime.now(zoneS);
            LocalTime TimeC = LocalTime.now(zoneC);
            LocalTime TimeH = LocalTime.now(zoneH);
            System.out.println("TimeS : " + TimeS);
            System.out.println("TimeC : " + TimeC);
            System.out.println("TimeH : " + TimeH);
            System.out.println("TimeS.isBefore(TimeC) : " + TimeS.isBefore(TimeC));
    
    结果如下所示:
    TimeS : 10:55:36.851
    TimeC : 10:55:36.851
    TimeH : 10:55:36.851
    TimeS.isBefore(TimeC) : false
    
    4) systemDefault函数,用于获取系统默认时区
    示例代码如下:
            ZoneId zone = ZoneId.systemDefault();
            System.out.println("zone : " + zone);
    
    结果如下所示:
            zone : Asia/Shanghai
    
    5) ZoneOffset 指定格林威治/ UTC 时间的时区偏移量
    示例代码如下,检索出亚洲东八区,字母以H开头的时区:
        public static void main(String[] args) throws ParseException {
            // 获取所有可用的时区
            Set<String> allZones = ZoneId.getAvailableZoneIds();
            // 按自然顺序排序 Create a List using the set of zones and sort it.
            List<String> zoneList = new ArrayList<String>(allZones);
            Collections.sort(zoneList);
            LocalDateTime dt = LocalDateTime.now();
            for (String s : zoneList) {
                // 获取到的字符串可以通过ZoneId.of获取实例
                ZoneId zone = ZoneId.of(s);
                // 把本地时间加时区信息 转换成一个ZonedDateTime
                // 但是这个LocalDateTime不包含时区信息,是怎么计算出来的呢?本地时间与这个时区相差n小时?
                // 这里的偏移量是针对格林威治标准时间来说的 +3 ,就是比标准时间快3个小时
                // 如果说一个时区是 +5;而北京是+8,那么该时区比北京慢3个小时
                // 北京时间是12点,那么该时区12-3 = 9
                ZonedDateTime zdt = dt.atZone(zone);
                ZoneOffset offset = zdt.getOffset();
                if(!zone.getId().contains("Asia/H")){
                    continue;
                }
                if(offset.getTotalSeconds() <= 0){
                    continue;
                }
                int hour = offset.getTotalSeconds() / (60 * 60);
                String out = String.format("%35s %10s%n", zone, offset);
    
                if (hour == 8) { //筛选出东八区的时区
                    System.out.printf(out);
                }
            }
        }
    
    执行结果如下:
        Asia/Harbin     +08:00
        Asia/Hong_Kong     +08:00
    
    8、ZoneDateTime 带时区的时间类
    ZoneDateTime 类用于创建带有时区的时间,可以用于表示一个真实时间的开始时间,比如火箭升空的时间等
    示例代码如下:
        public static void main(String[] args) throws ParseException {
            ZonedDateTime paris = ZonedDateTime.now(ZoneId.of("Europe/Paris")); // 欧洲巴黎 +2 时区
            ZonedDateTime shanghai = ZonedDateTime.now(ZoneId.of("Asia/Shanghai")); // 亚洲上海 +8 时区
            System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(paris));
            System.out.println("paris.getOffset() : " + paris.getOffset());
            System.out.println("shanghai.getOffset() : " + shanghai.getOffset());
            System.out.println(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(paris));
            System.out.println(DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(shanghai));
        }
    
    执行结果如下:
    paris.getOffset() : +02:00
    shanghai.getOffset() : +08:00
    2021-07-30T07:58:26.666+02:00
    2021-07-30T13:58:26.683+08:00
    
    9、Clock 时钟类
    Clock类用于获取指定时区的日期、时间和时间戳。该类提供了大量的方法获取对应的日期和时间
    示例代码如下:
        public static void main(String[] args) throws ParseException {
            Clock clock = Clock.system(ZoneId.ofOffset("UTC",ZoneOffset.of("+8")));
            Instant instant = clock.instant();
            ZoneId zoneId = ZoneId.ofOffset("UTC",ZoneOffset.of("+8"));
            LocalDateTime localDateTime1 = LocalDateTime.now(clock);
            LocalDateTime localDateTime2 = LocalDateTime.ofInstant(instant,zoneId);
    
            System.out.println("localDateTime1 : " + localDateTime1);
            System.out.println("localDateTime2 : " + localDateTime2);
            System.out.println("clock.millis() : " + clock.millis());
            System.out.println("System.currentTimeMillis() : " + System.currentTimeMillis());
        }
    
    执行结果如下:
    localDateTime1 : 2021-07-30T15:30:45.781
    localDateTime2 : 2021-07-30T15:30:45.769
    clock.millis() : 1627630245782
    System.currentTimeMillis() : 1627630245782
    
    10、DateTimeFormatter 时间格式化类
    DateTimeFormatter类是final类的,即是不变对象,且是线程安全的(SimpleDateFormat类不是线程安全的)
    DateTimeFormatter类提供了时间格式化的类型,即按照指定的格式或jdk默认的格式转换时间类型。
    当用来转换Instant类型的时间时,因为Instant类型不带有时区信息,需要在DateTimeFormatter类中加上时区的信息
    代码示例如下:
        public static void main(String[] args) throws ParseException {
            Instant localDateTime = Instant.now();
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
                    .withZone(ZoneId.systemDefault()); //设定默认的时区信息
            OffsetDateTime offsetDateTime =  localDateTime.atOffset(ZoneOffset.of("+8"));
            ZonedDateTime zonedDateTime = offsetDateTime.toZonedDateTime();// 函数封装有默认时区
            ZonedDateTime zonedDateTime2 = localDateTime.atZone(ZoneId.ofOffset("UTC",ZoneOffset.of("+8")));
            System.out.println("ocalDateTime format : " + formatter.format(localDateTime));
            System.out.println("zonedDateTime format : " + zonedDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            System.out.println("zonedDateTime2 format : " + zonedDateTime2.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
            System.out.println("offsetDateTime format : " + offsetDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        }
    
    执行结果如下:
    localDateTime format : 2021-07-31 15:05:41
    zonedDateTime format : 2021-07-31 15:05:41
    zonedDateTime2 format : 2021-07-31 15:05:41
    offsetDateTime format : 2021-07-31 15:05:41
    
  • 相关阅读:
    数据库设计规则
    了解何时使用 Override 和 New 关键字(C# 编程指南)
    Why we use stored procedure than Sql statement?
    HTML条件注释和javascript条件注释
    <%# %> 和 <% %> 有什么区别?
    short s1 = 1; s1 = s1 + 1;有什么错? short s1 = 1; s1 += 1;有什么错?
    如何实现 Visual Studio 2005 中远程调试
    认识延迟时间为0的setTimeout(转)
    Web应用程序中(VS2005+SP1)添加App_Code
    AWStats 一个不错的Web/Mail/FTP日志分析工具
  • 原文地址:https://www.cnblogs.com/ITBlock/p/15084616.html
Copyright © 2020-2023  润新知