java8时间API
Java8之前的日期时间API
表示时刻信息的 Date
Date的设计饱受诟病,其缺陷包括但不限于:
- 类名误导,该类实际上不仅反映日期,还反映时间
- 方法名误导,getDate()返回日期中的天,getDay()返回的是周几
- 年份是与1900年的差值,可读性极差
- 月份是从0计数的,可读性极差
- 周几是相对于周日的差值,可读性极差
- 不提供时区设置,内部总是使用本地时区
- 不提供历法设置,内部使用格里历或儒略历
- 不提供格式化的转换,从字符串中解析日期时相当难用
- 参数返回太随意,比如设置1月33日,实际是2月2日
- 存在同名类,java.sql包下依然有一个作用相同的Date类
- 该类允许扩展,实际上,应当把日期-时间类设计为不可变的final类
当前定位
Date 的目前定位是,唯一表示一个时刻,现在的 Date 类中接近百分之八十的方法都已废弃,被标记为 @Deprecated。还有几个为数不多没有被废弃的方法:
public long getTime()
:返回内部存储的毫秒数public void setTime(long time)
:重新设置内存的毫秒数public boolean before(Date when)
:比较给定的时刻是否早于当前 Date 实例public boolean after(Date when)
:比较给定的时刻是否晚于当前 Date 实例
描述年历的 Calendar
Calendar 用于表示年月日等日期信息,它是一个抽象类,一般通过以下四种工厂方法获取它的实例对象:
public static Calendar getInstance()
public static Calendar getInstance(TimeZone zone)
public static Calendar getInstance(Locale aLocale)
public static Calendar getInstance(TimeZone zone,Locale aLocale)
//最终调用的方法,因为不同的时区与国家语言对于时刻和年月日信息的输出是不同的,所以这也是为什么一个 Calendar 实例必须传入时区和国家信息的一个原因
private static Calendar createCalendar(TimeZone zone,Locale aLocale)
DateFormat 格式化转换
DateFormat dateFormat = new SimpleDateFormat("yyyy年MM月dd日");
//将一个日期对象格式化为字符串
public final String format(Date date)
//将一个格式化的字符串装换为一个日期对象
public Date parse(String source)
yyyy:年份用四位进行输出
MM:月份用两位进行输出
dd:两位表示日信息
HH:两位来表示小时数
mm:两位表示分钟数
ss:两位来表示秒数
E:表示周几,如果 Locale 在中国则会输出 星期x,如果在美国或英国则会输出英文的星期
a:表示上午或下午
Java8 的时间日期 API
Java 8的日期和时间类包括Instant、Duration、Period、LocalDate、LocalTime、LocalDateTime,这些类都包含在java.time包中。
表示时刻的 Instant
Instant是时间线上的一个点,表示一个时间戳。Instant可以精确到纳秒,这超过了long的最大表示范围,所以在Instant的实现中是分成了两部分来表示,一部分是seconds
,表示从1970-01-01 00:00:00开始到现在的秒数,另一个部分是nanos
,表示纳秒部分。
//根据系统当前时间创建一个 Instant 实例,表示当前时刻
Instant now = Instant.now();
//通过传入一个标准时间的偏移值来构建一个 Instant 实例
Instant instant = Instant.ofEpochSecond(long epochSecond, long nanoAdjustment);
//通过毫秒数值直接构建一个 Instant 实例
public static Instant ofEpochMilli(long epochMilli);
时间段Duration
Duration是两个时间戳的差值,使用java.time中的时间戳类,例如Instant、LocalDateTime等实现了Temporal类的日期时间类为参数
LocalDateTime from = LocalDateTime.of(2020,4, 22, 16, 6, 0);
LocalDateTime to = LocalDateTime.of(2020,5, 22, 16, 6, 0);
Duration duration = Duration.between(from, to);
Duration duration1 = Duration.of(5, ChronoUnit.DAYS); // 5天
Duration duration2 = Duration.of(1000, ChronoUnit.MILLIS); // 1000毫秒
日期段Period
Period是以年月日来衡量一个时间段,由于Period是以年月日衡量时间段,所以between()方法只能接收LocalDate类型的参数
// 2020-03-22 到 2020-04-22 这段时间
Period period = Period.between(LocalDate.of(2020, 3, 22),LocalDate.of(2020, 4, 22));
处理日期的 LocalDate
LocalDate 是一个不可变类,它关注时间中年月日部分。
//用当前系统时间的年月日信息初始化一个实例对象
public static LocalDate now();
//显式指定年月日信息
public static LocalDate of(int year, int month, int dayOfMonth);
//根据 dayOfYear 可以推出 month 和 dayOfMonth
public static LocalDate ofYearDay(int year, int dayOfYear);
//相对于格林零时区时间的日偏移量
public static LocalDate ofEpochDay(long epochDay);
LocalDate localDate = LocalDate.of(2020, 4, 22); // 初始化一个日期:2022-04-22
int year = localDate.getYear(); // 年份:2020
Month month = localDate.getMonth(); // 月份:MARCH
int dayOfMonth = localDate.getDayOfMonth(); // 月份中的第几天:22
DayOfWeek dayOfWeek = localDate.getDayOfWeek(); // 一周的第几天:FRIDAY
int length = localDate.lengthOfMonth(); // 月份的天数:30
boolean leapYear = localDate.isLeapYear(); // 是否为闰年:true
处理时间的 LocalTime
类似于 LocalDate,LocalTime 专注于时间的处理
//根据系统当前时刻获取其中的时间部分内容
public static LocalTime now();
//显式传入小时和分钟来构建一个实例对象
public static LocalTime of(int hour, int minute);
//通过传入时分秒构造实例
public static LocalTime of(int hour, int minute, int second);
//传入时分秒和纳秒构建一个实例
public static LocalTime of(int hour, int minute, int second, int nanoOfSecond);
//传入一个长整型数值代表当前日已经过去的秒数
public static LocalTime ofSecondOfDay(long secondOfDay);
//传入一个长整型代表当前日已经过去的纳秒数
public static LocalTime ofNanoOfDay(long nanoOfDay);
LocalTime localTime = LocalTime.of(16, 25, 52); // 初始化一个时间:16:25:52
int hour = localTime.getHour(); // 时:16
int minute = localTime.getMinute(); // 分:25
int second = localTime.getSecond(); // 秒:52
处理日期和时间的 LocalDateTime
LocalDateTime类是LocalDate和LocalTime的结合体
//通过of()方法直接创建
LocalDateTime ldt1 = LocalDateTime.of(2020, Month.FEBRUARY, 22, 16, 23, 12);
//可以调用LocalDate的atTime()方法或LocalTime的atDate()方法将LocalDate或LocalTime合并成一个LocalDateTime
LocalDate localDate = LocalDate.of(2020, Month.FEBRUARY, 22);
LocalTime localTime = LocalTime.of(16, 23, 12);
LocalDateTime ldt2 = localDate.atTime(localTime);
//向LocalDate和LocalTime的转化
LocalDate date = ldt1.toLocalDate();
LocalTime time = ldt1.toLocalTime();
日期操作
比较简单的日期操作
//比较简单的日期操作
LocalDate date = LocalDate.of(2020, 4, 22); // 2020-04-22
LocalDate date1 = date.withYear(2021); // 修改为 2021-04-22
LocalDate date2 = date.withMonth(3); // 修改为 2020-03-22
LocalDate date3 = date.withDayOfMonth(1); // 修改为 2020-04-01
LocalDate date4 = date.plusYears(1); // 增加一年 2021-04-22
LocalDate date5 = date.minusMonths(2); // 减少两个月,到2020年的2月
LocalDate date6 = date.plus(5, ChronoUnit.DAYS); // 增加5天 2020-04-27
比较复杂的日期操作,比如将时间调到下一个工作日,或者是下个月的最后一天,这时候我们可以使用with()方法的另一个重载方法,它接收一个TemporalAdjuster参数,可以使我们更加灵活的调整日期:
//返回下一个距离当前时间最近的星期日
LocalDate date7 = date.with(TemporalAdjusters.nextOrSame(DayOfWeek.SUNDAY));
// 返回本月最后衣蛾周六
LocalDate date9 = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.SATURDAY));
下面列出时间调节器类TemporalAdjuster提供的一些方法
方法名 | 描述 |
---|---|
dayOfWeekInMonth | 返回同一个月中每周的第几天 |
firstDayOfMonth | 返回当月的第一天 |
firstDayOfNextMonth | 返回下月的第一天 |
firstDayOfNextYear | 返回下一年的第一天 |
firstDayOfYear | 返回本年的第一天 |
firstInMonth | 返回同一个月中第一个星期几 |
lastDayOfMonth | 返回当月的最后一天 |
lastDayOfNextMonth | 返回下月的最后一天 |
lastDayOfNextYear | 返回下一年的最后一天 |
lastDayOfYear | 返回本年的最后一天 |
lastInMonth | 返回同一个月中最后一个星期几 |
next / previous | 返回后一个/前一个给定的星期几 |
nextOrSame / previousOrSame | 返回后一个/前一个给定的星期几,如果这个值满足条件,直接返回 |
时区
ZoneId
//接收一个“区域/城市”的字符串作为参数
ZoneId shanghaiZoneId = ZoneId.of("Asia/Shanghai");
//获取系统默认时区
ZoneId systemZoneId = ZoneId.systemDefault();
//获取所有合法的“区域/城市”字符串
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
ZonedDateTime
ZonedDateTime 可以被理解为 LocalDateTime 的外层封装,它的内部存储了一个 LocalDateTime 的实例,专门用于普通的日期时间处理。此外,它还定义了 ZoneId 和 ZoneOffset 来描述时区的概念。
//系统将以默认时区计算并存储日期时间信息
public static ZonedDateTime now();
//指定时区
public static ZonedDateTime now(ZoneId zone);
//指定日期时间和时区
public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone):
public static ZonedDateTime of(LocalDateTime localDateTime, ZoneId zone)
//通过时刻和时区构建实例对象
public static ZonedDateTime ofInstant(Instant instant, ZoneId zone):
//有了ZoneId,我们就可以将一个LocalDate、LocalTime或LocalDateTime对象转化为ZonedDateTime对象:
LocalDateTime localDateTime = LocalDateTime.now();
ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, shanghaiZoneId);
格式化日期时间
DateTimeFormatter 作为格式化日期时间的主要类,它与之前的 DateFormat 类最大的不同就在于它是线程安全的,其他的使用上的操作基本类似。
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
LocalDateTime localDateTime = LocalDateTime.now();
formatter.format(localDateTime);
String str = "2020年04月23日 23:59:59";
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:mm:ss");
LocalDateTime localDateTime2 = LocalDateTime.parse(str,formatter2);
世界标准时间(UTC)/格林威治时间(GMT)
UTC是协调世界时(Universal Time Coordinated)英文缩写,是由国际无线电咨询委员会规定和推荐,并由国际时间局(BIH)负责保持的以秒为基础的时间标度。UTC相当于本初子午线(即经度0度)上的平均太阳时,过去曾用格林威治平均时(GMT)来表示.北京时间比UTC时间早8小时,以1999年1月1日0000UTC为例,UTC时间是零点,北京时间为1999年1月1日早上8点整。
具体参考:https://pansci.asia/archives/84978
参考
https://www.cnblogs.com/mcbye/p/java8-date-time-api.html