zoukankan      html  css  js  c++  java
  • Java基础-时间日期[2]

    java.time

    jdk引入新的时间体系:

    1. LocalDate只保留日期
    2. LocalTime只保留时间
    3. LocalDateTime同时保留时间和日期
    4. ZonedDateTime保留了时区、时间、日期
    5. Instant:是不带时区一个时时间点,与java.util.Date类似,但是精确到纳秒。
    @Test
    public void testJdk8Date() {
        System.out.println(LocalDate.now());
        System.out.println(LocalTime.now());
        System.out.println(ZonedDateTime.now());
        System.out.println(LocalDateTime.now());
        System.out.println(Instant.now());
        System.out.println(MinguoDate.now());
    }
    //2021-04-14
    //11:54:14.660177900
    //2021-04-14T11:54:14.661181200+08:00[Asia/Shanghai]
    //2021-04-14T11:54:14.661181200
    //2021-04-14T03:54:14.661181200Z
    //Minguo ROC 110-04-14
    
    

    从上面也可以看出Instant是无时区的,代表UTC的时间戳,Z在时区里面表示UTC

    LocalDate.now()

    public static LocalDate now() {
        return now(Clock.systemDefaultZone());
    }
    public static LocalDate now(Clock clock) {
        Objects.requireNonNull(clock, "clock");
        final Instant now = clock.instant();  // called once
        return ofInstant(now, clock.getZone());
    }
    public static LocalDate ofInstant(Instant instant, ZoneId zone) {
        Objects.requireNonNull(instant, "instant");
        Objects.requireNonNull(zone, "zone");
        ZoneRules rules = zone.getRules();
        ZoneOffset offset = rules.getOffset(instant);
        //计数utc和时区偏差后的总时间
        long localSecond = instant.getEpochSecond() + offset.getTotalSeconds();
        long localEpochDay = Math.floorDiv(localSecond, SECONDS_PER_DAY);
        return ofEpochDay(localEpochDay);
    }
    //此时这里处理的已经是加上时区偏差的时间了
    //如东八区: epochDay = utcSec + 8*60*60
    public static LocalDate ofEpochDay(long epochDay) {
        EPOCH_DAY.checkValidValue(epochDay);
        long zeroDay = epochDay + DAYS_0000_TO_1970;
        // find the march-based year
        zeroDay -= 60;  // adjust to 0000-03-01 so leap day is at end of four year cycle
        long adjust = 0;
        if (zeroDay < 0) {
            // adjust negative years to positive for calculation
            long adjustCycles = (zeroDay + 1) / DAYS_PER_CYCLE - 1;
            adjust = adjustCycles * 400;
            zeroDay += -adjustCycles * DAYS_PER_CYCLE;
        }
        long yearEst = (400 * zeroDay + 591) / DAYS_PER_CYCLE;
        long doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
        if (doyEst < 0) {
            // fix estimate
            yearEst--;
            doyEst = zeroDay - (365 * yearEst + yearEst / 4 - yearEst / 100 + yearEst / 400);
        }
        yearEst += adjust;  // reset any negative year
        int marchDoy0 = (int) doyEst;
    
        // convert march-based values back to january-based
        int marchMonth0 = (marchDoy0 * 5 + 2) / 153;
        int month = (marchMonth0 + 2) % 12 + 1;
        int dom = marchDoy0 - (marchMonth0 * 306 + 5) / 10 + 1;
        yearEst += marchMonth0 / 10;
    
        // check year now we are certain it is correct
        int year = YEAR.checkValidIntValue(yearEst);
        return new LocalDate(year, month, dom);
    }
    private LocalDate(int year, int month, int dayOfMonth) {
        this.year = year;
        this.month = (short) month;
        this.day = (short) dayOfMonth;
    }
    

    最后LocalDate(int year, int month, int dayOfMonth) 完全和时区没有关系,只保存了所在时区应该显示的年月日,简单理解就是时间的字符串

    LocalDateTime转时间戳

    1. ZoneId:表示时间对应的时区,常见的是:区域/ 城市,如Asia/Shanghai,Asia/Tokyo
    2. ZoneOffset:ZoneId的子类,使用时间偏移量表示
    @Test
    public void testZone() {
        System.out.println(ZoneId.systemDefault());
        System.out.println(ZoneId.of("Asia/Shanghai"));
        System.out.println(ZoneId.of("Asia/Hong_Kong"));
        System.out.println(ZoneOffset.UTC);
        System.out.println(ZoneId.of("Z"));
        System.out.println(ZoneId.of("+8"));
        System.out.println(ZoneId.of("UTC+8"));
        System.out.println(ZoneId.ofOffset("UTC",ZoneOffset.ofHours(8)));
        //具体见方法注释
        System.out.println(ZoneOffset.of("+08:30:20"));
    }
    //Asia/Shanghai
    //Asia/Shanghai
    //Asia/Hong_Kong
    //Z
    //Z
    //+08:00
    //UTC+08:00
    //UTC+08:00
    //2021-04-14T06:47:58.587
    //2021-04-14T13:47:58.587
    

    ZoneDateTime

    ZoneDateTime在LocalDateTime的基础上增加了时区的概念,这样可以将同一个时间转换成不同时区的格式显示

    @Test
    public void testDateStr (){
        LocalDateTime leaving = LocalDateTime.of(2020, 6, 29, 19, 30);
        //这里也是2020/06/29 19:30:00,但是有了时区的概念,是上海时区的2020/06/29 19:30:00
        //而上面的LocalDateTime可以理解为只是一个时间字符串
        ZonedDateTime shanghaiTime = leaving.atZone(ZoneId.of("Asia/Shanghai"));
        System.out.println(shanghaiTime);
        //这里把上海时间加上半小时后,转化为了东京时间,东京时间与上海时间相差1个小时
        //所以这里显示的字符串是2020-06-29T21:00+09:00[Asia/Tokyo]
        ZonedDateTime tokyoTime = shanghaiTime.plusMinutes(30).withZoneSameInstant(ZoneId.of("Asia/Tokyo"));
        System.out.println(tokyoTime);
    }
    

    理解LocalDateTime的无时区性

    @Test
    public void testLocalDtToIne (){
        long defaultZoneDt = LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        long utcZoneDt = LocalDateTime.now().atZone(ZoneOffset.UTC).toInstant().toEpochMilli();
        System.out.println(defaultZoneDt);
        System.out.println(utcZoneDt);
        System.out.println(FgDateUtils.millsToDateTime(defaultZoneDt));
        System.out.println(FgDateUtils.millsToDateTime(utcZoneDt));
    }
    1618383299634
    1618412099635
    2021-04-14 14:54:59
    2021-04-14 22:54:59
    

    实际当前时间是上海时间2021-04-14 14:54:59

    LocalDateTime.now()只是简单的字符串,在初始化的过程,已经将utc的时间搓,转换为当前时区的年月日,所以取名也有Local。

    .atZone()则是将前面得到的时间字符串赋予时区,即让程序理解2021-04-14 14:54:59是那个时区的时间,如果理解为UTC的时间,那么对应上海时间还要在加上8个小时,也就是2021-04-14 22:54:59

    封装的工具类

    /**
    * @author froggengo@qq.com
    * @date 2021/4/14 9:30.
    */
    public class FgTimeUtils {
    
       //时间搓转日期,mills为utc时间搓
       public static LocalDateTime millsToDateTime(long mills) {
           Instant instant = Instant.ofEpochMilli(mills);
           return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
       }
    
       //时间搓转日期
       public static LocalDateTime secToDateTime(int sec) {
           Instant instant = Instant.ofEpochSecond(sec);
           return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
       }
    
       /**
        * 字符串转时间搓,时间格式
        * yyyy-MM-dd HH:mm:ss
        * yyyy-MM-dd
        * yyyy-MM
        */
       public static LocalDateTime strToDateTime(String str) {
           Objects.requireNonNull(str);
           String dateStr;
           switch (str.length()) {
               case 19:
                   dateStr = str;
                   break;
               case 10:
                   dateStr = str + " 00:00:00";
                   break;
               case 7:
                   dateStr = str + "-01 00:00:00";
                   break;
               default:
                   throw new UnsupportedOperationException();
           }
           return LocalDateTime.parse(dateStr, DateTimeFormatter.ofPattern(FgDateUtils.YYYY_MM_DD_HH_MM_SS));
       }
    
       /**
        * localDatetime转时间搓(utc),时间搓均指utc+0时间
        */
       public static long dateTimeToMills(LocalDateTime dateTime) {
           return dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
       }
    
       /**
        * 字符串转时间搓,时间格式
        * yyyy-MM-dd HH:mm:ss
        * yyyy-MM-dd
        * yyyy-MM
        */
       public static long strToMills(String str) {
           Objects.requireNonNull(str);
           return dateTimeToMills(strToDateTime(str));
       }
    
       /**
        * 计算偏移量后当天时间0点ZoneDateTime
        * LocalDate的另一个方法会转成
        * LocalDate.now().atStartOfDay(ZoneId.systemDefault()
        */
       public static LocalDateTime startOfDayByOffset(int offset) {
           LocalDate now = LocalDate.now().plusDays(offset);
           return LocalDateTime.of(now, LocalTime.MIN);
       }
    
       /**
        * 计算偏移后当月第一天时间0点
        */
       public static LocalDateTime startOfMonthByOffset(int offset) {
           LocalDate now = LocalDate.now().plusMonths(offset);
           return LocalDateTime.of(now.with(TemporalAdjusters.firstDayOfMonth()), LocalTime.MIN);
       }
    
       /**
        * 将time包下的时间对象转成相应的字符串
        */
       public static <T extends Temporal> String formatTime(T time) {
           if (time instanceof LocalDateTime) {
               return ((LocalDateTime) time).format(DateTimeFormatter.ofPattern(FgDateUtils.YYYY_MM_DD_HH_MM_SS));
           } else if (time instanceof LocalDate) {
               return ((LocalDate) time).format(DateTimeFormatter.ofPattern(FgDateUtils.YYYY_MM_DD));
           } else if ((time instanceof LocalTime)) {
               return ((LocalTime) time).format(DateTimeFormatter.ofPattern(FgDateUtils.HH_MM_SS));
           } else if ((time instanceof ZonedDateTime)) {
               return ((ZonedDateTime) time).format(DateTimeFormatter.ofPattern(FgDateUtils.YYYY_MM_DD_HH_MM_SS));
           }
           throw new UnsupportedOperationException("only support LocalDateTime、LocalDate、LocalTime、ZonedDateTime");
       }
    
       public static String formatDate(LocalDateTime dateTime) {
           return dateTime.format(DateTimeFormatter.ofPattern(FgDateUtils.YYYY_MM_DD));
       }
    
       //    两个时间搓的时间差
       public static String duration(long max, long min) {
           Duration duration = Duration.ofMillis(max - min);
           return duration.toDaysPart() + "天" + duration.toHoursPart() + "小时" 
               + duration.toMinutesPart() + "分" + duration.toSecondsPart() + "秒";
       }
    }
    
  • 相关阅读:
    (转)关于IBM小机P520的面板使用
    (转)mysql的sql_mode合理设置
    (转)Mysql技术内幕InnoDB存储引擎-事务&备份&性能调优
    杨辉三角
    异或的陷阱(转)
    通过数组看栈堆
    数组的一些知识点和插入选择冒泡排序
    运算符
    Java的变量相关
    有符号的数据表示法(原、反、补)
  • 原文地址:https://www.cnblogs.com/froggengo/p/14659112.html
Copyright © 2011-2022 走看看