kotlinx-datetime
kotlinx-datetime copied to clipboard
DateTimeComponents.Format parse throws an exception when timeZoneId() is UTC
I have this piece of code to handle a Long date (20241016153100) to an ISO8106 date, it works for most of the cases, but if tz is UTC, the id will be Z, and throw an exception.
DateTimeComponents.Format {
year()
monthNumber()
dayOfMonth()
hour()
minute()
second()
char('|')
timeZoneId()
}.parse("$date|${(tz.id)}").let {
buildString {
append(it.year.toString().padStart(2, '0'))
append('-')
append(it.monthNumber.toString().padStart(2, '0'))
append('-')
append(it.dayOfMonth.toString().padStart(2, '0'))
append('T')
append(it.hour.toString().padStart(2, '0'))
append(':')
append(it.minute.toString().padStart(2, '0'))
append(':')
append(it.second.toString().padStart(2, '0'))
append(tz.offsetAt(it.toInstantUsingOffset()).asTimeZone().offset.toString())
}
}
Errors: position 15: 'Expected timeZoneId but got ', position 0: 'Expected - but got 2', position 0: 'Expected + but got 2'kotlinx.datetime.DateTimeFormatException: Failed to parse value from '20231013000000|Z'
The workaround I have now is to change Z to Europe/London and it seems to works, but it would seems fair that timeZoneId could recognise Z as a valid timeZoneId.
Would this work instead?
import kotlinx.datetime.*
import kotlinx.datetime.format.*
fun main() {
val tz = TimeZone.UTC
val date = "20231013000000"
val ldt = LocalDateTime.Format {
year()
monthNumber()
dayOfMonth()
hour()
minute()
second()
}.parse(date)
val instant = ldt.toInstant(tz)
println(instant.format(DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET, tz.offsetAt(instant)))
}
Runnable version: https://pl.kotl.in/wJEhu6YbS
- Why put the timezone into a string just to immediately parse it back?
.asTimeZone().offsetshouldn't do anything.append(x.toString())is the same asappend(x): seeappend(value: Any?)in https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/-string-builder/append.html- Formatting in ISO 8601 by hand is not needed, we have such formatters already. For
Instant, that'sDateTimeComponents.Formats.ISO_DATE_TIME_OFFSET. - There is no reason to parse
DateTimeComponentswhen all you have is aLocalDateTime. - The year is padded to two digits, you probably meant 4. Also, wrong results for negative years.