Java 8 时间日期详细用法

x33g5p2x  于2021-12-18 转载在 其他  
字(4.7k)|赞(0)|评价(0)|浏览(402)

一、概述

java8 重新定义了一套语义非常清晰的日期、时间Api,位于java.time包中。该包中的所有类都是不可变且线程安全的。

其实,以上所有类都是基于java8 Clock类实现的,只是由于场景不同而显示方式不一样而已。而Clock又是基于System.currentTimeMillis() 实现的,所以以上时间api都是跟本主机时间关联的。

二、时间操作

以上虽然有很多个时间、日期类,但由于他们实现相同的接口,所以方法总体上是相通。下面就以LocalDateTime为例子:

  1. now(),创建当前时间,可指定时区
//当前本地时间:2018-12-16T13:45:11.232
LocalDateTime localDateTime = LocalDateTime.now();

//当前美国洛杉矶时间:2018-12-15T21:45:11.251
LocalDateTime losAngelesTime = LocalDateTime.now(ZoneId.of("America/Los_Angeles"));
LocalDateTime losAngelesTime2 = LocalDateTime.now(Clock.system(ZoneId.of("America/Los_Angeles")));

2.of(),创建指定的时间

// 2019-01-01T12:00:01 注:月份是从1开始算的了,不想Calendar是从0开始的
LocalDateTime time = LocalDateTime.of(2019, 1, 1, 12, 0, 1);
//另外月份也可以使用Month枚举类
LocalDateTime time1 = LocalDateTime.of(2019, Month.AUGUST, 1, 12, 1, 1);
  1. getXXX(),获取某个时间字段
LocalDateTime now = LocalDateTime.now();
//获取年份   2018
int year = now.getYear();
//获取周几   7(星期天)
int dayOfWeek = now.getDayOfWeek().getValue();
//获取小时   14
int hour = now.getHour();
  1. withXXX(),跳到指定的时间
//2018-12-16T14:12:32.162
LocalDateTime now = LocalDateTime.now();
//2019-02-16T14:10:32.162
LocalDateTime withTime = now.withYear(2019).withMonth(2).withMinute(10);
  1. plusXXX() / minusXXX() ,加 / 减 某个时间
//2018-12-16T14:18:01.005
LocalDateTime now = LocalDateTime.now();
//2019-01-01T14:18:01.005
LocalDateTime plusTime = now.plusDays(16);
//2018-12-16T04:18:01.005
LocalDateTime minusTime = now.minusHours(10);
  1. parse() / format(),解析时间 /格式化时间
//ofPattern 是自定义自己的格式
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
String timeStr="2018-12-31 23:59:59";
LocalDateTime parseTime = LocalDateTime.parse(timeStr, dateTimeFormatter);

//DateTimeFormatter也提供一些自带的格式
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL);
LocalDateTime now = LocalDateTime.now();
String formatTime = now.format(formatter); //2018年12月16日 星期日

三、Duration 或 Period

都是表示一段时间长度(时间量),只是Duration偏向“时间”方面的,如 10秒,1小时。而Period则偏向于“日期”方面的,如 1个月,1年。

//Duration 可以获取到两个时间相差的天数、小时、分钟、秒、毫秒
LocalDateTime ldt1 = LocalDateTime.of(2018, 10, 10, 12, 10, 10);
LocalDateTime ldt2 = LocalDateTime.of(2019, 5, 2, 2, 10, 10);
Duration duration = Duration.between(ldt1, ldt2);
System.out.println(duration.getSeconds());  // 17589600
System.out.println(duration.toHours());    //  4886
System.out.println(duration.toDays());    //   203

//Period 可以获取到两个时间相差的年数和月数
LocalDate ld1 = LocalDate.of(2017, 12, 26);
LocalDate ld2 = LocalDate.of(2019, 3, 27);
Period period = Period.between(ld1,ld2);
System.out.println(period.getYears());       // 1
System.out.println(period.toTotalMonths());  // 15

//特别注意以下两个getXXX()
System.out.println(period.getDays());    // 1
System.out.println(period.getMonths()); //  3

另外,这个类中的 ofXXX(),withXXX(),plusXXX(),minsXXX()等方法的含义都是跟上面的时间日期类相似。

四、java.time.tempral 包

  1. 时间调整器:TemporalAdjuster 和 TemporalAdjusters
//获取下个工作日
TemporalAdjuster nextWorkDayAdjuster = (temporal) -> {
    int dayOfWeek = temporal.get(ChronoField.DAY_OF_WEEK);
    if (dayOfWeek == DayOfWeek.FRIDAY.getValue()) {
        return temporal.plus(Period.ofDays(3));
    } else if (dayOfWeek == DayOfWeek.SATURDAY.getValue()) {
        return temporal.plus(Period.ofDays(2));
    } else {
        return temporal.plus(Period.ofDays(1));
    }
};

LocalDateTime now = LocalDateTime.now();
LocalDateTime nextWorkDay = now.with(nextWorkDayAdjuster);
System.out.println(nextWorkDay);

//获取下个月的第一天
LocalDateTime firstDayOfNextMonth = now.with(TemporalAdjusters.firstDayOfNextMonth());
System.out.println(firstDayOfNextMonth);
  1. 日期、时间查询器:TemporalQuery 和 TemporalQuerys 
//查询到过年还剩下几天
TemporalQuery<Long> newYearQuery = (temporalAccessor) -> {
    Temporal day = (Temporal) temporalAccessor;
    LocalDateTime newYear = LocalDateTime.of(2019, 2, 4, 0, 0, 0);
    //Duration duration = Duration.between(day, newYear);
    return ChronoUnit.DAYS.between(day, newYear);
};

LocalDateTime now = LocalDateTime.now();
Long remainDay = now.query(newYearQuery);
System.out.println(remainDay);

//只查询日期部分
LocalDate localDate = now.query(TemporalQueries.localDate());
System.out.println(localDate);

五、LocalDateTime 与 Date 互转

/**
 * 将localDateTime 转为 date
 */
public static Date localDateTime2Date(LocalDateTime localDateTime) {
    ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
    Instant instant = zonedDateTime.toInstant();
    return Date.from(instant);
}

/**
 * 将date转为LocalDatetTime
 */
public static LocalDateTime date2LocalDateTime(Date date) {
    Instant instant = date.toInstant();
    ZoneId zoneId = ZoneId.systemDefault();
    return instant.atZone(zoneId).toLocalDateTime();
}

六、补充:

纳秒: 表示一秒内的某一瞬间,范围是:0~999,999,999,java中用int类型存放。

在我们的普遍观念中,一年就是地球绕太阳一圈,时长为:365(+1)2460*60秒。这是理想中的世界时(UT),但实际上由于地球的不均匀和长期变慢性,而让时间出现了 ± 1秒的偏差,也称为闰秒。为了调整这个偏差,引入了协调世界时(UTC),它会在闰秒出现的时候,将那一分钟调整为59秒或61秒。

UTC正是我们手机电脑中的时间,它跟GMT可看做是同一东西。

zone offset:指距离UTC 0 偏移的时间,目前偏移量的范围是:-12:00 到 +14:00,而java中为了其扩展性,而将范围定为:-18:00 到 +18:00。

服务在实现app本地时间功能时,建议不要用手机的offset second来做,因为有些地方由于冬令时和夏令时的存在,而导致偏移量是不固定的。(可能你会想更新这个偏移量,但不建议这么做,毕竟用户可以随便修改这个值)所以我个人建议是存一个zoneId,(如:America/Los_Angeles),因为它能自动帮我们实现夏令时和冬令时。

参考:https://www.byteslounge.com/tutorials/java-8-date-time-api

相关文章