Java 8 时间日期详细用法

一、概述

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日 星期日

像LocalDate、LocalTime、LocalDateTime以及Instant这样表示时间点的日期-时间类提供了大量通用的方法

方法名是否是静态方法描述
from依据传入的Temporal创建对象实例
now依据系统时钟创建Temporal对象
of由Temporal对象的某个部分创建该对象的实例
parse由字符串创建Temporal对象的实例
atOffset将Temporal对象和某个时区偏移相结合
atZone将Temporal对象和某个时区相结合
format使用某个指定的格式器将Temporal对象转换为字符串(Instant类不提供该方法)
get读取Temporal对象的某一部分的值
minus创建Temporal对象的一个副本,通过将当前Temporal对象的值减去一定的时长创建该副本
plus创建Temporal对象的一个副本,通过将当前Temporal对象的值加上一定的时长创建该副本
with以该Temporal对象为模板,对某些状态进行修改创建该对象的副本

三、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()等方法的含义都是跟上面的时间日期类相似。

方法名是否是静态方法方法描述
between创建两个时间点之间的interval
from由一个临时时间点创建interval
of由它的组成部分创建interval的实例
parse由字符串创建interval的实例
addTo创建该interval的副本,并将其叠加到某个指定的temporal对象
get读取该interval的状态
isNegative检查该interval是否为负值,不包含零
isZero检查该interval的时长是否为零
minus通过减去一定的时间创建该interval的副本
multipliedBy将interval的值乘以某个标量创建该interval的副本
negated以忽略某个时长的方式创建该interval的副本
plus以增加某个指定的时长的方式创建该interval的副本
substractFrom从指定的temporal对象中减去该interval

四、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);

TemporalAdjuster中包含的工厂方法列表

方法名描述
dayOfWeekInMonth创建一个新的日期,它的值为同一个月中每一周的第几天
firstDayOfMonth创建一个新的日期,它的值为当月的第一天
firstDayOfNextMonth创建一个新的日期,它的值为下个月的第一天
firstDayOfNextYear创建一个新的日期,它的值为明年的第一天
firstDayOfYear创建一个新的日期,它的值为当年的第一天
firstInMonth创建一个新的日期,它的值为同一个月中,第一个符合星期几要求的值
lastDayOfMonth创建一个新的日期,它的值为当月的最后一天
lastDayOfNextMonth创建一个新的日期,它的值为下月的最后一天
lastDayOfNextYear创建一个新的日期,它的值为明年的最后一天
lastDayOfYear创建一个新的日期,它的值为今年的最后一天
lastInMonth创建一个新的日期,它的值为同一个月中,最后一个复合星期几要求的值
next/previous创建一个新的日期,并将其值设定为日期调整后或调整前,第一个符合指定星期几要求的日期
nextOrSame/previousOrSame创建一个新的日期,并将其值设定为日期调整后或者调整前,第一个符合指定星期几要求的日期,如果该日期已经符合要求,直接返回该对象

五、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();
}

六、解析日期-时间对象

处理日期和时间对象时,格式化以及解析日期-时间对象时另一个非常重要的功能。新的java.time.format包就是特别为这个目的而设计的。这个包中,最重要的类时DateTimeFormatter。创建格式器最简单的方法是通过它的静态工厂方法以及常量。像BASIC_ISO_DATE和ISO_LOCAL_DATE这样的常量是DateTimeFormatter类的预定义实例。所有的DateTimeFormatter实例都能用于以一定格式创建代表特定日期或时间的字符串。

LocalDate date=LocalDate.of(2014,3,18);
String s1=date.format(DateTimeFormatter.BASIC_ISO_DATE);//20140318
String s2=date.format(DateTimeFormatter.ISO_LOCAL_DATE);//2014-03-18

可以通过解析代表日期或时间的字符串重新创建该日期对象。所有的日期和时间API都提供了表示时间点或者时间段的工厂方法,你可以使用工厂方法parse达到重创该日期对象的目的。

LocalDate date1=LocalDAte.parse("20140318",DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date2=LocalDate.parse("2014-03-18",DateTimeFormatter.ISO_LOCAL_DATE);

和老的java.util.DateFormat相比较,所有的DateTimeFormatter实例都是线程安全的。所以,你能够以单例模式创建格式器实例,就像DateTimeFormatter所定义的那些常量,并能在多个线程间共享这些实例。DateTimeFormatter类还支持一个静态工厂方法,它可以按照某个特定的模式创建格式器。

DateTimeFormatter formatter=DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date1=LocalDate.of(2014,3,18);
String formattedDate=date1.format(formatters);
LocalDate date2=LocalDate.parse(formattedDate,formatter);

LocalDate的formate方法使用指定的模式生成了一个代表该日期的字符串。紧接着,静态的parse方法使用同样的格式器解析了刚才生成的字符串,并重建了该日期对象。

ofPattern方法也提供了一个重载的版本,使用它你可以创建某个Locale的格式器

DateTimeFormatter italianFormatter=
                DateTimeFormatter.ofPattern("d. MMMM yyyy",Locale.ITALIAN);
LocalDate date1=LocalDate.of(2014,3,18);
String fromattedDate=date.format(italianFormatter);//18. marzo 2014
LocalDate date2=LocalDate.parse(formattedDate,italianFormatter);

最后,如果还需要更加细粒度的控制,DateTimeFormatterBuilder类还提供了更复杂的格式器,可以选择恰当的方法,一步一步地构造自己的格式器。另外,它还提供了非常强大的解析功能,比如区分大小写的解析、柔性解析(允许解析器使用启发式的机制去解析输入,不精确地匹配指定的模式)、填充,以及在格式器中指定可选节。

比如,可以通过DateTimeFormatterBuilder自己编程实现我们在代码清单中使用的italianFormatter

DateTimeFormatter italianFormatter=new DateTimeFormatterBuilder()
        .appendText(ChronoField.DAY_OF_MONTH)
        .appendLiteral(". ")
        .appendText(ChronoField.MONTH_OF_YEAR)
        .appendLiteral(" ")
        .appendText(ChronoField.YEAR)
        .parseCaseInsensitive()
        .toFormatter(Locale.ITALIAN);

七、补充:

纳秒: 表示一秒内的某一瞬间,范围是: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://blog.csdn.net/y_k_y/article/details/84633119

https://blog.csdn.net/zsx157326/article/details/80887673?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.channel_param

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值