Java8新日期和时间API

1 现有的日期时间API的问题

  • 线程安全问题:Date和Calender类都不是线程安全类,所以开发者要写很多代码处理并发安全问题。Java8新的日期时间类是不可变的(immutable )和线程安全的。
  • API的设计很差:日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
  • 时区处理问题:日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。

2 Java8 新的日期和时间类

编号类的名称描述
1LocalDate只包含日期,比如:2018-02-05
2LocalTime只包含时间,比如:23:12:10
3LocalDateTime包含日期和时间,比如:2018-02-05 23:14:21
4Instant时间戳
5Duration持续时间,时间差
6Period时间段
7ZoneOffset时区偏移量,比如:+8:00
8ZonedDateTime带时区的时间
9Clock时钟,比如获取目前美国纽约的时间
10java.time.format.DateTimeFormatter时间格式化

3 LocalDate、LocalTime和LocalDateTime

3.1 LocalDate

LocalDate表示具体的日期,不包括时间,也不包含时区信息。

LocalDate now = LocalDate.now(); // 获取当前日期
LocalDate localDate = LocalDate.of(2017, 1, 4);     // 初始化一个日期:2017-01-04
int year = localDate.getYear();                     // 年份:2017
Month month = localDate.getMonth();                 // 月份:JANUARY
int dayOfMonth = localDate.getDayOfMonth();         // 月份中的第几天:4
DayOfWeek dayOfWeek = localDate.getDayOfWeek();     // 一周的第几天:WEDNESDAY
int length = localDate.lengthOfMonth();             // 月份的天数:31
boolean leapYear = localDate.isLeapYear();          // 是否为闰年:false

3.2 LocalTime

LocalTime仅包含时间,不包含日期。

LocalTime now = LocalTime.now();  // 获取当前时间
LocalTime localTime = LocalTime.of(17, 23, 52);     // 初始化一个时间:17:23:52
int hour = localTime.getHour();                     // 时:17
int minute = localTime.getMinute();                 // 分:23
int second = localTime.getSecond();                 // 秒:52

3.3 LocalDateTime

LocalDateTime既包括日期也包括时间。

LocalDateTime now = LocalDateTime.now(); // 当前日期时间
LocalDateTime ldt1 = LocalDateTime.of(2017, Month.JANUARY, 4, 17, 23, 52);

LocalDate localDate = LocalDate.now();
LocalTime localTime = LocalTime.now();
LocalDateTime ldt2 = localDate.atTime(localTime); // LocalDate和localTime合并

LocalDate localDate1 = ldt1.toLocalDate(); // 转化成日期
LocalTime localTime1 = ldt1.toLocalTime(); // 转化成时间

4 Instant、Duration和Period

4.1 Instant

Instant用于表示一个时间戳,它与我们常使用的System.currentTimeMillis()有些类似,不过Instant可以精确到纳秒(Nano-Second),System.currentTimeMillis()方法只精确到毫秒(Milli-Second)。如果查看Instant源码,发现它的内部使用了两个常量,seconds表示从1970-01-01 00:00:00开始到现在的秒数,nanos表示纳秒部分(nanos的值不会超过999,999,999)。

Instant now = Instant.now(); 
long l = now.toEpochMilli(); // 获得毫秒数

4.2 Duration

Duration表示一个时间段。

LocalDateTime from = LocalDateTime.of(2017, Month.JANUARY, 5, 10, 7, 0);    // 2017-01-05 10:07:00
LocalDateTime to = LocalDateTime.of(2017, Month.FEBRUARY, 5, 10, 7, 0);     // 2017-02-05 10:07:00
Duration duration = Duration.between(from, to);     // 表示从 2017-01-05 10:07:00 到 2017-02-05 10:07:00 这段时间

long days = duration.toDays();              // 这段时间的总天数
long hours = duration.toHours();            // 这段时间的小时数
long minutes = duration.toMinutes();        // 这段时间的分钟数
long seconds = duration.getSeconds();       // 这段时间的秒数
long milliSeconds = duration.toMillis();    // 这段时间的毫秒数
long nanoSeconds = duration.toNanos();      // 这段时间的纳秒数

4.3 Period

Period在概念上和Duration类似,区别在于Period是以年月日来衡量一个时间段,比如2年3个月6天:

Period period2 = Period.of(2, 3, 6);

// 2017-01-05 到 2018-02-05 这段时间
Period period = Period.between(
         LocalDate.of(2017, 1, 5),
         LocalDate.of(2018, 2, 5));

5 日期的操作和格式化

5.1 增加和减少日期

LocalDate date = LocalDate.of(2017, 1, 5);          // 2017-01-05

LocalDate date1 = date.withYear(2016);              // 修改为 2016-01-05
 LocalDate date2 = date.withMonth(2);                // 修改为 2017-02-05
 LocalDate date3 = date.withDayOfMonth(1);           // 修改为 2017-01-01

 LocalDate date4 = date.plusYears(1);                // 增加一年 2018-01-05
 LocalDate date5 = date.minusMonths(2);              // 减少两个月 2016-11-05
 LocalDate date6 = date.plus(5, ChronoUnit.DAYS);    // 增加5天 2017-01-10

特殊操作:

LocalDate date7 = date.with(nextOrSame(DayOfWeek.SUNDAY));      // 返回下一个距离当前时间最近的星期日
LocalDate date9 = date.with(lastInMonth(DayOfWeek.SATURDAY));   // 返回本月最后一个星期六

需要导入静态类:

import static java.time.temporal.TemporalAdjusters.*;

5.2 格式化日期

LocalDateTime dateTime = LocalDateTime.now();
String strDate1 = dateTime.format(DateTimeFormatter.BASIC_ISO_DATE);    // 20170105
String strDate2 = dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE);    // 2017-01-05
String strDate3 = dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME);    // 14:20:16.998
String strDate4 = dateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));   // 2017-01-05
String strDate5 = dateTime.format(DateTimeFormatter.ofPattern("今天是:YYYY年 MMMM DD日 E", Locale.CHINESE)); // 今天是:2017年 一月 05日 星期四

String strDate6 = "2017-01-05";
String strDate7 = "2017-01-05 12:30:05";

LocalDate date = LocalDate.parse(strDate6, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
LocalDateTime dateTime1 = LocalDateTime.parse(strDate7, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));

6 时区

ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai"); // 时区id
ZoneId systemZoneId = ZoneId.systemDefault(); // 默认系统时区id
Set<String> zoneIds = ZoneId.getAvailableZoneIds(); // 获取全部时区id

LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, shanghaiZoneId); // 包括时区,日期时间等信息

另一种表示时区的方式是使用ZoneOffset,它是以当前时间和世界标准时间(UTC)/格林威治时间(GMT)的偏差来计算,例如:

ZoneOffset zoneOffset = ZoneOffset.of("+09:00");
LocalDateTime localDateTime = LocalDateTime.now();
OffsetDateTime offsetDateTime = OffsetDateTime.of(localDateTime, zoneOffset);

参考:
1 https://lw900925.github.io/java/java8-newtime-api.html;
2 https://mp.weixin.qq.com/s/wWZiJm9xDV90RE2YJpPVFg

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值