时间规范每个国家或地区都不一致,实现起来困难较大,另外老版的JDK时间API没有很好的设计和规范,使用起来很复杂而且多线程时容易出现问题,JDK8提供一套更友好,有便捷安全的API。
LocalDate 、LocalTime 、LocalDateTime
LocalDate、LocalTime、LocalDateTime 类的实例是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。它们提供了简单的日期或时间,并不包含当前的时间信息。也不包含与时区相关的信息。
常用方法:
- now() 静态方法,根据当前时间创建对象
- LocalDate localDate = LocalDate.now();
- LocalTime localTime = LocalTime.now();
- LocalDateTime localDateTime = LocalDateTime.now();
- of() 静态方法,根据指定日期/时间创建对象
- LocalDate localDate = LocalDate.of(2016, 10, 26);
- LocalTime localTime = LocalTime.of(02, 22, 56);
- LocalDateTime localDateTime = LocalDateTime.of(2016, 10,26, 12, 10, 55);
- plusDays, plusWeeks,plusMonths, plusYears 向当前 LocalDate 对象添加几天、几周、几个月、几年
- minusDays, minusWeeks,minusMonths, minusYears 从当前 LocalDate 对象减去几天、几周、几个月、几年
- plus, minus 添加或减少一个 Duration 或 Period
- withDayOfMonth,withDayOfYear,withMonth,withYear将月份天数、年份天数、月份、年份修改为指定 的值 并返回新的LocalDate 对象
- getDayOfMonth 获得月份天数(1-31)
- getDayOfYear 获得年份天数(1-366)
- getDayOfWeek 获得星期几(返回一个 DayOfWeek枚举值)
- getMonth 获得月份, 返回一个 Month 枚举值
- getMonthValue 获得月份(1-12)
- getYear 获得年份
- until 获得两个日期之间的 Period 对象,或者指定 ChronoUnits 的数字
- isBefore, isAfter 比较两个 LocalDate
- isLeapYear 判断是否是闰年
ISO 8601 时间标准
国际标准ISO 8601是日期和时间的表示方法,全称为《数据存储和交换形式·信息交换·日期和时间的表示方法》,是一套全世界共认的时间表示标准。
- 年份:年由4位数组成,以公历公元1年为0001年,以公元前1年为0000年,公元前2年为-0001年,其他以此类推
- 月份:月为2位数,月中的日为2位数,例如2004年5月3日可写成2004-05-03或20040503。
- 星期或日期:可以用2位数表示年内第几个日历星期,再加上一位数表示日历星期内第几天,但日历星期前要加上一个大写字母W,如2004年5月3日可写成2004-W19-1或2004W191。但2005-W011是从2005年1月3日开始的,前几天属于上年的第53个日历星期。每个日历星期从星期一开始,星期日为第7天。
- 时间:小时、分和秒都用2位数表示,对UTC时间最后加一个大写字母Z,其他时区用实际时间加时差表示。如UTC时间下午2点30分5秒表示为14:30:05Z或143005Z,当时的北京时间表示为22:30:05+08:00或223005+0800,也可以简化成223005+08。
- 日期和时间组合:合并表示时,要在时间前面加一大写字母T,如要表示北京时间2004年5月3日下午5点30分8秒,可以写成2004-05-03T17:30:08+08:00或20040503T173008+08。
- 时间段:如果要表示某一作为一段时间的时间期间,前面加一大写字母P,但时间段后都要加上相应的代表时间的大写字母。如在一年三个月五天六小时七分三十秒内,可以写成P1Y3M5DT6H7M30S。
- 重复时间:前面加上一大写字母R,如要从2004年5月6日北京时间下午1点起重复半年零5天3小时,要重复3次,可以表示为R3/20040506T130000+08/P0Y6M5DT3H0M0S。对应的各地标准
来个示例: 2014-03-25T06:26:01.927Z
T和Z是不是看着很别扭?官方说明是某些极端情况下T和Z可以防止数据丢失(比空格要好很多),你不用纠结,人家就是规范,更重要的是,jdk8采用了这套规范,所以特此说明。
System.out.println("当前日期: " + LocalDate.now());
System.out.println("当前时间: " + LocalTime.now());
System.out.println("当前日期和时间: " + LocalDateTime.now());
//当前日期: 2019-12-07
//当前时间: 23:38:24.743
//当前日期和时间: 2019-12-07T23:38:24.743
//自定义时间
LocalDateTime dt = LocalDateTime.of(2019, 12, 7, 21, 21, 21, 11);
System.out.println(dt);//2019-12-07T21:21:21.000000011
System.out.println("年: " + dt.getYear());
System.out.println("月份 " + dt.getMonth());
System.out.println("月的数字 " + dt.getMonthValue());
System.out.println("本年第几天 " + dt.getDayOfYear());
System.out.println("本月几号 " + dt.getDayOfMonth());
System.out.println("星期几 " + dt.getDayOfWeek());
System.out.println("小时 " + dt.getHour());
System.out.println("分钟 " + dt.getMinute());
System.out.println("秒 " + dt.getSecond());
System.out.println("纳秒 " + dt.getNano());
//年: 2019
//月份 DECEMBER
//月的数字 12
//本年第几天 341
//本月几号 7
//星期几 SATURDAY
//小时 21
//分钟 21
//秒 21
//纳秒 11
//判断日期大小
boolean before = dt.isBefore(LocalDateTime.now());//之前
boolean after = dt.isAfter(LocalDateTime.now());//之后
System.out.println(before);//true
System.out.println(after);//false
//日期加减
LocalDateTime localDateTime = dt.plusYears(1); //加一年
LocalDateTime localDateTime1 = dt.plusDays(2); //加2天
LocalDateTime localDateTime2 = dt.minusHours(2);//减2小时
//……等等
Instant 时间戳
用于“时间戳”的运算。它是以Unix元年(传统的设定为UTC时区1970年1月1日午夜时分)开始所经历的描述进行运算
//时间戳 Instant (使用 Unix 元年 1970年1月1日 00:00:00 所经历的毫秒值)
//默认使用 UTC 时区
Instant ins = Instant.now(); //默认使用 UTC 时区
System.out.println(ins);
OffsetDateTime odt = ins.atOffset(ZoneOffset.ofHours(8));
System.out.println(odt);
System.out.println(ins.getNano());
Instant ins2 = Instant.ofEpochSecond(5);
System.out.println(ins2);
//2019-12-07T16:03:25.310Z
//2019-12-08T00:03:25.310+08:00
//310000000
//1970-01-01T00:00:05Z
Duration 和 Period
- Duration:用于计算两个“时间”间隔
- Period:用于计算两个“日期”间隔
Instant ins1 = Instant.now();
System.out.println("--------------------");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
Instant ins2 = Instant.now();
System.out.println("所耗费时间为:" + Duration.between(ins1, ins2));
System.out.println("----------------------------------");
LocalDate ld1 = LocalDate.now();
LocalDate ld2 = LocalDate.of(2011, 1, 1);
Period pe = Period.between(ld2, ld1);
System.out.println(pe.getYears());
System.out.println(pe.getMonths());
System.out.println(pe.getDays());
//--------------------
//所耗费时间为:PT1.001S
//----------------------------------
//8
//11
//7
日期的 操纵
- TemporalAdjuster : 时间校正器。有时我们可能需要获取 ,例如:将日期调整到“下个周日”等操作。
- TemporalAdjusters : 该类通过静态方法提供了大量的常用 TemporalAdjuster 的实现。
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt);
LocalDateTime ldt2 = ldt.withDayOfMonth(10);
System.out.println(ldt2);
LocalDateTime ldt3 = ldt.with(TemporalAdjusters.next(DayOfWeek.SUNDAY));
System.out.println(ldt3);
//自定义:下一个工作日
LocalDateTime ldt5 = ldt.with((l) -> {
LocalDateTime ldt4 = (LocalDateTime) l;
DayOfWeek dow = ldt4.getDayOfWeek();
if (dow.equals(DayOfWeek.FRIDAY)) {
return ldt4.plusDays(3);
} else if (dow.equals(DayOfWeek.SATURDAY)) {
return ldt4.plusDays(2);
} else {
return ldt4.plusDays(1);
}
});
System.out.println(ldt5);
//2019-12-08T00:02:51.110
//2019-12-10T00:02:51.110
//2019-12-15T00:02:51.110
//2019-12-09T00:02:51.110
解析 与格式化
java.time.format.DateTimeFormatter 类:该类提供了三种格式化方法:
- 预定义的标准格式
- 语言环境相关的格式
- 自定义的格式
// DateTimeFormatter : 解析和格式化日期或时间
// DateTimeFormatter dtf = DateTimeFormatter.ISO_LOCAL_DATE;
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss E");
LocalDateTime ldt = LocalDateTime.now();
String strDate = ldt.format(dtf);
System.out.println(strDate);
LocalDateTime newLdt = LocalDateTime.parse(strDate, dtf);
System.out.println(newLdt);
//2019年12月08日 00:02:33 星期日
//2019-12-08T00:02:33
时区 的处理
- Java8 中加入了对时区的支持,带时区的时间为分别为:onedDate、ZonedTime、ZonedDateTime
- 其中每个时区都对应着 ID,地区ID都为 “{区域}/{城市}”的格式例如 :Asia/Shanghai 等
- ZoneId:该类中包含了所有的时区信息
- getAvailableZoneIds() : 可以获取所有时区时区信息
- of(id) : 用指定的时区信息获取 ZoneId 对象
//ZonedDate、ZonedTime、ZonedDateTime : 带时区的时间或日期
Set<String> set = ZoneId.getAvailableZoneIds();
set.forEach(System.out::println);
LocalDateTime ldt = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
System.out.println(ldt);
ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("US/Pacific"));
System.out.println(zdt);