首先看一下time包,里面有几个子包和各种日期时间类。一一开始学习。
该类是绝对时间,即国际标准时间(UTC时间),世界时间(就类似于整个中国都用的是北京时间一样),UTC时间就是整个世界用的标准时间。此时北京时间2019-09-25T10:37:58.553,而国际时间为2019-09-25T02:37:58.375Z。理解了instant类的含义,开始下一步学习。
Instant具体为时间点,某个时刻。时间点在时间线上。时间线有三个重要时间点(最大值,最小值,原点)。
System.out.println(Instant.EPOCH);//时间原点
System.out.println(Instant.MAX);//最大值
System.out.println(Instant.MIN);//最小值
Instant可以精确到纳秒,查看Instant源码可知,内部有着两个常量。seconds表示从1970-01-01 00:00:00开始到现在的秒数,用long类型存储,nanos表示纳秒部分(nanos的值不会超过999,999,999),用int类型存储。
Instant实例获取方式有多种:
这里介绍先两个方法
//获得当前时间点
Instant start = Instant.now();
System.out.println(start);
打印结果:
此时北京时间是09-25-11:11。
Instant time = Instant.ofEpochSecond(10000000, 10000);
System.out.println(time);
得到的是距离时间原点10000000秒10000纳秒的时间点
打印结果如下:
//获得当前时间点
Instant start = Instant.now();
System.out.println(start);
//获得增加两分钟的时间点
Instant start1 = start.plusSeconds(120);
System.out.println(start1);
打印结果:
Instant类就简单了解到这步,后面有需要的再从API中学习了解。
上面在算术运算中提及了Duration类,这里来学习一下。
Duration:时间段。Duration的内部实现与Instant类似,也是包含两部分:seconds表示秒(long类型),nanos表示纳秒(int)。两者的区别是Instant用于表示一个时间戳(或者说是一个时间点),而Duration表示一个时间段,所以Duration类中不包含now()静态方法。
可以通过Duration.between()方法创建Duration对象:
//获得当前时间点
Instant start = Instant.now();
System.out.println(start);
//获得增加两分钟的时间点
Instant start1 = start.plusSeconds(120);
System.out.println(start1);
Duration btime = Duration.between(start, start1);// 表示从 start1 到 start 这段时间
long days = btime.toDays(); // 这段时间的小时数
long hours = btime.toHours(); // 这段时间的小时数
long minutes = btime.toMinutes(); // 这段时间的分钟数
long seconds = btime.getSeconds(); // 这段时间的秒数
long milliSeconds = btime.toMillis(); // 这段时间的毫秒数
long nanoSeconds = btime.toNanos(); // 这段时间的纳秒数
也可通过of()方法创建一个时间段。
Duration duration1 = Duration.of(5, ChronoUnit.DAYS); // 5天
Duration duration2 = Duration.of(1000, ChronoUnit.MILLIS); // 1000毫秒
现在我们从UTC时间来到当地时间,在中国自然就是北京时间,在其他地区就是其他地区的时间。LocalDate是日期类,只有日期(年月日)不含具体时间
now()方法,of()方法
//获取当天日期
LocalDate today = LocalDate.now();
System.out.println("今天日期:"+today);
//获取当前年月日
int year = today.getYear();
int month = today.getMonthValue();
int day = today.getDayOfMonth();
System.out.println("年份:"+year+",月份:"+month+",日:"+day);
//获取特定日期
LocalDate myBirthday = LocalDate.of(1996, 5, 28);
LocalDate myBirthday1 = LocalDate.of(1996, Month.APRIL, 10);
System.out.println("生日:"+myBirthday);
System.out.println("生日:"+myBirthday1);
//检查两个日期是否想等
LocalDate date1 = LocalDate.of(2019, 9, 24);
if(date1.equals(today)){
System.out.println("是同一天");
}
//如何获取一周之后日期(增加日,周,月)
LocalDate nextWeek = today.plus(1, ChronoUnit.WEEKS);//1可以量化为几周
LocalDate nextWeek1 = today.plusYears(1);
System.out.println("next week is :"+nextWeek);
System.out.println("next year is :"+nextWeek1);
//判断某个日期在另外一个日期前还是后
LocalDate tomorrow = LocalDate.of(2019, 9, 25);
if(tomorrow.isAfter(today)){
System.out.println("明天在今天之后");
}
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
if(yesterday.isBefore(today)){
System.out.println("昨日在今天之前");
}
//检查是否是闰年
if(today.isLeapYear()){
System.out.println("今年是闰年");
}else {
System.out.println("今年不是闰年");
}
YearMonth类只展示日期的年月,不含日
//如何表示固定日期,
YearMonth currentYearMonth = YearMonth.now();
System.out.printf("Days in month year %s: %d%n", currentYearMonth, currentYearMonth.lengthOfMonth());
YearMonth creditCardExpiry = YearMonth.of(2019, Month.FEBRUARY);
System.out.printf("Your credit card expires on %s %n", creditCardExpiry);
运行结果:
前面有只有年月,现在MonthDay类就是只有月日,没有年的
//如何检查重复事件,比如生日
//使用MonthDay类。这个类由月日组合,不包含年信息
LocalDate dateOfBirth = LocalDate.of(1996, 5, 28);
MonthDay birthday = MonthDay.of(dateOfBirth.getMonth(),dateOfBirth.getDayOfMonth());
MonthDay currentMonthDay = MonthDay.from(today);
System.out.println("birthday"+birthday);
System.out.println("currentMonthDay"+currentMonthDay);
if(currentMonthDay.equals(birthday)){
System.out.println("Many Many happy returns of the day !!");
}else{
System.out.println("Sorry, today is not your birthday");
}
这个类以年,月和日为单位建立数量或时间量。 请参阅Duration的等效于此类的时间。
//两个日期之间包含多少个月,多少个日,多少年java.time.Period
LocalDate testDate = LocalDate.of(1996, 5, 28);
Period period = Period.between(testDate,today);
System.out.println("出生年数:"+period.getYears()+",出生月数:"+period.getMonths()+",出生日数:"+period.getDays());
打印结果如下:
可以看到在月份和日数上返回的是相对差。此时是2019年9月25日,比较是时间是1996年5月28日。返回的年数没问题,月数是相对差:3月,日子是相对差28(先过完3天5月结束,然后到25号,共28天)。那么我们怎么获得真正的月数和日数?
这时候需要使用LocalDate中的util方法处理。
System.out.println("年:"+testDate.until(today, ChronoUnit.YEARS)+",月:"+testDate.until(today, ChronoUnit.MONTHS)
+",周:"+testDate.until(today, ChronoUnit.WEEKS)+",日:"+testDate.until(today, ChronoUnit.DAYS));
打印结果如下:
前面讨论的是日期,现在讨论一下时间
//获取当前时间 具有毫秒值
LocalTime time =LocalTime.now();
System.out.println("当前时间"+time);
//获取当前时间 没有毫秒值
LocalTime time1 =LocalTime.now().withNano(0);
System.out.println("当前时间"+time1);
//如何增加时间的时分秒数
LocalTime newTimeHour = time.plusHours(2).withNano(0);
LocalTime newTimeMin = time.plusMinutes(120).withNano(0);
LocalTime newTimeSecond = time.plusSeconds(7200).withNano(0);
System.out.println("增加2小时"+newTimeHour);
System.out.println("增加120分钟"+newTimeMin);
System.out.println("增加7200秒"+newTimeSecond);
完整的时间:包括年月日+时间
//当前完整的时间
LocalDateTime localDateTime1 = LocalDateTime.now();
System.out.println(localDateTime1);
//去掉毫秒数
LocalDateTime localDateTime2 = LocalDateTime.now().withNano(0);
System.out.println(localDateTime2);
日期调整类。在行程安排上,经常会出现这样的案例,“每月的第一个星期二”。TemporalAdjusters类提供了大量用于常见调整的静态方法。
//TemporalAdjusters
//获取这个月第二个周末的日期
System.out.println(today.with(TemporalAdjusters.dayOfWeekInMonth(2,DayOfWeek.SUNDAY)));
//获取上个月最后一周
System.out.println(today.with(TemporalAdjusters.dayOfWeekInMonth(0,DayOfWeek.SUNDAY)));
//获取这个月的倒数第一个周末的时间
System.out.println(today.with(TemporalAdjusters.dayOfWeekInMonth(-1,DayOfWeek.SUNDAY)));
//明年的第一天
System.out.println(today.with(TemporalAdjusters.firstDayOfNextYear()));
//获取接下来的一个周5的时间
System.out.println(today.with(TemporalAdjusters.next(DayOfWeek.FRIDAY)));
// 获取本月最后一天
System.out.println(today.with(TemporalAdjusters.lastDayOfMonth()));
还可以通过实现TemporalAdjusters类实现自己的调整器
// 参数默认localdate
TemporalAdjuster next = TemporalAdjusters.ofDateAdjuster(
tdate->{
DayOfWeek work = tdate.getDayOfWeek();
int addDays=0;
if (work.equals(DayOfWeek.FRIDAY)) {
addDays=3;
}else if(work.equals(DayOfWeek.SATURDAY)){
addDays=2;
}else {
addDays=1;
}
return today.plusDays(addDays);
}
);
System.out.println("下个工作日为:"+today.with(next));
互联网编码分配管理机构(IANA)保存着一个数据库,里面保存着世界上所有已知时区。Java使用的是IANA数据库。
每个时区都有一个ID,例如America/New_York,Europe/Berlin。要想找到所有的时区ID,可以调用ZoneId.getAvailableZoneIds()方法。
给定一个时区ID,静态方法 ZoneId.of(String zoneId)可以产生一个ZoneId对象。可以通过调用local.atZone(zoneId)用这个对象将LocalDateTime对象转为ZonedDateTime对象,或者调用静态方法ZonedDateTime.of()来构造一个ZonedDateTime对象。
//处理不同时区
ZoneId america = ZoneId.of("America/New_York");
LocalDateTime localDateTime = LocalDateTime.of(2019, 9, 24, 16, 14);
ZonedDateTime dateAndTimeInNewYork = ZonedDateTime.of(localDateTime, america );
System.out.println("不同时区"+dateAndTimeInNewYork);
纽约时刻:
时区涉及到夏令时(不太懂什么意思)
当夏令时开始时候,时钟要向前拨快一个小时,当你构建的时间正好落入这跳过去的一个小时内时:
ZonedDateTime skipTime =ZonedDateTime.of(LocalDate.of(2013, 3, 31),LocalTime.of(2, 30),ZoneId.of("Europe/Berlin"));
System.out.println(skipTime);
打印结果:
我希望构造的是2:30,但是我得到的却是3:30
反过来,当夏令时结束时候,时钟要往回拨慢一个小时,这样同一个本地时间就会出现两次。当你构建位于这个时间段的时间时,就会得到这两个时刻中较早的一个。
ZonedDateTime skipTime1 =ZonedDateTime.of(LocalDate.of(2013, 10, 27),LocalTime.of(2, 30),ZoneId.of("Europe/Berlin"));
System.out.println("skipTime1:"+skipTime1);
ZonedDateTime anHourLater = skipTime1.plusHours(1);
System.out.println("anHourLater:"+anHourLater);
打印结果:
两个打印值都是2:30。即一个小时后时间会具有相同的小时和分钟,但是时区偏移量发生变化。
你还需要在调整跨越夏令时边界日期时特别注意。例如你需要把会议放在下一周,不要加上7天的Duration,而应该用Period类。
看的迷迷糊糊的…
DateTimeFormatter类提供了三种用于打印日期/时间值的格式器:
String formatter1 = DateTimeFormatter.ISO_OFFSET_DATE.format(skipTime);
System.out.println(formatter1);
打印一下:
标准格式器是为了机器刻度的时间戳而设计的。我们常用的日期时间形式的使用Locale相关的格式器。
静态方法ofLocalizedDate() ofLocalizedDateTime() ofLocalizedDateTime()可以创建上述格式器
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
String formatter2 = dateTimeFormatter.format(localDateTime);
System.out.println(formatter2);
打印结果:
上述方法使用了默认的Locale,为了切换不同的Locale,可以使用withLocale方法
String formatter3 = dateTimeFormatter.withLocale(Locale.CHINA).format(localDateTime);
System.out.println(formatter3);
也可以通过制定模式来指定自己的日期格式
dateTimeFormatter = DateTimeFormatter.ofPattern("E yyyy-MM-dd HH:mm");
String formatter2 = dateTimeFormatter.format(localDateTime);
System.out.println(formatter2);
打印如下:
LocalDateTime dateTime = LocalDateTime.now();
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE); // 20190925
String strDate2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE); // 2019-09-25
String strDate3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME); // 17:11:12.145
String strDate4 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); // 2019-09-25
String strDate5 = dateTime.format(DateTimeFormatter.ofPattern("今天是:YYYY年 MMMM DD日 E", Locale.CHINESE)); // 今天是:2019年 九月 25日 星期三
String strDate6 = "2019-09-25";
String strDate7 = "2019-09-25 17:33:24";
LocalDate date = LocalDate.parse(strDate6, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime dateTime1 = LocalDateTime.parse(strDate7, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));