Android 使用LocalDate、LocalTime、LocalDateTime等Java8的日期時間

Evan Chen
Evan Android Note
Published in
9 min readJan 13, 2021

以往在Android處理日期時間Date(java.util.Date)Calendar(java.util.Calendar)有一些不太方便的地方。到了Java 8 有了新的日期類別來處理:

LocalDate 表示一個日期
LocalTime 表示不含日期的時間
LocalDateTime 表示日期與時間
ZonedDateTime 包含時區的時間
Duration、Period 時間長度

在Java8的日期(java.time)雖然好用,但以前要使用LocalDate這些就會有minSdkVersion 26 以上才能使用的限制(如下圖),所以也很難真的在Android上使用。

但在gradle:4.0.0 以上有了Java 8+ API desugaring support,也就不受需要API 26以上的限制了。

build.gradle(Project)

首先當然你的gradle版本要在4.0.0以上

dependencies {
classpath "com.android.tools.build:gradle:4.0.0"
}

build.gralde(Module)

android {
defaultConfig {
// Required when setting minSdkVersion to 20 or lower
multiDexEnabled true
}
compileOptions {
// Flag to enable support for the new language APIs
coreLibraryDesugaringEnabled true
// Sets Java compatibility to Java 8
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8

}
}
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.0.9'
}

改好了Gradle之後Sync,就可以使用Java 8 的日期了。

LocalDate、LocalTime、LocalDateTime

以Local 開頭的這3個都是沒有包含時區的日期與時間。例如要表示生日是2000–01–01,不管在什麼時區,你都會說你的生日都是2000–01–01。

LocalDate

LocalDate 僅有日期資訊,沒有時間

//取得現在日期
val date = LocalDate.now()
//特定日期,如2021-1-1
val date = LocalDate.of(2021, 1, 1)

LocalTime

LocalDate 僅有時間資訊,沒有日期

//13:40:50
val time = LocalTime.of(13, 40, 50)

LocalDateTime

同時有日期與時間

//2021-1-1 13:40:50.30
val datetime = LocalDateTime.of(2021, 1, 1, 13, 40, 50, 30)

建立日期時間的方式,除了上方用的of,也可以用parse的方式。

val date = LocalDate.parse("2021-01-01")val time = LocalTime.parse("13:40:50")val dateTime = LocalDateTime.parse("2021-01-01T13:40:50")

如果要用自定的格式來建立日期時間,就可以使用DateTimeFormatter

val dateTime = LocalDateTime.parse(
"2021/01/01 13:40:50",
DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss")
)

建立時間後,就可以直接取得這些資訊

//2021/01/01 13:40:50
dateTime.year //2021
dateTime.monthValue //1
dateTime.month //JANUARY
dateTime.dayOfMonth //1
dateTime.dayOfWeek //FRIDAY
dateTime.hour //13
dateTime.minute //40
dateTime.second //50

格式化時間(日期轉字串)

//dateTime: 2021-01-01 13:40:50//20210101
dateTime.format(DateTimeFormatter.BASIC_ISO_DATE)
//2021-01-01
dateTime.format(DateTimeFormatter.ISO_LOCAL_DATE)
//13:40:50
dateTime.format(DateTimeFormatter.ISO_LOCAL_TIME)
//2021/01/01
dateTime.format(DateTimeFormatter.ofPattern("yyyy/MM/dd"))

時間的加減

dateTime.plusDays(1) //加一天
dateTime.plusWeeks(1) //加一週
dateTime.plusMonths(1) //加一個月

TemporalAdjusters

用來取得這個月的最後一天、今年的最後一天等這些資訊

//dateTime=2021/01/01 13:40:50//這個月的最後一天 2021-01-31T13:40:50
dateTime.with(TemporalAdjusters.lastDayOfMonth())

dayOfWeekInMonth 每週的第幾天
firstDayOfMonth 當月第一天
firstDayOfNextMonth 下個月的第一天
firstDayOfNextYear 明年的第一天
firstDayOfYear 今年的第一天
firstInMonth 當月的第一個星期幾
lastDayOfMonth 當月最後一天
lastDayOfNextMonth 下個月的最後一天
lastDayOfNextYear 明年的最後一天
lastDayOfYear 今年的最後一天
lastInMonth 當月的最後一個星期幾

比較時間

dateTime.isBefore(LocalDateTime.parse("2021-01-02T13:40:50")) //true
dateTime.isAfter(LocalDateTime.parse("2021-01-02T13:40:50")) //false

Period

用來定義時間長度,你可以用來計算兩個時間的間距。

val startDate = LocalDate.of(2021, 1, 1)val endDate = LocalDate.of(2021, 1, 3)val period = Period.between(startDate, endDate) //P2Dperiod.days //幾天
period.months //幾個月
period.years //幾年
//自定義Period
Period.parse("P2D")

Duration

跟Period一樣是用來定義時間長度,但時間單位更小

val startDateTime = LocalDateTime.parse("2021-01-02T13:40:50")val endDateTime = LocalDateTime.parse("2021-01-02T13:40:51.11")val duration = Duration.between(startDateTime, endDateTime) //PT1.11Sduration.seconds //幾秒//自定義Duration
Period.parse("PT1.11S")

ZonedDateTime

ZonedDateTime則是包含了時區的日期時間。你可以加上ZoneId來建立一個含有時區的時間。

val dateTime = ZonedDateTime.of(
LocalDateTime.parse("2021-01-02T13:10:00"),
ZoneId.of("UTC+8"))

ZoneId

用ZoneId來建立一個時區的代碼

val zoneId = ZoneId.of("UTC+8")

取得所有時區,像是Asia/Tokyo、America/Los_Angeles、UCT、GMT

ZoneId.getAvailableZoneIds()

有了ZonedDateTime,就可以把不同時區的時間來比較。例如我要計算台北飛東京的飛行時間。

台北起飛:2021–01–02 13:10 (台北時間)
東京抵達:2021–01–02 16:40 (東京時間)

//台北出發2021-01-02 13:10
val departure = ZonedDateTime.of(
LocalDateTime.parse("2021-01-02T13:10:00"),
ZoneId.of("UTC+8")
)
//東京抵達2021-01-02 16:40
val arrival = ZonedDateTime.of(
LocalDateTime.parse("2021-01-02T16:40:00"),
ZoneId.of("Asia/Tokyo")
)
//飛行時間2小時30分
val duration = Duration.between(departure, arrival)
println(duration) //PT2H30M

參考:

https://developer.android.com/studio/write/java8-support#library-desugaring

--

--