您的当前位置:首页正文

JDK8-time

2024-11-07 来源:个人技术集锦

伴随lambda表达式、streams以及一系列小优化,Java 8 推出了全新的日期时间API,在教程中我们将通过一些简单的实例来学习如何使用新API。Java处理日期、日历和时间的方式一直为社区所诟病,将 java.util.Date设定为可变类型,以及SimpleDateFormat的非线程安全使其应用非常受限。Java也意识到需要一个更好的 API来满足社区中已经习惯了使用JodaTime API的人们。全新API的众多好处之一就是,明确了日期时间概念,例如:瞬时(instant)、 长短(duration)、日期、时间、时区和周期。同时继承了Joda库按人类语言和计算机各自解析的时间处理方式。不同于老版本,新API基于ISO标准日历系统,java.time包下的所有类都是不可变类型而且线程安全。下面是新版API中java.time包里的一些关键类:

  •     Instant:瞬时实例。
  •     LocalDate:本地日期,不包含具体时间 例如:2014-01-14 可以用来记录生日、纪念日、加盟日等。
  •     LocalTime:本地时间,不包含日期。
  •     LocalDateTime:组合了日期和时间,但不包含时差和时区信息。
  •     ZonedDateTime:最完整的日期时间,包含时区和相对UTC或格林威治的时差。

新API还引入了ZoneOffSet和ZoneId类,使得解决时区问题更为简便。解析、格式化时间的DateTimeFormatter类也全部重新设 计。

 

java.time包下有5个包组成

  • java.time – 包含值对象的基础包
  • java.time.chrono – 提供对不同的日历系统的访问
  • java.time.format – 格式化和解析时间和日期
  • java.time.temporal – 包括底层框架和扩展特性
  • java.time.zone – 包含时区支持的类


java.time包定义的类表示了日期-时间概念的规则,包括instants, durations, dates, times, time-zones and periods。这些都是基于ISO日历系统,它又是遵循 Gregorian规则的。

还有一些方法前缀的含义,统一了api:

 

类图结构

来源:

 

TemporalQuery

@FunctionalInterface
public interface TemporalQuery<R>
{
      R queryFrom(TemporalAccessor temporal)
}

ChronoField

此枚举类是作为get方法的参数获取时间的值
它里面的属性含义有的跟Calendar的成员变量含义差不多,想要了解一下可以看我的关于Calendar类详解的文章 ,如果要看很详细的讲解可以去查看ChronoField类的文档

TemporalUnit

时间单位

public interface TemporalUnit
{
	//返回add amount个 unit之后的值
	<R extends Temporal> R 	addTo(R temporal, long amount)
	//计算2个Temporal的时间差。
	long 	between(Temporal temporal1Inclusive, Temporal temporal2Exclusive)
	///返回unit的持续时间
	Duration 	getDuration()
	//检查此unit是否表示日期的组成部分
	boolean 	isDateBased()
	//检查unit的持续时间是否为估计值。
	boolean 	isDurationEstimated()
	//检查此unit是否被支持
	default boolean 	isSupportedBy(Temporal temporal)
	//检查此unit是否表示时间的组成部分
	boolean 	isTimeBased()
	//获取unit的显示名称
	String 	toString()
}

TemporalAmount

时间数量接口

实现类

Duration由固定秒数定义,精确到纳秒。例如:34.5 seconds ,0.0003 seconds,可由day,hour,minute互相转换,因为是固定的。

Period为一段时间,包括多个时间域,例如:2 years, 3 months and 4 days

public interface TemporalAmount
{
	//add to Temporal
	Temporal 	addTo(Temporal temporal)
	//get unit value
	long 	get(TemporalUnit unit)
	//获取支持的Unit列表
	List<TemporalUnit> 	getUnits()
	//sub from Temporal
	Temporal 	subtractFrom(Temporal temporal)
}

 

TemporalAccessor

public interface TemporalAccessor
{
	//获取指定时间域的int值
	default int 	get(TemporalField field);
	//获取指定时间域的long值
	long 	getLong(TemporalField field);
	Gets the value of the specified field as a long.
	//是否支持指定时间域
	boolean 	isSupported(TemporalField field);
	//返回一个时间对象,通过query,query是个函数接口。
	default <R> R 	query(TemporalQuery<R> query);
	//返回指定时间域的有效范围
	default ValueRange 	range(TemporalField field);
}

Temporal

public interface Temporal extends TemporalAccessor
{
	//是否支持Unit
	boolean 	isSupported(TemporalUnit unit)
	//减时间单位
	default Temporal 	minus(long amountToSubtract, TemporalUnit unit)
	//减相对时间
	default Temporal 	minus(TemporalAmount amount)
	Returns an object of the same type as this object with an amount subtracted.
	//加时间单位
	Temporal 	plus(long amountToAdd, TemporalUnit unit)
	//加相对时间
	default Temporal 	plus(TemporalAmount amount)
	//计算时间差
	long 	until(Temporal endExclusive, TemporalUnit unit)
	//时间调整
	default Temporal 	with(TemporalAdjuster adjuster)
	//时间调整
	Temporal 	with(TemporalField field, long newValue)
}

TemporalAdjusters

时间调整器接口,函数接口。

此类配合java.time基础包中类的with方法:

@FunctionalInterface
public interface TemporalAdjuster
{
	//调整时间
	Temporal 	adjustInto(Temporal temporal)
}
   // 以下2种方式等价,推荐第2种。
   temporal = thisAdjuster.adjustInto(temporal);
   temporal = temporal.with(thisAdjuster);

Month

Month是个枚举,表示一年的12个月

Month有个int属性,表示每个月份对应的数字。不要使用ordinal()获取月份对应数字,而是使用getValue()方法。

 

DayOfWeek

枚举,表示每周的某天。

有个int属性,表示每个星期几对应的数字。不要使用ordinal()获取月份对应数字,而是使用getValue()方法。

数字从1到7分别代表星期一到星期日。固定不变,不支持根据local不同星期日对应不同数字。如有需要,通过WeekFields设置。

Year

YearMonth

Instant

MonthDay

LocalDate

LocalDateTime

LocalTime

Era

表示纪年

实现类:

  • IsoEra:ISO,没有任务Era定义。枚举类型,包括'Current era' (CE) for years on or after 0001-01-01 (ISO), and 'Before current era' (BCE) for years before that.
  • HijrahEra:回历。枚举类型,包括:Anno Hegirae,伊斯兰纪元)
  • MinguoEra:民国纪年。枚举类型,包括BEFORE_ROC,ROC 。Republic Of China.
  • JapaneseEra:日本纪年。class类型。
  • ThaiBuddhistEra:泰国佛历。枚举类型。包括:BE,BEFORE_BE。

DateTimeFormatter

java.util.Date或java.util.Calendar到新库类的转换

转换可通过下面的方法进行。
Date.toInstant()
Date.from(Instant)
Calendar.toInstant()

日期和时间模式

日期和时间格式由 日期和时间模式字符串 指定。在 日期和时间模式字符串 中,未加引号的字母 'A' 到 'Z' 和 'a' 到 'z' 被解释为模式字母,用来表示日期或时间字符串元素。文本可以使用单引号 (') 引起来,以免进行解释。所有其他字符均不解释,只是在格式化时将它们简单复制到输出字符串。

简单的讲:这些 A ——Z,a —— z 这些字母(不被单引号包围的)会被特殊处理替换为对应的日期时间,其他的字符串还是原样输出。

日期和时间模式(注意大小写,代表的含义是不同的)如下:

 

时区

示例1:

        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime t = LocalDateTime.parse("2019-11-12 00:00:00",f);
        Instant i = t.toInstant(ZoneOffset.UTC);
        Long s = i.getEpochSecond();

输出:

t:2019-11-12T00:00

i:2019-11-12T00:00:00Z

s:1573516800(北京时间:2019-11-12 08:00:00)

示例2:

        DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        LocalDateTime t = LocalDateTime.parse("2019-11-12 00:00:00",f);
        Instant i = t.toInstant(ZoneOffset.ofHours(8));
        Long s = i.getEpochSecond();

输出:

t:2019-11-12T00:00

i:2019-11-11T16:00:00Z

s:1573488000(北京时间:2019-11-12 00:00:00)

Top