byUnicodePattern

Appends a Unicode datetime format string to the DateTimeFormatBuilder.

This is the format string syntax used by the Java Time's DateTimeFormatter class, Swift's and Objective-C's NSDateFormatter class, and the ICU library. The syntax is specified at https://unicode-org.github.io/icu/userguide/format_parse/datetime/#datetime-format-syntax.

Currently, locale-aware directives are not supported, due to no locale support in Kotlin.

In addition to the standard syntax, this function also supports the following extensions:

  • [] denote optional sections. For example, hh:mm[:ss] will allow parsing seconds optionally. This is similar to what is supported by the Java Time's DateTimeFormatter class.

Usage example:

DateTimeComponents.Format {
// 2023-01-20T23:53:16.312+03:30[Asia/Tehran]
byUnicodePattern("uuuu-MM-dd'T'HH:mm[:ss[.SSS]]xxxxx'['VV']'")
}

The list of supported directives is as follows:

DirectiveMeaning
'string'literal string, without quotes
'''literal char '
[fmt]equivalent to fmt during formatting, but during parsing also accepts the empty string
uISO year without padding
uulast two digits of the ISO year, with the base year 2000
uuuuISO year, zero-padded to four digits
M, Lmonth number (1-12), without padding
MM, LLmonth number (01-12), zero-padded to two digits
dday-of-month (1-31), without padding
Hhour-of-day (0-23), without padding
HHhour-of-day (00-23), zero-padded to two digits
mminute-of-hour (0-59), without padding
mmminute-of-hour (00-59), zero-padded to two digits
ssecond-of-hour (0-59), without padding
sssecond-of-hour (00-59), zero-padded to two digits
S, SS, SSS...fraction-of-second without a leading dot, with as many digits as the format length
VVtimezone name (for example, Europe/Berlin)

The UTC offset is formatted using one of the following directives. In every one of these formats, hours, minutes, and seconds are zero-padded to two digits. Also, hours are unconditionally present.

DirectiveMinutesSecondsSeparatorRepresentation of zero
Xunless zeronevernoneZ
XXalwaysnevernoneZ
XXXalwaysnevercolonZ
XXXXalwaysunless zerononeZ
XXXXX, ZZZZZalwaysunless zerocolonZ
xunless zeronevernone+00
xx, Z, ZZ, ZZZalwaysnevernone+0000
xxxalwaysnevercolon+00:00
xxxxalwaysunless zeronone+0000
xxxxxalwaysunless zerocolon+00:00

Additionally, because the y directive is very often used instead of u, they are taken to mean the same. This may lead to unexpected results if the year is negative: y would always produce a positive number, whereas u may sometimes produce a negative one. For example:

LocalDate(-10, 1, 5).format { byUnicodeFormat("yyyy-MM-dd") } // -0010-01-05
LocalDate(-10, 1, 5).toJavaLocalDate().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")) // 0011-01-05

Note that, when the format includes the era directive, byUnicodePattern will fail with an exception, so almost all of the intentional usages of y will correctly report an error instead of behaving slightly differently.

Throws

if the builder is incompatible with the specified directives.

if the kotlinx-datetime library does not support the specified directives.

Samples

import kotlinx.datetime.*
import kotlinx.datetime.format.*
import kotlin.test.*

fun main() { 
   //sampleStart 
   // Using the Unicode pattern to define a custom format and obtain the corresponding Kotlin code
val customFormat = LocalDate.Format {
    @OptIn(FormatStringsInDatetimeFormats::class)
    byUnicodePattern("MM/dd uuuu")
}
check(customFormat.format(LocalDate(2021, 1, 13)) == "01/13 2021")
check(
    DateTimeFormat.formatAsKotlinBuilderDsl(customFormat) == """
        monthNumber()
        char('/')
        dayOfMonth()
        char(' ')
        year()
    """.trimIndent()
) 
   //sampleEnd
}