本文目的:掌握 Java 中日期和時(shí)間常用 API 的使用。
參考:Jakob Jenkov的英文教程Java Date Time Tutorial 和 JavaDoc
概覽
Java 8 新增 API
| Java 8 部分新類 | 描述 |
|---|---|
| Instant | 表示時(shí)間線上的某一瞬間,用秒和納秒表示。 |
| Duration | 表示時(shí)間差,用秒和納秒表示。 |
| LocalDate | 表示沒有時(shí)區(qū)信息的日期,例如生日、法定假日等。 |
| LocalTime | 表示沒有時(shí)區(qū)信息的一天中的本地時(shí)間。 |
| LocalDateTime | 表示沒有時(shí)區(qū)信息的日期和時(shí)間 |
| ZonedDateTime | 表示日期和時(shí)間,包括時(shí)區(qū)信息 |
| DateTimeFormatter | 將日期時(shí)間對(duì)象格式化為字符串。 |
眾所周知,在 Java 8 中添加了一個(gè)全新的日期時(shí)間 API 位于 java.time 包中,主要變化是,自1970年1月1日以來,日期和時(shí)間現(xiàn)在不再由單個(gè)毫秒數(shù)表示,而是由1970年1月1日以來的秒數(shù)和納秒數(shù)表示。
秒數(shù)既可以是正的,也可以是負(fù)的,用 long 表示。納秒數(shù)始終為正,由 int 表示。
Java 7 具有以下日期和時(shí)間類和方法:
| Java 7 日期時(shí)間常用類/方法 | 描述 |
|---|---|
| System.currentTimeMillis() | 自1970年1月1日起以毫秒為單位返回當(dāng)前日期和時(shí)間的靜態(tài)方法 |
| java.util.Date | 表示日期和時(shí)間的類。這個(gè)類中的大多數(shù)方法都是不推薦的。 |
| java.sql.Date | 表示日期的類。這個(gè)date類與JDBC一起使用。 |
| java.sql.Timestamp | 表示日期和時(shí)間的類。這個(gè)date和time類與JDBC一起使用。 |
| java.util.Calendar | 日歷類的基類。 有方法做日期和時(shí)間算術(shù),比如將日期或月份添加到另一個(gè)日期。 |
| java.util.GregorianCalendar | 一個(gè) Calendar 類的子類。代表公歷,在今天的西方世界大部分地區(qū)使用。擁有 Calendar 中的所有做日期和時(shí)間算術(shù)的方法。 |
| java.util.TimeZone | 一個(gè)表示時(shí)區(qū)的類,在跨時(shí)區(qū)執(zhí)行日歷計(jì)算時(shí)非常有用。 |
應(yīng)該使用所有這些類中的哪一個(gè)取決于想要做什么,如果你需要做簡(jiǎn)單的計(jì)時(shí), System.currentTimeMillis() 方法就可以了。
- 如果只需要一個(gè)對(duì)象來保存日期,例如作為簡(jiǎn)單域模型對(duì)象中的屬性,則可以使用 java.util.Date 類。
- 如果需要讀取和寫入數(shù)據(jù)庫的日期和時(shí)間,則使用 java.sql.Date 和 java.sql.Timestamp 類。
- 如果您需要進(jìn)行日期計(jì)算,例如將日期或月份添加到另一個(gè)日期,或者查看工作日(星期一,星期二等)這些給定日期,或者轉(zhuǎn)換時(shí)區(qū)之間的日期和時(shí)間,請(qǐng)使用 java.util.Calendar 和 java .util.GregorianCalendar 類。
System.currentTimeMillis()
currenttimemillis() 靜態(tài)方法以毫秒為單位返回自1970年1月1日以來的時(shí)間。返回的值是long。這里有一個(gè)例子:
long timeNow = System.currentTimeMillis();
這個(gè)返回值可以用來初始化 java.util.Date, java.sql.Date, java.sql.Timestamp 和 java.util.GregorianCalendar 對(duì)象,它還可以用于在程序中測(cè)量時(shí)間。
currenttimemillis() 方法的粒度大于 1 毫秒,這取決于操作系統(tǒng),還可能更大,許多操作系統(tǒng)以幾十毫秒為單位測(cè)量時(shí)間。如果需要更精確的計(jì)時(shí),請(qǐng)使用 System.nanoTime() ,但是這個(gè)方法返回的時(shí)間是從任意一個(gè)時(shí)刻計(jì)算的,甚至有可能是負(fù)數(shù),所以不能用于初始化日期時(shí)間對(duì)象,只適合用于計(jì)算兩個(gè)時(shí)間點(diǎn)的時(shí)間差。
java.util.Date
用來表示日期,包含年月日時(shí)分秒 ,目前該類中的大多數(shù)方法都不贊成使用了,一般用 Calendar 類來代替它,但還是有必要簡(jiǎn)單了解一下。
下面是一些使用例子:
Date dateNow = new Date(); // 使用當(dāng)前日期和時(shí)間創(chuàng)建
Date 類的默認(rèn)構(gòu)造器,源碼是這樣的:
public Date() {
this(System.currentTimeMillis());
}
也可以使用一個(gè) long 型的有參構(gòu)造函數(shù):
Date date = new Date(long);
Date 類還有一個(gè) getTime() 實(shí)例方法,這個(gè)方法的返回值就是 new Date(long) 時(shí)指定的 long 參數(shù)。
從 Java 8 開始,新增了和 Instant 互相轉(zhuǎn)換的方法,關(guān)于 Instant 請(qǐng)參考本文下部分,這里了解就行:
static Date from(Instant instant);
Instant toInstant();
java.sql.Date
此類是上述 java.util.Date 類的子類,所以它繼承了 java.util.Date 的所有方法和字段。一般在 JDBC API 中使用它,比如可以在 PreparedStatement 上設(shè)置日期,或者從 ResultSet 獲取日期,
和 java.util.Date 最大的區(qū)別就是它只記日期,不記時(shí)間,即只有年月日,如果構(gòu)造的時(shí)候包含了時(shí)間信息,那么時(shí)間信息會(huì)被舍棄,如果要記時(shí)間,需要用到 java.sql.Timestamp 類。
java.sql.Timestamp
此類也繼承了 java.util.Date,包含的信息有年月日時(shí)分秒納秒,是的,它還擴(kuò)展了納秒,一個(gè)使用示例如下:
long time = System.currentTimeMillis();
java.sql.Timestamp timestamp = new java.sql.Timestamp(time);
timestamp.setNanos(123456);
int nanos = timestamp.getNanos(); // nanos = 123456
java.util.Calendar 和 GregorianCalendar
Calendar 抽象類用于執(zhí)行日期和時(shí)間換算,無法使用構(gòu)造器實(shí)例化它,原因是世界上有不止一個(gè)日歷。
但是其提供了一個(gè) getInstance() 方法,可以獲取對(duì)應(yīng)當(dāng)前時(shí)間的 Calendar 對(duì)象:
Calendar rightNow = Calendar.getInstance();
getInstance() 方法底層是如下這樣實(shí)現(xiàn)的:
public static Calendar getInstance() {
return createCalendar(TimeZone.getDefault(), Locale.getDefault(Locale.Category.FORMAT));
}
沒錯(cuò),很容易想到,此方法還有重載的,可以提供部分指定初始化參數(shù)的版本,如下:
getInstance(TimeZone zone);
getInstance(Locale aLocale);
getInstance(TimeZone zone, Locale aLocale);
此外,一般可以通過其子類 GregorianCalendar 來訪問日期時(shí)間信息,一個(gè)例子如下:
Calendar calendar = new GregorianCalendar();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int dayOfMonth = calendar.get(Calendar.DAY_OF_MONTH); // 一月 Jan = 0, 不是 1
int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK);
int weekOfYear = calendar.get(Calendar.WEEK_OF_YEAR);
int weekOfMonth= calendar.get(Calendar.WEEK_OF_MONTH);
int hour = calendar.get(Calendar.HOUR); // 12 小時(shí)制
int hourOfDay = calendar.get(Calendar.HOUR_OF_DAY); // 24 小時(shí)制
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
int millisecond= calendar.get(Calendar.MILLISECOND);
calendar.set(Calendar.YEAR, 2018);
calendar.set(Calendar.MONTH, 11); // 11 = december,十二月
calendar.set(Calendar.DAY_OF_MONTH, 24); // 圣誕節(jié)
年月日等的加減
Calendar calendar = new GregorianCalendar();
// 加 1 天
calendar.add(Calendar.DAY_OF_MONTH, 1);
// 當(dāng)?shù)诙€(gè)參數(shù)為負(fù)數(shù)時(shí),表示減,下面就是減 1 天
calendar.add(Calendar.DAY_OF_MONTH, -1);
Calendar/Date/String 的互相轉(zhuǎn)換
// Calendar to Date
Calendar calendar = Calendar.getInstance();
java.util.Date date = calendar.getTime();
// Date to Calendar
calendar.setTime(new java.util.Date());
// Calendar to String
Calendar calendat = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateStr = sdf.format(calendar.getTime());
// String to Calendar
String str = "2018-12-3";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date date = sdf.parse(str);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
// Date to String
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
String dateStr = sdf.format(new Date());
// String to Date
String str = "2018-12-3";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date dateParse = sdf.parse(str);
Calendar 容易犯錯(cuò)的地方
- Calendar 類的 MONTH 字段不是往常的從 1 到 12 。而是從 0 到 11 ,其中 0 是一月,11 是十二月。
- 一周的某一天是從 1 到 7 表示,這點(diǎn)不出意料,但是一周的第一天是星期日而不是星期一,這意味著 1 =星期日,2 =星期一,7 =星期六。
- 如果需要進(jìn)行復(fù)雜的日期和時(shí)間計(jì)算,最好在官方JavaDoc中閱讀java.util.Calendar的類文檔。 類文檔包含有關(guān)類的特定行為的更多詳細(xì)信息。 例如,如果將日期設(shè)置為 2018 年 1 月 34 日,那么實(shí)際日期是什么?
java.util.TimeZone
TimeZone 是一個(gè)表示時(shí)區(qū)的類,在跨時(shí)區(qū)執(zhí)行日歷計(jì)算時(shí)非常有用,一般和 Calendar 一起使用。
注意:在 Java 8 日期時(shí)間 API 中,時(shí)區(qū)由 java.time.ZoneId 類表示。 如果使用的是 Java 8 日期時(shí)間類(如 ZonedDateTime 類)的話,則只需要使用 ZoneId 類就行了。 如果使用的是 Calendar (來自Java 7和更早的日期時(shí)間API),那么仍然可以使用 java.util.TimeZone 類。
從 Calendar 中獲取TimeZone
Calendar calendar = new GregorianCalendar();
// 從 Calendar 獲取時(shí)區(qū)
TimeZone timeZone = calendar.getTimeZone();
// 為 Calendar 設(shè)置時(shí)區(qū)
calendar.setTimeZone(timeZone);
創(chuàng)建 TimeZone 對(duì)象
// 獲取默認(rèn)時(shí)區(qū)對(duì)象
TimeZone timeZone = TimeZone.getDefault();
// 獲取指定時(shí)區(qū)對(duì)象
TimeZone timeZone = TimeZone.getTimeZone("Asia/Shanghai");
TimeZone timeZone = TimeZone.getTimeZone("Europe/Copenhagen");
TimeZone.getTimeZone() 方法的參數(shù)可以是一個(gè) zone ID ,可以查看 JavaDoc 獲取全部 ID 。
注意:如果 getTimeZone(String zoneID);方法的 zoneID 設(shè)置錯(cuò)誤(不匹配系統(tǒng)支持的任意值),比如 "Asiannn/Shanghai",那也不會(huì)拋出任何異常,而是默默地設(shè)置 zoneID 為 GMT0 ,即格林威治時(shí)間。
時(shí)區(qū)的名稱、ID和偏移量
我們可以查看給定時(shí)區(qū)的顯示名稱、ID和時(shí)間偏移量,如下所示
TimeZone timeZone = TimeZone.getDefault();
System.out.println(timeZone.getDisplayName());
System.out.println(timeZone.getID());
System.out.println(timeZone.getOffset(System.currentTimeMillis()));
以上代碼將輸出:
中國標(biāo)準(zhǔn)時(shí)間
Asia/Shanghai
28800000
getOffset() 方法以 int 類型返回該時(shí)區(qū)在指定日期的 UTC 偏移量(毫秒)。上例中的 28800000 毫秒,也就是 8 h ,我們?cè)跂|八區(qū)(+8)。
在時(shí)區(qū)之間轉(zhuǎn)換
TimeZone timeZoneCN = TimeZone.getTimeZone("Asia/Shanghai");
TimeZone timeZone0 = TimeZone.getTimeZone("Etc/GMT0");
Calendar calendar = new GregorianCalendar();
calendar.setTimeZone(timeZoneCN);
long timeCN = calendar.getTimeInMillis();
System.out.println(calendar.getTimeZone().getDisplayName());
System.out.println("timeCN = " + timeCN);
System.out.println("hour = " + calendar.get(Calendar.HOUR_OF_DAY));
calendar.setTimeZone(timeZone0);
System.out.println(calendar.getTimeZone().getDisplayName());
long time0 = calendar.getTimeInMillis();
System.out.println("time0 = " + time0);
System.out.println("hour = " + calendar.get(Calendar.HOUR_OF_DAY));
以上程序?qū)?huì)輸出如下:
中國標(biāo)準(zhǔn)時(shí)間
timeCN = 1543850448183
hour = 23
格林威治時(shí)間
time0 = 1543850448183
hour = 15
可以看到,以毫秒為單位的時(shí)間在兩個(gè)時(shí)區(qū)是相同的,但是已從23點(diǎn)變成15點(diǎn)鐘了,因?yàn)橹袊鴺?biāo)準(zhǔn)時(shí)間比格林威治時(shí)間快 8 小時(shí),如此,我們?cè)O(shè)置不同時(shí)區(qū)獲取對(duì)應(yīng)時(shí)區(qū)的正確時(shí)間,這樣就實(shí)現(xiàn)的換算的目的。
使用 SimpleDateFormat 解析和格式化日期
java.text.SimpleDateFormat 類可以解析字符串中的日期,也可以格式化字符串中的日期,本文將展示幾個(gè)例子:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String dateString = format.format(new Date());
Date date = format.parse ("2018-12-03");
作為參數(shù)傳遞給 SimpleDateFormat 類的字符串是一種模式(模板),用于說明如何解析和格式化日期。 在上面的示例中使用了模式“yyyy-MM-dd”,表示年份 4 位數(shù)(yyyy),月份 2 位數(shù)(MM)和日期 2 位數(shù)(dd)的表示形式,"2018-12-03"中使用‘-’分割是因?yàn)樵谀J街幸彩怯谩?’分割字母的。
以下是常見模式字母列表,具體請(qǐng)看 JavaDoc :
y = year (yy or yyyy)
M = month (MM)
d = day in month (dd)
h = hour (0-12) (hh)
H = hour (0-23) (HH)
m = minute in hour (mm)
s = seconds (ss)
S = milliseconds (SSS)
z = time zone text (e.g. Pacific Standard Time...)
Z = time zone, time offset (e.g. -0800)
//一下是一些示例:
yyyy-MM-dd HH:mm:ss (2018-12-3 23:59:59)
HH:mm:ss.SSS (23:59.59.999)
yyyy-MM-dd HH:mm:ss.SSS (2009-12-31 23:59:59.999)
yyyy-MM-dd HH:mm:ss.SSS Z (2009-12-31 23:59:59.999 +0100)
如果指定 “dd” 來解析new SimpleDateFormat("yyyy-MM-dd");那么天數(shù)肯定被表示為 2 位,比如 3 號(hào)就是 03。
如果是指定 “d” 來解析new SimpleDateFormat("yyyy-MM-d"); 那么天數(shù)優(yōu)先是 1 位,比如 3 號(hào)就是 3, 如果超出 1 位,那會(huì)自動(dòng)擴(kuò)展為 2 位,比如 13 號(hào),那么就是 13 。
Instant 表示某一瞬間
Java .time.Instant 類表示時(shí)間線上的一個(gè)特定時(shí)刻,被定義為自原點(diǎn)起的偏移量,原點(diǎn)是1970年1月1日00點(diǎn)格林,也就是格林尼治時(shí)間。 時(shí)間以每天 86400 秒為單位,從原點(diǎn)向前移動(dòng)。
Java.time 這個(gè)包是線程安全的,并且和其他大部分類一樣,是不可變類。Instant 也不例外。
使用 Instant 類的工廠方法之一創(chuàng)建實(shí)例。例如,要?jiǎng)?chuàng)建一個(gè)表示當(dāng)前時(shí)刻的時(shí)間點(diǎn),可以調(diào)用 instance .now() ,如下所示:
Instant now = Instant.now();
Instant 對(duì)象包含秒和納秒,來表示其包含的時(shí)間, 自紀(jì)元以來的秒數(shù)是上完提到的自原點(diǎn)以來的秒數(shù)。 納秒是 Instant 的一部分,不到一秒鐘。分別可以通過如下 2 個(gè)方法獲?。?/p>
long getEpochSecond();
int getNano();
Instant 運(yùn)算
Instant類還有幾種方法可用于相對(duì)于Instant進(jìn)行計(jì)算。 這些方法中的一些(不是全部)是:
- plusSeconds()
- plusMillis()
- plusNanos()
- minusSeconds()
- minusMillis()
- minusNanos()
一個(gè)例子如下:
Instant now = Instant.now(); // 現(xiàn)在這一瞬間
Instant later = now.plusSeconds(3); // 3 秒后的瞬間
Instant earlier = now.minusSeconds(3); // 3 秒前的瞬間
因?yàn)?Instant 是不可變的,所以上面的計(jì)算方法,是返回一個(gè)代表計(jì)算結(jié)果的新的 Instant 對(duì)象。
Duration 表示時(shí)間間隔
java.time.Duration 表示兩個(gè) Instant 之間的一段時(shí)間,Duration 實(shí)例是不可變的,因此一旦創(chuàng)建它,就不能更改它的值。但可以基于一個(gè) Duration 對(duì)象創(chuàng)建新的 Duration 對(duì)象。
創(chuàng)建 Duration 對(duì)象
可以使用 Duration 類的工廠方法之一創(chuàng)建 Duration 對(duì)象,有 between()/ofDays()/ofSeconds()/from() 等方法,但其底層都是調(diào)用了同一個(gè)構(gòu)造方法,其源碼如下:
private Duration(long seconds, int nanos) {
super();
this.seconds = seconds;
this.nanos = nanos;
}
下面是一個(gè)使用 between() 方法創(chuàng)建的示例:
Instant first = Instant.now();
// 其他耗時(shí)操作
Instant second = Instant.now();
Duration duration = Duration.between(first, second);
訪問 Duration 對(duì)象的時(shí)間信息
從上述構(gòu)造器源碼可知,Duration 在內(nèi)部維護(hù)兩個(gè)值:
- final int nanos;
- final long seconds;
請(qǐng)注意沒有單獨(dú)的毫秒部分,只有納秒和秒。但可以可以將整個(gè)時(shí)間間隔 Duration 轉(zhuǎn)換為其他時(shí)間單位,如納秒、分鐘、小時(shí)或天:
- long toNanos()
- long toMillis()
- long toMinutes()
- long toHours()
- long toDays()
toNanos() 與 getNano() 的不同之處在于 getNano() 僅返回持續(xù)時(shí)間小于一秒的部分(即整個(gè)時(shí)間段中不到 1 秒的那部分)。 toNanos() 方法返回的是轉(zhuǎn)換為納秒的整個(gè)時(shí)間段(即秒部分轉(zhuǎn)成納秒+納秒部分)。
沒有 toSeconds() 方法,因?yàn)?getSeconds() 方法已經(jīng)可以獲取 Duration 的秒部分。
Duration 的計(jì)算
Duration 類包含一組可用于基于 Duration 對(duì)象執(zhí)行計(jì)算的方法。其中一些方法是:
- Duration plus(Duration duration)
- Duration plusNanos(long)
- Duration plusMillis(long)
- Duration plusSeconds(long)
- Duration plusMinutes(long)
- Duration plusHours(long)
- Duration plusDays(long)
- Duration minusXxx(long) 上面所有對(duì)應(yīng) minus 方法
這些方法的使用大同小異,一下是一個(gè)例子:
Duration start = ...
Duration added = start.plusDays(3); // 加 3 天
Duration subtracted = start.minusDays(3); // 減 3 天
同樣,為了使Duration對(duì)象保持不可變,所有計(jì)算方法都返回表示計(jì)算結(jié)果的新的 Duration 對(duì)象。
LocalDate 表示本地日期
java.time.LocalDate 表示本地日期,沒有時(shí)區(qū)信息。當(dāng)?shù)氐娜掌诳梢允巧栈蚍ǘ偃盏?,與一年中的某一天有關(guān),和一天中的某一時(shí)間無關(guān)。這個(gè)類對(duì)象也是不可變的,計(jì)算操作會(huì)返回一個(gè)新的 LocalDate 對(duì)象。
下面是一個(gè)創(chuàng)建 LocalDate 對(duì)象的例子:
LocalDate localDate1 = LocalDate.now();
LocalDate localDate2 = LocalDate.of(2018, 11, 11);
還有很多方法可以創(chuàng)建 LocalDate 對(duì)象,我列出一部分下面,具體的請(qǐng)查看 JavaDoc 。
訪問 LocalDate 中的日期信息
LocalDate 中一共有 3 個(gè)日期信息字段,分別是:
- final int year;
- final short month;
- final short day;
對(duì)應(yīng)一些獲取信息的方法:
- int getYear()
- Month getMonth()
- int getDayOfMonth()
- int getDayOfYear()
- DayOfWeek getDayOfWeek()
LocalDate 計(jì)算
- LocalDate plusYears(long yearsToAdd)
- LocalDate plusMonths(long monthsToAdd)
- LocalDate plusWeeks(long weeksToAdd)
- LocalDate plusDays(long daysToAdd)
- LocalDate minusXxx(long xxxToSubtract) 對(duì)應(yīng)上面 plus 方法的 minus 版本
下面是一個(gè)例子:
LocalDate localDate = LocalDate.of(2018, 12, 12);
LocalDate localDate1 = localDate.plusYears(3); // 加 3 年
LocalDate localDate2 = localDate.minusYears(3);
LocalTime 表示本地時(shí)間
java.time.LocalTime 表示沒有任何時(shí)區(qū)信息的特定時(shí)間,例如,上午 10 點(diǎn)。同樣,這是一個(gè)不可變類。
下面是一個(gè)創(chuàng)建 LocalTime 對(duì)象的例子:
LocalTime localTime1 = LocalTime.now();
LocalTime localTime2 = LocalTime.of(21, 30, 59, 11001);
LocalTime 內(nèi)部維護(hù)了 4 個(gè)變量維護(hù)時(shí)間信息:
- final byte hour;
- final byte minute;
- final byte second;
- final int nano;
也包含了必要的計(jì)算時(shí)間的方法,例如 LocalTime plusHours(long hoursToAdd); 其他的和 LocalDate 大同小異,就不展開講了。
LocalDateTime 表示本地日期和時(shí)間
java.time.LocalDateTime 類表示沒有任何時(shí)區(qū)信息的本地日期和時(shí)間,同樣是不可變類。
查看其源碼發(fā)現(xiàn)其內(nèi)部就是維護(hù)了一個(gè) LocalDate 對(duì)象和一個(gè) LocalTime 對(duì)象來表示日期時(shí)間信息。
final LocalDate date;
final LocalTime time;
所以完全可以把它看成是 LocalDate 和 LocalTime 的結(jié)合。
下面是一個(gè)創(chuàng)建 LocalDateTime 對(duì)象的例子:
LocalDateTime localDateTime1 = LocalDateTime.now();
LocalDateTime localDateTime2 =LocalDateTime.of(2018, 11, 11, 10, 55, 36, 123);
上面第二行代碼使用 of() 工廠方法創(chuàng)建對(duì)象,其參數(shù)分別對(duì)應(yīng)年月日時(shí)分秒納秒。
其他獲取日期時(shí)間信息和計(jì)算請(qǐng)參考 LocalDate 和 LocalTime 的。
ZonedDateTime 表示帶有時(shí)區(qū)信息的日期和時(shí)間
java.time.ZonedDateTime 可以用來代表世界上某個(gè)特定事件的開始,比如會(huì)議、火箭發(fā)射等等。
它同樣是不可變類,下面是一個(gè)創(chuàng)建此類對(duì)象的例子:
ZonedDateTime zonedDateTime = ZonedDateTime.now();
ZoneId zoneId = ZoneId.of("UTC+1");
ZonedDateTime zonedDateTime2 = ZonedDateTime.of(2015, 11, 30, 23, 45, 59, 1234, zoneId);
時(shí)區(qū)
時(shí)區(qū)由 ZoneId 類表示,如前面的示例所示??梢允褂?ZoneId.now() 方法創(chuàng)建 ZoneId 對(duì)象。也可以使用 of() 方法指定時(shí)區(qū)信息,下面是一個(gè)例子:
ZoneId zoneId1 = ZoneId.of("UTC+1");
ZoneId zoneId2 = ZoneId.of("Europe/Paris");
傳遞給 of() 方法的參數(shù)是要為其創(chuàng)建 ZoneId 的時(shí)區(qū)的ID。在上面的例子中,ID 是“UTC+1”,它是 UTC (格林威治)時(shí)間的偏移量。另外也可以直接指定具體的時(shí)區(qū) ID 字符串,這在本文開頭有介紹。
ZonedDateTime 相比 LocalDateTime 只是多了地區(qū)信息,其內(nèi)部維護(hù)了下面這 3 個(gè)變量來表示日期信息和地區(qū):
- final LocalDateTime dateTime;
- final ZoneOffset offset;
- final ZoneId zone;
所以其他的方法如獲取日期時(shí)間信息和計(jì)算時(shí)間,請(qǐng)參考上述。
DateTimeFormatter
java.time.DateTimeFormatter 類用于解析和格式化用 Java 8 日期時(shí)間 API 中的類表示的日期。
預(yù)定義 DateTimeFormatter 對(duì)象
DateTimeFormatter 類包含一組預(yù)定義的(常量)實(shí)例,這些實(shí)例可以解析和格式化來自標(biāo)準(zhǔn)日期格式的日期。這省去了為 DateTimeFormatter 定義日期格式的麻煩。包含的部分預(yù)定義實(shí)例如下:
BASIC_ISO_DATE
ISO_LOCAL_DATE
ISO_LOCAL_TIME
ISO_LOCAL_DATE_TIME
ISO_OFFSET_DATE
ISO_ZONED_DATE_TIME
這些預(yù)定義的 DateTimeFormatter 實(shí)例中的每一個(gè)都預(yù)先配置為格式化和解析不同格式的日期。 這里不解釋所有這些預(yù)定義的 DateTimeFormatter 實(shí)例。 可以在 JavaDoc 中查看。
格式化 Date 的例子
DateTimeFormatter formatter = DateTimeFormatter.BASIC_ISO_DATE;
String formattedDate = formatter.format(LocalDate.now());
System.out.println(formattedDate); // 20181204
String formattedZonedDate = formatter.format(ZonedDateTime.now());
System.out.println("formattedZonedDate = " + formattedZonedDate);// 20181204+0800
最后一行輸出 20181204+0800 代表 UTC+8 時(shí)區(qū)的 2019 年、第 12 個(gè)月(12 月)和第 4 天(第 4 天)。