• Java> Java核心卷读书笔记


    总结

    时间点用Instant(如1ms , 1ns),
    时间段用Duration(如2个Instant对象所代表时间差),
    本地日期用LocalDate(如2020年12月1日),
    本地时间用LocalTime(如13时30分20秒),
    本地日期+时间用LocalDateTime = LocalDate + LocalTime(如2020年12月1日13时30分20秒),
    时区时间用ZonedDateTime(本地北京时间转化到纽约时间),
    输出时间不同格式用DateTimeFormatter,
    简单环境应用可以使用SimpleDateFormat(线程不安全),
    不同时区时间格式化输出用Locale切换。

    概要

    Java 1.0 Date
    简单
    Java 1.1 Calendar
    引入后,Date类大部分方法弃用。但实例易变,并且没有处理诸如闰秒这样的问题。
    Java 3.0 java.time
    修正了过去的缺陷

    时间线

    秒的来源
    最初,根据地球自转推导而来。地球自转一周24h = 24x60x60 = 86400s。缺陷:地球有轻微颤动,1秒定义不精确。
    1967年以来,原子钟网络被当作官方时间:根据铯133原子内在特性推导而来。
    绝对时间与地球同步自转进行同步,官方时间的秒需要稍作调整,从1972年开始,偶尔需要插入“闰秒”。
    Java的Date和Time API规范要求Java使用的时间尺度为:

    • 每天86400秒
    • 每天正午与官方时间精确匹配
    • 在其他时间点上,以精确定义的方式与官方时间接近匹配

    Instant和Duration类

    Instant类

    Instant表示时间线上的某个点。
    “新纪元”时间线原点被设置为 穿过伦敦本初子午线所处时区的1970年1月1日的午夜,与UNIX/POSIX时间中使用的惯例相同。
    从“新纪元”时间线原点开始,时间按照每天86400秒向前或向回度量,精确到纳秒。Instant值可向回追溯10亿年(Instant.MIN) << 宇宙年龄(约135亿年),不过对所有实际应用来说,应该足够。最大值Instant.MAX是公元1 000 000 000年的12月31日。

    当前时间: Instant.now()
    Instant对象含义:时间戳
    比较2个Instant对象:equals和compareTo

    如何度量算法运行时间?

    Instant start = Instant.now();
    runAlgorithm();
    Instant end = Instant.now();
    Duration timeElapsed = Durtion.between(start, end);
    long millis = timeElapsed.toMillis();
    

    Duration类

    Duration是2个时刻之间的时间量。
    Duration按传统单位度量时间长度的常用方法

    toNanos // 转化纳秒
    toMillis // 转化为毫秒
    getSeconds // 转化为秒
    toMinutes // 转化为分钟
    toHours // 转化为小时
    toDays // 转化为天
    

    例子,如果想要检查某个算法是否比另外一个算法快10倍,可以这样做

    Duration timeElapse2 = Duration.between(start2, end2);
    boolean overTenTimeFaster = timeElapse.multipliedBy(10).minus(timeElapsed2).isNegative(); 
    // 等价于下面的语句
    overTenTimeFaster = timeElapsed.toNanos() * 10 < timeElapsed2.toNanos();
    


    注意: Instant和Duration都是不可修改的类,诸如mltipliedBy和minus都会返回一个新实例

    本地时间LocalDate

    Java中人类时间分为2种:本地时间,时区时间。
    本地时间包含日期和当天的时间,与时区没有任何关联。
    某些特殊情况下,时区可能回成为障碍。不推荐使用时区,除非先表达绝对时间。

    LocalDate类

    LocalDate是带有年、月、日的本地日期,可以用now或of方法构建LocalDate对象。
    java.util.Date使用从1900年0月开始计算(与Unix一致)

    • LocalDate对象创建方法
    LocalDate today = LocalDate.now(); // 今天的日期
    LocalDate alonzosBirthday = LocalDate.of(1903.6.14); // 以1903年6月14日构建LocalDate对象
    alnozosBirthday = LocalDay.of(1903, Mont.JUNE, 14); // 1903年6月14日
    
    • LocalDate常用方法
    方法 描述
    now, of 静态方法构建LocalDate对象,要么从当前时间构建,那么从给定年月日构建
    plusDays, plusWeeks, plusMonths, plusYears 在当前的LocalDate上加上一定量的天、星期、月或年
    minusDays, minusWeeks, minusMonths, minusYears 在当前的LocalDate上减去一定量的天、星期、月或年
    plus, minus 加上或减去一个Duration或Period
    withDayOfMont, withDayOfYear, withMonth, withYear 返回一个新的LocalDate,其月的日期、年的日期、月或年修改为给定的值
    getDayOfMonth 获取是一月的第几天(1~31)
    getDayOfYear 获取是一年的第几天(1~366)
    getDayOfWeek 获取星期几,返回DayOfWeek枚举值
    getMonth, getMonthValue 获取月份Month枚举值,或者1~12数字
    getYear 获取年份,-999 999 999 ~ 999 999 999之间
    until 获取Period,或者两个日期之间按照给定的ChrounoUnits计算的数值
    isBefore, isAfter 将当前LocalDate与另一个LocalDate进行比较
    isLeapYear 如果是闰年,返回true;否则返回false

    注意:闰年指年份能被4整除,但是不能被100整除;或者能被400整除。
    例子,程序员日是每年256天。计算方法:

    LocalDate programmersDay = LocalDate.of(2020, 1, 1).plusDays(255);
    

    日期间隔Period类

    2个时间点Instant间隔是Duration,2个本地日期LocalDate直接的间隔是什么呢?
    是Period,表示流逝的年、月或日的数量。
    利用Period计算日期,和LocalDate计算日期差异:例如,计算下一年生日

    LocalDate birthday = LocalDate.now();
    
    // 根据当前生日日期,计算明年生日日期3种方式
    birthday.plusYears(1); // 正确
    birthday.plusDays(365); // 错误,会有闰年问题
    birthday.plus(Period.ofYears(1)); // LocalDate日期对象 + Period所代表的日期间隔(时长)
    

    如何计算2个本地日期之间时长?

    LocalDate day1 = LocalDate.of(2015.1.1);
    LocalDate day2 = LocalDate.now();
    
    day1.until(day2); // 相隔5年11个月0天
    day1.until(day2, ChronoUnit.DAYS);// 计算具体相隔多少天
    

    异常情况:
    有些方法可能创建出并不存在的日期,如1月31+1个月,不会产生2月31日,也不会抛出异常,而是返回该月最后一天。
    例如,LocalDate.of(2016, 1, 31).plusMonths(1)LocalDate.of(2016, 3, 31).minusMonths(1)都将产生2016年2月29日

    日期调整器

    本地时刻LocalTime

    LocalTime表示当日时刻,如15:30:00。LocalTime默认24小时制,不关心AM/PM,交由格式器解决。
    LocalTime创建

    LocalTime rightNow = LocalTime.now();
    LocalTime bedtime = LocalTime.of(22, 30); // 或者LocalTime.of(22, 30, 0) 表示时间24小时制 22时30分00秒
    

    LocalTime常用方法

    方法 描述
    now, of 类方法,构建LocalTime对象。of方法从时分构建LocalTime对象,时分必选,秒、纳秒可选
    plusHour, plusMinutes, plusSeconds, plusNanos 在当前LocalTime + 一定量小时、分钟、秒、纳秒
    minusHour, minusMinutes, minusSeconds, minusNanos 在当前LocalTime - 一定量小时、分钟、秒、纳秒
    plus, minus 加上或减去一个Duration
    withHour, withMinute, withSecond, withNano 返回一个新LocalTime, 其小时、分钟、秒、纳秒修改为给定值
    getHour, getMinute, getSecond, getNano 获取当前LocalDate的小时、分钟、秒、纳秒
    toSecondOfDay, toNanoOfDay 返回午夜到当前秒或纳秒的数量
    isBefore, isAfter 将当前LocalTime与另外一个LocalTime进行比较

    LocalDateTime类

    适合存储固定时区的时间点,如排课或排程。如果需要跨不同时区,或者跨越夏令时,应该使用ZonedDateTime类。

    时区时间

    时区时间有什么用?
    在北京是17点44分,然而在纽约是4点44分,而在伦敦却是9点44分。在不同时区的人,如何约定好同一个时间举办一个会议? 这就需要用到时区时间ZonedDateTime类。
    互联网编码分配管理机构(IANAN)保存着一个数据库,里面存储着世界上所有已知的时区 IANAN官网,每年更新几次,批量更新会处理夏令时的变更规则。Java使用了IANAN数据库。

    时区ZonedDateTime类

    时区ID

    每个时区都有一个时区ID,例如Anmerica/New_York和Europe/Berlin。
    目前,全世界有进600个ID。

    • 找出所有可用时区
    ZoneId.getAvailableZoneIds()
    
    • 给定时区ID,构建ZondId对象
    ZoneId.of(id);
    
    • 将LocalDateTime对象转换为ZonedDateTime对象
      两种方法
    // 方法一
    LocalDate local = local.now();
    local.atZone(id);
    
    // 方法二
    ZonedDateTime.of(year, month, day, hour, minute, second, nano, zoneId);
    
    // e.g.
    ZonedDateTime apollolllaunch = ZonedDateTime.of(1969, 7, 16, 9, 32, 0, 0, ZoneId.of("America/New_York")); // 1969-07-16T09:32-04:00[America/New_York]
    // 获得Instant, ZonedDateTime -> Instant
    Instant instant = apollolllaunch.toInstant();
    // Instant -> ZonedDateTime
    instant.atZone(ZoneId.of("UTC")); // 获得格林威治皇家天文台的ZonedDateTime对象
    

    ZonedDateTime类

    ZonedDateTime许多方法与LocalDateTime类的相同,不过夏令时带来一些复杂性。


    夏令时

    夏令时,Daylight Saving Time,是一种节约能源而人为规定地方时间的制度,这一制度实行期间所采用的统一时间称为“夏令时”。一般在夏季人为将时间提前1小时,冬季又调回1小时,每个国家具体规定不同。
    夏令时开始时,时钟要向前拨快一小时。夏令时结束时,时钟要拨慢一小时。

    // e.g. 2013年, 中欧地区3月31日 2:00 切换到夏令时. 如果试图构建的时间是不存在的3月31日2:30,那么实际上得到的是3:30
    ZonedDateTime skipped = ZonedDateTime.of(
          LocalDate.of(2013, 3, 31),
          LocalTime.of(2, 30),
          ZoneId.of("Europe/Berlin")
    ); // 2013年3月31日 3:30
    
    // 夏令时结束时, 时钟要回拨慢一小时, 这样同一个本地时间就会有出现2次. 当构建位于这个时间段内的时间对象时, 会得到这2个时刻中较早的一个
    ZonedDateTime ambiguous = ZonedDateTime.of(
    LocalDate.of(2013, 10, 27),
    LocalTime.of(2, 30),
    ZoneId.of("Europe/Berlin")
    ); // 2013-10-27T02:30+02:00[Europe/Berlin]
    
    ZonedDateTime anHourLater = ambiguous.plusHours(1); // 2013-10-27T02:30+01:00[Europe/Berlin]
    
    // e.g 跨越夏令时边界事需要特别注意. 例如, 如果将会议设置在下个星期, 不要直接+7天Duration, 而应该使用Period类
    ZonedDateTime nextMeeting = meeting.plus(Duration.ofDays(7)); // 错误做法
    
    ZonedDateTime nextMeeting = meeting.plus(Period.ofDays(7)); // 正确做法
    

     
    注意:offsetDateTime类,UTSC具有偏移量的时间,没有时区规则限制,用于专用应用,如某些网络协议。人类时区时间应该使用ZonedDateTime。

    格式化和解析

    格式器DateTimeFormatter

    DateTimeFormatter类提供3种打印日期/时间值的格式器:

    • 预定义的格式器
    • Local相关的格式器
    • 带有定制模式的格式器

    注意:java.time.format.DateTimeFormatter类被设计用来替代java.util.DateFormat。如果为向后兼容需要使用后者,可以调用formatter.toFormat()。

    示例:使用标准的格式器,直接调用DateTimeFormatter.format方法

    ZonedDateTime apollolllaunch = ZonedDateTime.of(1969, 7, 16, 9, 32, 0, 0, ZoneId.of("America/New_York")); // 1969-07-16T09:32-04:00[America/New_York]
    
    String formatted = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(apollolllaunch ); // 1969-07-16T09:32:00-04:00
    System.out.println(formatted);
    

    标准格式器主要是为了机器刻度的时间戳而设计的,向人类表示日期和时间,可以使用Locale相关格式器。
    有4种与Locale相关的格式化风格:SHORT, MEDIUM, LONG, FULL.

    Locale格式化风格

    • 创建Locale相关格式化风格
    // 创建DateTimeFormatter
    DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
    // 使用默认Locale
    String formatted = formatter.format(apollolllaunch ); // 1969年7月16日 上午09时32分00秒
    System.out.println(formatted);
    
    // 使用withLocale, 切换到不同Locale
    formatted = formatter.withLocale(Locale.FRENCH).format(apollolllaunch ); // 16 juillet 1969 09:32:00 EDT
    
    // 按不同Locale和格式给出星期日期和月份名字
    for (DayOfWeek w: DayOfWeek.values()) {
          // 打印星期几的英文简称: Mon Tue Wed Thu Fri Sat Sun 
          System.out.print(w.getDisplayName(TextStyle.SHORT, Locale.ENGLISH) + " "); 
    }
    
  • 相关阅读:
    算法(一)—— 河内之塔(汉诺塔)
    JAVA爬取网页邮箱
    js中判断某字符串含有某字符出现的次数
    逻辑删除和物理删除的区别
    Forward和Redirect的区别
    Postman 传Map类型的参数
    Java基础
    【html-css】
    【HTML----】
    【python-while-以及字符串的相关操作和函数】
  • 原文地址:https://www.cnblogs.com/fortunely/p/14065877.html
Copyright © 2020-2023  润新知