一篇文章概括 Java Date Time 的使用

本文目的:掌握 Java 中日期和時(shí)間常用 API 的使用。
參考:Jakob Jenkov的英文教程Java Date Time TutorialJavaDoc

概覽

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ò)的地方

  1. Calendar 類的 MONTH 字段不是往常的從 1 到 12 。而是從 0 到 11 ,其中 0 是一月,11 是十二月。
  2. 一周的某一天是從 1 到 7 表示,這點(diǎn)不出意料,但是一周的第一天是星期日而不是星期一,這意味著 1 =星期日,2 =星期一,7 =星期六。
  3. 如果需要進(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 天)。


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 除了lambda表達(dá)式,stream以及幾個(gè)小的改進(jìn)之外,Java 8還引入了一套全新的時(shí)間日期API,在本篇教程...
    帶娃兒先走閱讀 1,399評(píng)論 0 6
  • 外公今年七十有余,這些年沒種莊稼了,腿腳反而不利索,走起路來顫巍巍的。晚上他在房間里看莆仙戲、寫字,今天看《春草闖...
    陳廠長閱讀 326評(píng)論 0 3
  • 幾年前,李老師對(duì)我說,來新疆一定要走一趟獨(dú)庫公路,后來,身邊不止一個(gè)人跟我提起獨(dú)庫公路,這個(gè)夙愿直到今天才實(shí)現(xiàn)! ...
    邱玲melody閱讀 2,648評(píng)論 1 5

友情鏈接更多精彩內(nèi)容