CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-jetbrains-kotlinx--kotlinx-datetime-jvm

A multiplatform Kotlin library for working with date and time with JVM target support.

Pending
Overview
Eval results
Files

formatting.mddocs/

Formatting System

This document covers the comprehensive parsing and formatting system for all datetime types, including the builder DSL, predefined formats, and DateTimeComponents for complex parsing scenarios.

DateTimeFormat Interface

The base interface for all datetime formatting operations.

sealed interface DateTimeFormat<T> {
    // Format value to string
    fun format(value: T): String
    
    // Format value to appendable
    fun <A : Appendable> formatTo(appendable: A, value: T): A
    
    // Parse string to value
    fun parse(input: CharSequence): T
    
    // Parse string to value or return null if invalid
    fun parseOrNull(input: CharSequence): T?
}

// Companion object for utility functions
object DateTimeFormat.Companion {
    fun formatAsKotlinBuilderDsl(format: DateTimeFormat<*>): String
}

Format Builders

Each datetime type provides a format builder function for creating custom formats using a DSL.

LocalDate Format Builder

fun LocalDate.Companion.Format(
    block: DateTimeFormatBuilder.WithDate.() -> Unit
): DateTimeFormat<LocalDate>

// Builder interface for date formatting
interface DateTimeFormatBuilder.WithDate {
    // Year formatting
    fun year(padding: Padding = Padding.ZERO)
    fun yearTwoDigits(baseYear: Int)
    
    // Month formatting
    fun monthNumber(padding: Padding = Padding.ZERO)
    fun monthName(names: MonthNames)
    fun monthAbbreviated(names: MonthNames)
    
    // Day formatting
    fun dayOfMonth(padding: Padding = Padding.ZERO)
    fun dayOfYear(padding: Padding = Padding.ZERO)
    fun dayOfWeek(names: DayOfWeekNames)
    fun dayOfWeekAbbreviated(names: DayOfWeekNames)
    
    // Literal text
    fun chars(value: String)
    fun char(value: Char)
    
    // Alternative formats
    fun alternativeParsing(block: DateTimeFormatBuilder.WithDate.() -> Unit)
}

LocalTime Format Builder

fun LocalTime.Companion.Format(
    block: DateTimeFormatBuilder.WithTime.() -> Unit
): DateTimeFormat<LocalTime>

// Builder interface for time formatting
interface DateTimeFormatBuilder.WithTime {
    // Hour formatting
    fun hour(padding: Padding = Padding.ZERO)
    fun hourOfAmPm(padding: Padding = Padding.ZERO)
    fun amPmHour(padding: Padding = Padding.ZERO)
    fun amPmMarker(am: String, pm: String)
    
    // Minute and second formatting
    fun minute(padding: Padding = Padding.ZERO)
    fun second(padding: Padding = Padding.ZERO)
    
    // Fractional second formatting
    fun secondFraction(fixedLength: Int)
    fun secondFraction(minLength: Int, maxLength: Int)
    
    // Literal text
    fun chars(value: String)
    fun char(value: Char)
    
    // Alternative formats
    fun alternativeParsing(block: DateTimeFormatBuilder.WithTime.() -> Unit)
}

LocalDateTime Format Builder

fun LocalDateTime.Companion.Format(
    block: DateTimeFormatBuilder.WithDateTime.() -> Unit
): DateTimeFormat<LocalDateTime>

// Builder interface combining date and time formatting
interface DateTimeFormatBuilder.WithDateTime : 
    DateTimeFormatBuilder.WithDate, 
    DateTimeFormatBuilder.WithTime {
    
    // Date component
    fun date(format: DateTimeFormat<LocalDate>)
    
    // Time component
    fun time(format: DateTimeFormat<LocalTime>)
    
    // Combined date and time with separator
    fun dateTime(
        dateFormat: DateTimeFormat<LocalDate>,
        timeFormat: DateTimeFormat<LocalTime>,
        separator: String = "T"
    )
}

YearMonth Format Builder

fun YearMonth.Companion.Format(
    block: DateTimeFormatBuilder.WithYearMonth.() -> Unit
): DateTimeFormat<YearMonth>

// Builder interface for year-month formatting
interface DateTimeFormatBuilder.WithYearMonth {
    // Year formatting
    fun year(padding: Padding = Padding.ZERO)
    fun yearTwoDigits(baseYear: Int)
    
    // Month formatting
    fun monthNumber(padding: Padding = Padding.ZERO)
    fun monthName(names: MonthNames)
    fun monthAbbreviated(names: MonthNames)
    
    // Literal text
    fun chars(value: String)
    fun char(value: Char)
    
    // Alternative formats
    fun alternativeParsing(block: DateTimeFormatBuilder.WithYearMonth.() -> Unit)
}

UtcOffset Format Builder

fun UtcOffset.Companion.Format(
    block: DateTimeFormatBuilder.WithUtcOffset.() -> Unit
): DateTimeFormat<UtcOffset>

// Builder interface for UTC offset formatting
interface DateTimeFormatBuilder.WithUtcOffset {
    // Offset formatting
    fun offset(format: UtcOffsetFormat)
    fun offsetHours(padding: Padding = Padding.ZERO)
    fun offsetMinutesOfHour(padding: Padding = Padding.ZERO)
    fun offsetSecondsOfMinute(padding: Padding = Padding.ZERO)
    
    // Literal text
    fun chars(value: String)
    fun char(value: Char)
    
    // Alternative formats
    fun alternativeParsing(block: DateTimeFormatBuilder.WithUtcOffset.() -> Unit)
}

Predefined Formats

Each datetime type provides commonly used predefined formats through its Formats object.

LocalDate Formats

object LocalDate.Formats {
    // ISO 8601 format: "2023-12-25"
    val ISO: DateTimeFormat<LocalDate>
    
    // ISO basic format: "20231225"
    val ISO_BASIC: DateTimeFormat<LocalDate>
}

LocalTime Formats

object LocalTime.Formats {
    // ISO 8601 format: "14:30:00" or "14:30:00.123456789"
    val ISO: DateTimeFormat<LocalTime>
}

LocalDateTime Formats

object LocalDateTime.Formats {
    // ISO 8601 format: "2023-12-25T14:30:00" or "2023-12-25T14:30:00.123456789"
    val ISO: DateTimeFormat<LocalDateTime>
}

YearMonth Formats

object YearMonth.Formats {
    // ISO 8601 format: "2023-12"
    val ISO: DateTimeFormat<YearMonth>
}

UtcOffset Formats

object UtcOffset.Formats {
    // ISO 8601 format: "+01:00", "-05:30", "Z"
    val ISO: DateTimeFormat<UtcOffset>
    
    // Four digits format: "+0100", "-0530", "+0000"
    val FOUR_DIGITS: DateTimeFormat<UtcOffset>
}

DateTimeComponents

Intermediate representation for parsing and formatting complex datetime values that may include timezone information and partial data.

class DateTimeComponents {
    // Date components
    var year: Int?
    var monthNumber: Int?
    var dayOfMonth: Int?
    var dayOfYear: Int?
    var dayOfWeek: DayOfWeek?
    
    // Time components
    var hour: Int?
    var hourOfAmPm: Int?
    var isAmPm: Boolean?
    var minute: Int?
    var second: Int?
    var nanosecond: Int?
    
    // Offset components
    var offsetIsNegative: Boolean?
    var offsetHours: Int?
    var offsetMinutesOfHour: Int?
    var offsetSecondsOfMinute: Int?
    
    // Timezone component
    var timeZoneId: String?
    
    // Conversion methods
    fun toLocalDate(): LocalDate
    fun toLocalTime(): LocalTime
    fun toLocalDateTime(): LocalDateTime
    fun toUtcOffset(): UtcOffset
    fun toInstantUsingOffset(): Instant
}

DateTimeComponents Format Builder

fun DateTimeComponents.Companion.Format(
    block: DateTimeFormatBuilder.WithDateTimeComponents.() -> Unit
): DateTimeFormat<DateTimeComponents>

// Builder interface for complex datetime formatting
interface DateTimeFormatBuilder.WithDateTimeComponents :
    DateTimeFormatBuilder.WithDate,
    DateTimeFormatBuilder.WithTime,
    DateTimeFormatBuilder.WithUtcOffset {
    
    // Timezone formatting
    fun timeZoneId()
    
    // Optional sections
    fun optional(vararg format: String, block: DateTimeFormatBuilder.WithDateTimeComponents.() -> Unit)
}

DateTimeComponents Predefined Formats

object DateTimeComponents.Formats {
    // ISO 8601 with offset: "2023-12-25T14:30:00+01:00"
    val ISO_DATE_TIME_OFFSET: DateTimeFormat<DateTimeComponents>
    
    // RFC 1123: "Mon, 25 Dec 2023 14:30:00 GMT"
    val RFC_1123: DateTimeFormat<DateTimeComponents>
}

Padding Options

enum class Padding {
    // No padding during formatting, optional during parsing
    NONE,
    
    // Pad with zeros during formatting, required during parsing
    ZERO,
    
    // Pad with spaces during formatting, required during parsing
    SPACE
}

Usage Examples

Basic Format Builder Usage

// Custom date format: "25/12/2023"
val customDateFormat = LocalDate.Format {
    dayOfMonth(Padding.ZERO)
    char('/')
    monthNumber(Padding.ZERO)
    char('/')
    year()
}

val date = LocalDate(2023, 12, 25)
val formatted = date.format(customDateFormat) // "25/12/2023"
val parsed = LocalDate.parse("01/01/2024", customDateFormat)

Advanced Time Formatting

// 12-hour format with AM/PM: "2:30 PM"
val twelveHourFormat = LocalTime.Format {
    amPmHour(Padding.NONE)
    char(':')
    minute(Padding.ZERO)
    char(' ')
    amPmMarker("AM", "PM")
}

val time = LocalTime(14, 30)
val formatted = time.format(twelveHourFormat) // "2:30 PM"

Complex DateTime Formatting

// European style with timezone: "25. December 2023, 14:30 CET"
val europeanFormat = DateTimeComponents.Format {
    dayOfMonth(Padding.NONE)
    chars(". ")
    monthName(MonthNames.ENGLISH_FULL)
    char(' ')
    year()
    chars(", ")
    hour(Padding.ZERO)
    char(':')
    minute(Padding.ZERO)
    char(' ')
    timeZoneId()
}

Using Predefined Formats

// Using ISO formats
val date = LocalDate(2023, 12, 25)
val isoDate = date.format(LocalDate.Formats.ISO) // "2023-12-25"

val dateTime = LocalDateTime(2023, 12, 25, 14, 30, 45, 123_456_789)
val isoDateTime = dateTime.format(LocalDateTime.Formats.ISO) // "2023-12-25T14:30:45.123456789"

// Parse using predefined formats
val parsedDate = LocalDate.parse("2023-12-25") // Uses ISO format by default
val parsedDateTime = LocalDateTime.parse("2023-12-25T14:30:45", LocalDateTime.Formats.ISO)

Working with DateTimeComponents

// Parse complex datetime string with timezone
val complexFormat = DateTimeComponents.Formats.ISO_DATE_TIME_OFFSET
val components = DateTimeComponents.parse("2023-12-25T14:30:00+01:00", complexFormat)

// Extract different representations
val instant = components.toInstantUsingOffset()
val localDateTime = components.toLocalDateTime()
val offset = components.toUtcOffset()

// Access individual components
val year = components.year // 2023
val timeZoneId = components.timeZoneId // null (offset-based, not zone-based)

Alternative Parsing

// Accept multiple date formats during parsing
val flexibleDateFormat = LocalDate.Format {
    year()
    alternativeParsing {
        char('-')
        monthNumber(Padding.ZERO)
        char('-')
        dayOfMonth(Padding.ZERO)
    }
    alternativeParsing {
        char('/')
        monthNumber(Padding.ZERO)
        char('/')
        dayOfMonth(Padding.ZERO)
    }
}

// Can parse both "2023-12-25" and "2023/12/25"
val date1 = LocalDate.parse("2023-12-25", flexibleDateFormat)
val date2 = LocalDate.parse("2023/12/25", flexibleDateFormat)

Error Handling

// Safe parsing with null return
val maybeDate = LocalDate.parseOrNull("invalid-date") // returns null

// Exception-based parsing
try {
    val date = LocalDate.parse("invalid-date") // throws DateTimeFormatException
} catch (e: DateTimeFormatException) {
    println("Failed to parse date: ${e.message}")
}

Integration with Instant Parsing

// Parse Instant with custom DateTimeComponents format
val instantFormat = DateTimeComponents.Format {
    year()
    char('-')
    monthNumber(Padding.ZERO)
    char('-')
    dayOfMonth(Padding.ZERO)
    char(' ')
    hour(Padding.ZERO)
    char(':')
    minute(Padding.ZERO)
    char(':')
    second(Padding.ZERO)
    char(' ')
    offset(UtcOffsetFormat.FOUR_DIGITS)
}

val instant = Instant.parse("2023-12-25 14:30:00 +0100", instantFormat)

Install with Tessl CLI

npx tessl i tessl/maven-org-jetbrains-kotlinx--kotlinx-datetime-jvm

docs

core-types.md

formatting.md

index.md

jvm-interop.md

periods-units.md

serialization.md

tile.json