Formatting and Parsing
KInstant, KZonedInstant, KZonedDateTime and KDuration can be serialized to Strings with custom formats. In reverse, Strings can be parsed into KZonedDateTime, which can be further converted to KInstant and KZonedInstant, using custom formats. Needless to say, the standard ISO 8601 format is supported out-of-the-box.
Supported formats are as follows:
| Symbol | Meaning | Examples |
|---|---|---|
| y | year | 2023; 23 |
| M | month | 7; 07 |
| MMM | month short name | Feb |
| MMMM | month long name | February |
| d | day of month | 9; 09; 31 |
| H | hour (0~23) | 0; 00; 18 |
| h | hour (1~12) | 6; 06; 10 |
| m | minute | 4; 04; 58 |
| s | second | 5; 05; 59 |
| l | millisecond | 12; 012; 120; 123 |
| aa | am/pm | am; pm |
| AA | AM/PM | AM; PM |
| e | Day of week. 0 = Sun, 6 = Sat | 1 |
| E | Day of week | Mon |
| Z | Time zone offset or 'Z' | Z; +08:00 |
| z | Time zone offset | +00:00; +08:00 |
| ' | Literal | ' |
Examples
Formatting Dates, Times and Timezone Offsets
Custom Formats
val now = KInstant(timestampMs = 1694618242720)
val localDateTime = now.atLocalZoneOffset()
println(localDateTime.format("yyyy-MM-dd'T'HH:mm:ss.lllZ")) // 2023-09-13T23:17:22.720+08:00
println(localDateTime.format("yyyy-M-d h:mm:ss aa")) // 2023-9-13 11:17:22 pm
val utcTime = now at KZoneOffset(0, 0)
println(localDateTime.format("yyyy-MM-dd'T'HH:mm:ss.lllZ")) // 2023-09-13T15:17:22.720Z
println(localDateTime.format("yyyy-MM-dd'T'HH:mm:ss.lllz")) // 2023-09-13T15:17:22.720+00:00
ISO 8601 Formats
val instant = KInstant(timestampMs = 1710212523_999)
println(instant.toIso8601String()) // 2024-03-12T03:02:03Z
println(instant.toIso8601StringWithMilliseconds()) // 2024-03-12T03:02:03.999Z
val zonedInstant = KZonedInstant(timestampMs = 1710212523_999, zoneOffset = KZoneOffset(hours = 8, minutes = 0))
println(zonedInstant.toIso8601String()) // 2024-03-12T11:02:03+08:00
println(zonedInstant.toIso8601StringWithMilliseconds()) // 2024-03-12T11:02:03.999+08:00
val zonedDateTime = KZonedDateTime(year = 2024, month = 3, day = 12, hour = 5, minute = 12, second = 3, millisecond = 999, zoneOffset = KZoneOffset(hours = 8, minutes = 0))
println(zonedDateTime.toIso8601String()) // 2024-03-12T05:12:03+08:00
println(zonedDateTime.toIso8601StringWithMilliseconds()) // 2024-03-12T05:12:03.999+08:00
Formatting Durations and Literals
val duration1 = 95.seconds()
println(duration1.format("m:ss")) // 1:35
println(duration1.format("m'm' s's'")) // 1m 35s
Formatting Localized Weekdays
val dateTime = KInstant(1705677172000) // Friday, January 19, 2024 3:12:52 PM GMT
val formatter = KDateTimeFormat("E")
println(formatter.format(dateTime)) // Fri
formatter.weekDayNames = listOf("星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六")
println(formatter.format(dateTime)) // 星期五
Formatting Localized AM/PM
val dateTime = KInstant(1723698748231) // Thursday, August 15, 2024 5:12:28 AM GMT
val formatter3 = KDateTimeFormat("AA aa")
formatter3.setAmPmNames("오전", "오후")
println(formatter3.format(dateTime)) // 오전 오전
Formatting Localized Months
val zonedInstant = KInstant(1731723336012).at(KZoneOffset(8, 0)) // Sat, 16 Nov 2024 10:15:36.012 HKT
println(KDateTimeFormat(pattern = "E, dd MMM yyyy HH:mm:ss.lll Z").format(zonedInstant)) // Sat, 16 Nov 2024 10:15:36.012 +08:00
println(KDateTimeFormat(pattern = "E, dd MMMM yyyy HH:mm:ss.lll Z").format(zonedInstant)) // Sat, 16 November 2024 10:15:36.012 +08:00
KDateTimeFormat(pattern = "MMMM dd").let { formatter ->
formatter.monthLongNames = listOf("一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月")
println(formatter.format(zonedInstant)) // 十一月 16
}
KDateTimeFormat(pattern = "MMM dd").let { formatter ->
formatter.monthShortNames = listOf("一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月")
println(formatter.format(zonedInstant)) // 十一月 16
}
Parsing from Strings
Parse from ISO 8601 format without milliseconds
val time1: KZonedInstant = KZonedInstant.parseFromIso8601String("2023-09-10T17:18:53-07:00")
val time2: KZonedInstant = KDateTimeFormat.ISO8601_DATETIME
.parseToKZonedDateTime("2023-09-10T17:18:53-07:00")
.toKZonedInstant()
.also { dateTime ->
assertEquals(1694391533000, dateTime.toEpochMilliseconds())
assertEquals(-7, dateTime.zoneOffset.hours)
assertEquals(0, dateTime.zoneOffset.minutes)
}
Parse from ISO 8601 format with milliseconds
// `KZonedInstant.parseFromIso8601String` is tolerable
val time1: KZonedInstant = KZonedInstant.parseFromIso8601String("2023-09-10T17:18:53.123-07:00")
val time2: KZonedInstant = KDateTimeFormat.FULL
.parseToKZonedDateTime("2023-09-10T17:18:53.123-07:00")
.toKZonedInstant()
.also { dateTime ->
assertEquals(1694391533123, dateTime.toEpochMilliseconds())
assertEquals(-7, dateTime.zoneOffset.hours)
assertEquals(0, dateTime.zoneOffset.minutes)
}
Parse from custom formats
val time1: KZonedInstant = KZonedInstant.parseFrom(
input = "23-09-11 02:54:19pmUTC",
formats = listOf(KDateTimeFormat("yy-MM-dd hh:mm:ssaaZ"))
)
val time2: KZonedInstant = KDateTimeFormat("yy-MM-dd hh:mm:ssaaZ")
.parseToKZonedDateTime("23-09-11 02:54:19pmUTC")
.toKZonedInstant()
.also { dateTime ->
assertEquals(1694444059000, dateTime.toEpochMilliseconds())
assertEquals(0, dateTime.zoneOffset.hours)
assertEquals(0, dateTime.zoneOffset.minutes)
}
Try to parse from multiple formats
val time: KZonedInstant = KZonedInstant.parseFrom(
input = "23-09-11 02:54:19pmUTC",
formats = listOf(
KDateTimeFormat("yyyy-MM-dd hh:mm:ssaaZ"),
KDateTimeFormat("yyyy-MM-dd hh:mm:ssaa Z"),
KDateTimeFormat("yy-MM-dd hh:mm:ssaaZ"),
KDateTimeFormat("yy-MM-dd hh:mm:ssaa Z"),
)
)
Parse localized AM/PM
val time: KZonedInstant = KDateTimeFormat("yy-MM-dd hh:mm:ss A Z")
.apply { setAmPmNames("a.m.", "p.m.") }
.parseToKZonedDateTime("23-09-11 02:54:19 P.M. -01:00")
.toKZonedInstant()
Parse localized month names
val timeFromEnglishString: KZonedInstant = KDateTimeFormat("dd MMMM yyyy HH:mm:ss.lll Z")
.parseToKZonedDateTime("16 November 2024 10:15:36.012 +08:00")
.toKZonedInstant()
val timeFromChineseString: KZonedInstant = KDateTimeFormat("dd MMM yyyy HH:mm:ss.lll Z")
.apply { monthShortNames = listOf("一月", "二月", "三月", "四月", "五月", "六月", "七月", "八月", "九月", "十月", "十一月", "十二月") }
.parseToKZonedDateTime("16 十一月 2024 10:15:36.012 +08:00")
.toKZonedInstant()
Optimizing for Performance
If formatting or parsing of a specific format is frequent, please consider creating a reusable KDateTimeFormat instance to optimize runtime performance.
val formatter = KDateTimeFormat("yyyy-MM-dd'T'HH:mm:ss.lllZ")
println(formatter.format(KInstant(timestampMs = 1694618242720))) // 2023-09-13T23:17:22.720+08:00
println(formatter.format(KInstant(timestampMs = 1694618242723))) // 2023-09-13T23:17:22.723+08:00
There are also a few builtin KDateTimeFormat instances can be used directly.