时区
GMT(Greenwich Mean Time):格林尼治时间,格林尼治标准时间的正午是指当太阳横穿格林尼治子午线时(也就是在格林尼治上空最高点时)的时间。
UTC(Universal Time Coordinated):统一协调时间,其以原子时秒长为基础,在时刻上尽量接近于格林尼治标准时间,标准 UTC 时间格式 yyyy-MM-dd’T’HH:mm:ss.SSSXXX。
格林尼治时间已经不再被作为标准时间使用,UTC 是最主要的世界时间标准。
Java提供了获取当前时间的方法
System.currentTimeMillis() 返回当前时间,以毫秒为单位。
表示是当前时刻至 1970-01-01 00:00:00.000 的毫秒差值。返回的long值可以用来初始化java.util.Date, java.sql.Date, java.sql.Timestamp和java.util.GregorianCalendar对象。System.nanoTime() 返回一个时间值(系统计时器的当前值),精确到纳秒。
它是由 JVM 提供的一个时间,主要用来精确衡量两个时间段之间的时间
时间粒度:System.currentTimeMillis()方法的时间粒度是大于1毫秒的。如果你反复执行这个方法,短时间内得到的结果是相同的,或又突然在某一次结果增加了几十毫秒,这是正常的。
旧的时间API
- Java的日期/时间类的定义并不一致,在java.util和java.sql的包中都有日期类,此外用于格式化和解析的类在java.text包中定义。
- java.util.Date同时包含日期和时间,而java.sql.Date仅包含日期,将其纳入java.sql包并不合理。另外这两个类都有相同的名字,这本身就是一个非常糟糕的设计。
- 对于时间、时间戳、格式化以及解析,并没有一些明确定义的类。对于格式化和解析的需求,我们有java.text.DateFormat抽象类,但通常情况下,SimpleDateFormat类被用于此类需求。
- 所有的日期类都是可变的,因此他们都不是线程安全的,这是Java日期类最大的问题之一。
- 日期类并不提供国际化,没有时区支持,因此Java引入了java.util.Calendar和java.util.TimeZone类,但他们同样存在上述所有的问题。
java.util.Date
java.util.Date类用于封装日期及时间信息,一般仅用它显示某个日期,不对他作任何操作处理,作处理推荐用Calendar类,计算方便。
构造方法
Date() :分配 Date对象并初始化此对象,以表示分配它的时间(精确到毫秒)。
Date(long date):分配 Date对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。
Calendar与GregorianCalendar
java.util.Calendar类用于封装日历信息,其主作用在于其方法可以对时间分量进行运算。Calendar类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。
Calendar类是抽象类,构造方法是protected的,API中提供了getInstance方法用来创建对象。
Java只提供java.util.GregorianCalendar这一种java.util.Calendar的实现类。
SimpleDateFormat
SimpleDateFormat(String pattern),pattern -为描述日期和时间格式的模式,注:此构造方法可能不支持所有语言环境。要覆盖所有语言环境,请使用 DateFormat 类中的工厂方法。
1 | public final String format(Date date)将一个 Date 格式化为日期/时间字符串 |
DateFormat
java.text.DateFormat类(抽象类)是SimpleDateFormat类的父类
java.sql.Date
java.sql.Date继承java.util.Date,为了把前者转为后者,不支持Date参数的构造器,传入long类型的时间。
java.sql.Date是SQL中的单纯的日期类型,没有时分秒。如果同时需要日期和时间,应该使用Timestamp。它也是 java.util.Date 的子类,Timestamp 则包含时间戳的完整信息。
java.sql.Timestamp是java.util.Date的派生类(继承),所以在java.util.Date上能做的事,也可以在java.sql.Timestamp上做。
现在的Date类中大部分方法已经弃用,现在一般使用旧的API,Date只负责存储一个时间,并对Calendar和DateFormat提供操作接口。Calendar获取Date中特定的信息,对日期时间进行操作,SimpleDateFormat对日期时间进行格式化输入输出。
总的来说,Date、Calendar 和 DateFormat 已经能够处理一般的时间日期问题了。但是它们依然很繁琐,不好用并且这些日期类都是可变且线程不安全的。
Java 8 时间日期API
特性
1 | 不变性:新的日期/时间API中,所有的类都是不可变的,这对多线程很有好处。 |
Java8日期时间的默认格式如下:yyyy-MM-dd-HH-mm-ss.zzz
主要的 核心类:
1 | LocalDate:日期类,不带时间 |
LocalDate、LocalTime、LocalDateTime
LocalDate是不变的日期时间对象代表一个日期,往往被视为年月日。其他日期字段,如一年中的一天,一周和一周的一天,也可以访问。
LocalTime是不变的日期时间对象代表一个时间,往往被视为小时分钟秒。时间为代表的纳秒级精度。
LocalDateTime是不变的日期时间对象代表一个日期时间,往往被视为年、月、日、时、分、秒。其他日期和时间字段,如一年中的一天,一周和一周的一天,也可以访问。时间为代表的纳秒级精度。
DateTimeFormatter
格式器用于解析日期字符串和格式化日期输出,创建格式器最简单的方法是通过 DateTimeFormatter 的静态工厂方法以及常量。创建格式器一般有如下三种方式:
1 | 常用 ISO 格式常量,如 ISO_LOCAL_DATE |
使用DateTimeFormatter完成格式化
1 | LocalDateTime localDateTime = LocalDateTime.now(); |
使用DateTimeFormatter完成格式化
1 | LocalDate localDate = LocalDate.parse("2018/11/11",DateTimeFormatter.ofPattern("yyyy/MM/dd")); |
和旧的 java.util.DateFormat 相比较,所有的 DateTimeFormatter 实例都是线程安全的。
Instant
Instant 表示时间线上的一点(与 Date 类似),它只是简单地表示自 1970 年 1 月 1 日 0 时 0 分 0 秒(UTC)开始的秒数。
Instant 由两部分组成,一是从原点开始到指定时间点的秒数 s, 二是距离该秒数 s 的纳秒数。它以 Unix 时间戳的形式存储日期时间。
Instant类的工厂方法创建一个Instant实例
1 | Instant now = Instant.now(); |
Clock
Clock用于查找当前时刻,可以用来获取某个时区下当前的日期和时间,也可以用来代替旧的System.currentTimeMillis()方法和TimeZone.getDefault()方法。
Duration
一个Duration实例是不可变的,当创建出对象后就不能改变它的值了。你只能通过Duration的计算方法,来创建出一个新的Durtaion对象.
Period
Period 是以年月日来衡量一个时间段,用于计算两个日期间隔,所以 between() 方法只能接收 LocalDate 类型的参数。
ZonedDateTime和ZonedId
ZonedDateTime类是Java 8中日期时间功能里,用于表示带时区的日期与时间信息的类。ZonedDateTime 类的值是不可变的,所以其计算方法会返回一个新的ZonedDateTime 实例。
Java 使用 ZoneId 来标识不同的时区,从基准 UTC 开始的一个固定偏移。
TemporalAdjusters
有的时候,你需要进行一些更加复杂的操作,比如,将日期调整到下个周日、下个工作日,或者是本月的最后一天。
1 | LocalDate localDate = LocalDate.now(); |
用重载版本的with方法,向其传递一个提供了更多定制化选择的TemporalAdjuster对象,更加灵活地处理日期。TemporalAdjusters类通过静态方法提供了大量的常用的TemporalAdjuster的实现供我们使用。
这些日期类之间转换
java.util.Date 与 LocalDate、LocalTime、LocalDateTime 转换
1 | //将Date转换为LocalDate,LocalTime,LocalDateTime可以借助于ZonedDateTime和Instant,实现如下: |
由于JDK8实现了向下兼容,所以Date里在JDK8版本引入了2个方法,from和toInstant,所以我们可以借助这两个方法来实现LocalDateTime到Date的转换。
将LocalDateTime转为Date如下:
1 | LocalDateTime localDateTime = LocalDateTime.now(); |
日期与字符串的转换
1 | //通过LocalDate,LocalTime,LocalDateTime的parse方法和DateTimeFormatter来实现: |
时间戳与LocalDateTime转换
1 | //时间戳->LocalDateTime |
新的 API 区分各种日期时间概念并且各个概念使用相似的方法定义模式,这种相似性非常有利于 API 的学习。总结一下一般的方法或者方法前缀:
1 | of:静态工厂方法,用于创建实例 |
参考文章:https://www.cnblogs.com/kiwenzhang/p/10960741.html
Joda-Time
Joda-Time提供了一组Java类包用于处理包括ISO8601标准在内的date和time。可以利用它把JDK Date和Calendar类完全替换掉,而且仍然能够提供很好的集成。
Joda 与 JDK 是百分之百可互操作的,因此您无需替换所有 Java 代码,只需要替换执行日期/时间计算的那部分代码。
如果时间需要按照今天,昨天这样返回,例子如下:
1 | public class DateFormatUtil { |
需要引入包:
1 | <dependency> |