CtrlK
BlogDocsLog inGet started
Tessl Logo

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

A multiplatform Kotlin library for working with date and time, specifically the iOS x64 target variant

Pending
Overview
Eval results
Files

formatting.mddocs/

Formatting and Parsing System

Comprehensive formatting and parsing system with DSL builders for creating custom date/time formats. The library supports ISO 8601 formats out of the box and provides flexible builders for custom formatting needs.

Capabilities

DateTimeFormat<T>

Core formatting interface that handles both parsing and formatting of date/time values.

/**
 * Format for parsing and formatting date/time values
 * Sealed interface providing type-safe formatting operations
 */
sealed interface DateTimeFormat<T> {
    /**
     * Format a value to string
     * @param value The value to format
     * @returns Formatted string representation
     */
    fun format(value: T): String
    
    /**
     * Format a value to an appendable
     * @param appendable Target to append the formatted value to
     * @param value The value to format
     * @returns The appendable for chaining
     */
    fun formatTo(appendable: Appendable, value: T): Appendable
    
    /**
     * Parse a string to the target type
     * @param input String to parse
     * @returns Parsed value
     * @throws DateTimeParseException if parsing fails
     */
    fun parse(input: CharSequence): T
    
    /**
     * Parse a string to the target type, returning null on failure
     * @param input String to parse
     * @returns Parsed value or null if parsing fails
     */
    fun parseOrNull(input: CharSequence): T?
    
    companion object {
        /**
         * Generate Kotlin DSL code for recreating a format
         * @param format The format to analyze
         * @returns Kotlin code string
         */
        fun formatAsKotlinBuilderDsl(format: DateTimeFormat<*>): String
    }
}

Usage Examples:

import kotlinx.datetime.*

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

// Parse from string
val parsed = LocalDate.parse("2023-12-25", LocalDate.Formats.ISO)

// Safe parsing
val maybeParsed = LocalDate.Formats.ISO.parseOrNull("invalid-date")  // null

// Format to StringBuilder
val buffer = StringBuilder()
LocalDate.Formats.ISO.formatTo(buffer, date)
println(buffer.toString())  // "2023-12-25"

Predefined Formats

Each date/time type provides predefined format constants for common use cases.

LocalDate Formats

object LocalDate.Formats {
    /** ISO 8601 extended format: YYYY-MM-DD */
    val ISO: DateTimeFormat<LocalDate>
    
    /** ISO 8601 basic format: YYYYMMDD */
    val ISO_BASIC: DateTimeFormat<LocalDate>
}

LocalTime Formats

object LocalTime.Formats {
    /** ISO 8601 extended format: HH:MM:SS[.fff] */
    val ISO: DateTimeFormat<LocalTime>
}

LocalDateTime Formats

object LocalDateTime.Formats {
    /** ISO 8601 extended format: YYYY-MM-DDTHH:MM:SS[.fff] */
    val ISO: DateTimeFormat<LocalDateTime>
}

YearMonth Formats

object YearMonth.Formats {
    /** ISO 8601 extended format: YYYY-MM */
    val ISO: DateTimeFormat<YearMonth>
}

UtcOffset Formats

object UtcOffset.Formats {
    /** ISO 8601 extended format: +HH:MM, +HH:MM:SS, or Z */
    val ISO: DateTimeFormat<UtcOffset>
    
    /** ISO 8601 basic format: +HHMM, +HHMMSS, or Z */
    val ISO_BASIC: DateTimeFormat<UtcOffset>
    
    /** Four digits format: always ±HHMM, never Z */
    val FOUR_DIGITS: DateTimeFormat<UtcOffset>
}

Usage Examples:

import kotlinx.datetime.*

val date = LocalDate(2023, 12, 25)
val time = LocalTime(15, 30, 45, 123456789)
val dateTime = LocalDateTime(date, time)
val yearMonth = YearMonth(2023, 12)
val offset = UtcOffset(hours = 5, minutes = 30)

// Format using predefined formats
println(date.format(LocalDate.Formats.ISO))         // "2023-12-25"
println(date.format(LocalDate.Formats.ISO_BASIC))   // "20231225"
println(time.format(LocalTime.Formats.ISO))         // "15:30:45.123456789"
println(dateTime.format(LocalDateTime.Formats.ISO)) // "2023-12-25T15:30:45.123456789"
println(yearMonth.format(YearMonth.Formats.ISO))    // "2023-12"
println(offset.format(UtcOffset.Formats.ISO))       // "+05:30"
println(offset.format(UtcOffset.Formats.ISO_BASIC)) // "+0530"
println(offset.format(UtcOffset.Formats.FOUR_DIGITS)) // "+0530"

// Parse using predefined formats
val parsedDate = LocalDate.parse("2023-12-25", LocalDate.Formats.ISO)
val parsedTime = LocalTime.parse("15:30:45", LocalTime.Formats.ISO)
val parsedOffset = UtcOffset.parse("+05:30", UtcOffset.Formats.ISO)

DateTimeFormatBuilder DSL

Flexible DSL for creating custom date/time formats with fine-grained control over each component.

Base Builder Interface

/**
 * Base interface for all format builders
 * Provides common formatting operations
 */
interface DateTimeFormatBuilder {
    /**
     * Add literal text to the format
     * @param value Literal string to include
     */
    fun chars(value: String)
    
    /**
     * Add a single literal character
     * @param value Character to include
     */
    fun char(value: Char)
}

Date Component Builders

/**
 * Builder for formats that include date components
 */
interface DateTimeFormatBuilder.WithDate : DateTimeFormatBuilder {
    /**
     * Year component
     * @param padding Padding style for the year
     */
    fun year(padding: Padding = Padding.ZERO)
    
    /**
     * Month as number
     * @param padding Padding style (NONE, ZERO, SPACE)
     */
    fun monthNumber(padding: Padding = Padding.ZERO)
    
    /**
     * Day of month
     * @param padding Padding style
     */
    fun dayOfMonth(padding: Padding = Padding.ZERO)
    
    /**
     * Day of year (1-366)
     * @param padding Padding style
     */
    fun dayOfYear(padding: Padding = Padding.ZERO)
    
    /**
     * Day of week as number (1=Monday, 7=Sunday)
     * @param padding Padding style
     */
    fun dayOfWeek(padding: Padding = Padding.ZERO)
}

Time Component Builders

/**
 * Builder for formats that include time components
 */
interface DateTimeFormatBuilder.WithTime : DateTimeFormatBuilder {
    /**
     * Hour component (0-23)
     * @param padding Padding style
     */
    fun hour(padding: Padding = Padding.ZERO)
    
    /**
     * Minute component (0-59)
     * @param padding Padding style
     */
    fun minute(padding: Padding = Padding.ZERO)
    
    /**
     * Second component (0-59)
     * @param padding Padding style
     */
    fun second(padding: Padding = Padding.ZERO)
    
    /**
     * Fractional second component
     * @param minLength Minimum number of digits
     * @param maxLength Maximum number of digits
     */
    fun secondFraction(minLength: Int = 0, maxLength: Int = 9)
    
    /**
     * AM/PM marker
     * @param am String for AM (default "AM")
     * @param pm String for PM (default "PM")
     */
    fun amPmMarker(am: String = "AM", pm: String = "PM")
}

Combined Builders

/**
 * Builder for formats with both date and time components
 */
interface DateTimeFormatBuilder.WithDateTime : 
    DateTimeFormatBuilder.WithDate, 
    DateTimeFormatBuilder.WithTime

/**
 * Builder for formats with UTC offset
 */
interface DateTimeFormatBuilder.WithUtcOffset : DateTimeFormatBuilder {
    /**
     * UTC offset component
     * @param format Offset format style
     */
    fun offset(format: UtcOffsetFormat)
}

/**
 * Builder for YearMonth formats
 */
interface DateTimeFormatBuilder.WithYearMonth : DateTimeFormatBuilder {
    fun year(padding: Padding = Padding.ZERO)
    fun monthNumber(padding: Padding = Padding.ZERO)
}

Padding Enumeration

/**
 * Padding style for formatting numeric components
 */
enum class Padding {
    /** No padding */
    NONE,
    
    /** Pad with zeros */
    ZERO,
    
    /** Pad with spaces */
    SPACE
}

Format Builder Functions

Factory functions for creating custom formats using the DSL.

/**
 * Create a LocalDate format using the DSL
 * @param builder DSL builder function
 * @returns DateTimeFormat for LocalDate
 */
fun LocalDate.Format(
    builder: DateTimeFormatBuilder.WithDate.() -> Unit
): DateTimeFormat<LocalDate>

/**
 * Create a LocalTime format using the DSL
 * @param builder DSL builder function
 * @returns DateTimeFormat for LocalTime
 */
fun LocalTime.Format(
    builder: DateTimeFormatBuilder.WithTime.() -> Unit
): DateTimeFormat<LocalTime>

/**
 * Create a LocalDateTime format using the DSL
 * @param builder DSL builder function
 * @returns DateTimeFormat for LocalDateTime
 */
fun LocalDateTime.Format(
    builder: DateTimeFormatBuilder.WithDateTime.() -> Unit
): DateTimeFormat<LocalDateTime>

/**
 * Create a YearMonth format using the DSL
 * @param builder DSL builder function
 * @returns DateTimeFormat for YearMonth
 */
fun YearMonth.Format(
    builder: DateTimeFormatBuilder.WithYearMonth.() -> Unit
): DateTimeFormat<YearMonth>

/**
 * Create a UtcOffset format using the DSL
 * @param builder DSL builder function
 * @returns DateTimeFormat for UtcOffset
 */
fun UtcOffset.Format(
    builder: DateTimeFormatBuilder.WithUtcOffset.() -> Unit
): DateTimeFormat<UtcOffset>

/**
 * Create a DateTimeComponents format using the DSL
 * @param builder DSL builder function
 * @returns DateTimeFormat for DateTimeComponents
 */
fun DateTimeComponents.Format(
    builder: DateTimeFormatBuilder.WithDateTime.() -> Unit
): DateTimeFormat<DateTimeComponents>

Usage Examples:

import kotlinx.datetime.*

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

val date = LocalDate(2023, 12, 25)
println(date.format(customDateFormat))  // "25/12/2023"

// Custom LocalTime format: "3:30:45 PM"
val customTimeFormat = LocalTime.Format {
    hour(padding = Padding.NONE)  // No leading zero
    char(':')
    minute()
    char(':')
    second()
    char(' ')
    amPmMarker()
}

val time = LocalTime(15, 30, 45)
println(time.format(customTimeFormat))  // "3:30:45 PM"

// Custom LocalDateTime format with milliseconds: "2023-12-25 15:30:45.123"
val customDateTimeFormat = LocalDateTime.Format {
    year()
    char('-')
    monthNumber()
    char('-')
    dayOfMonth()
    char(' ')
    hour()
    char(':')
    minute()
    char(':')
    second()
    char('.')
    secondFraction(minLength = 3, maxLength = 3)  // Always 3 digits
}

val dateTime = LocalDateTime(2023, 12, 25, 15, 30, 45, 123000000)
println(dateTime.format(customDateTimeFormat))  // "2023-12-25 15:30:45.123"

// Complex format with day of week: "Monday, December 25, 2023"
val verboseFormat = LocalDate.Format {
    // Note: This would require additional enum formatting support
    monthNumber()  // Would need month name support in actual implementation
    char(' ')
    dayOfMonth()
    chars(", ")
    year()
}

DateTimeComponents

Container class for holding individual date/time components during formatting operations.

/**
 * Container for date/time components used in formatting
 * Holds individual components that can be formatted independently
 */
class DateTimeComponents {
    // Date components
    var year: Int?
    var month: Int?
    var dayOfMonth: Int?
    var dayOfYear: Int?
    var dayOfWeek: Int?
    
    // Time components
    var hour: Int?
    var minute: Int?
    var second: Int?
    var nanosecond: Int?
    
    // Offset component
    var offsetSeconds: Int?
    
    /**
     * Convert to LocalDate if date components are available
     * @returns LocalDate or null if insufficient components
     */
    fun toLocalDate(): LocalDate?
    
    /**
     * Convert to LocalTime if time components are available
     * @returns LocalTime or null if insufficient components
     */
    fun toLocalTime(): LocalTime?
    
    /**
     * Convert to LocalDateTime if date and time components are available
     * @returns LocalDateTime or null if insufficient components
     */
    fun toLocalDateTime(): LocalDateTime?
    
    /**
     * Convert to UtcOffset if offset component is available
     * @returns UtcOffset or null if offset not set
     */
    fun toUtcOffset(): UtcOffset?
}

Instant Formatting

Special formatting for Instant values that require offset specification.

/**
 * Format an Instant using DateTimeComponents format with specified offset
 * @param format DateTimeComponents format to use
 * @param offset UTC offset for formatting the instant
 * @returns Formatted string
 */
fun Instant.format(format: DateTimeFormat<DateTimeComponents>, offset: UtcOffset): String

/**
 * Parse an Instant from string using DateTimeComponents format
 * @param input String to parse
 * @param format DateTimeComponents format to use
 * @returns Parsed Instant
 */
fun Instant.Companion.parse(input: CharSequence, format: DateTimeFormat<DateTimeComponents>): Instant

Usage Examples:

import kotlinx.datetime.*
import kotlin.time.Clock

// Create a custom format for Instant
val instantFormat = DateTimeComponents.Format {
    year()
    char('-')
    monthNumber()
    char('-')
    dayOfMonth()
    char('T')
    hour()
    char(':')
    minute()
    char(':')
    second()
    offset(UtcOffsetFormat.ISO)
}

val now = Clock.System.now()
val offset = UtcOffset(hours = 5, minutes = 30)

// Format instant with offset
val formatted = now.format(instantFormat, offset)
println(formatted)  // "2023-12-25T20:30:45+05:30"

// Parse back to instant
val parsed = Instant.parse(formatted, instantFormat)

Advanced Formatting Patterns

Conditional Formatting

import kotlinx.datetime.*

// Format that shows seconds only when non-zero
val conditionalTimeFormat = LocalTime.Format {
    hour()
    char(':')
    minute()
    // In a real implementation, this would need conditional support
    // Currently not directly supported, would need custom format implementation
}

// Work around with multiple formats for different cases
val timeWithSeconds = LocalTime.Format {
    hour()
    char(':')
    minute()
    char(':')
    second()
}

val timeWithoutSeconds = LocalTime.Format {
    hour()
    char(':')
    minute()
}

fun formatTimeConditionally(time: LocalTime): String {
    return if (time.second == 0 && time.nanosecond == 0) {
        time.format(timeWithoutSeconds)
    } else {
        time.format(timeWithSeconds)
    }
}

val time1 = LocalTime(15, 30)          // No seconds
val time2 = LocalTime(15, 30, 45)      // Has seconds

println(formatTimeConditionally(time1))  // "15:30"
println(formatTimeConditionally(time2))  // "15:30:45"

Localized Formatting

While the core library focuses on ISO formats, custom localized formats can be created:

import kotlinx.datetime.*

// German date format: DD.MM.YYYY
val germanDateFormat = LocalDate.Format {
    dayOfMonth()
    char('.')
    monthNumber()
    char('.')
    year()
}

// US date format: MM/DD/YYYY
val usDateFormat = LocalDate.Format {
    monthNumber()
    char('/')
    dayOfMonth()
    char('/')
    year()
}

val date = LocalDate(2023, 12, 25)
println("German: ${date.format(germanDateFormat)}")  // "25.12.2023"
println("US: ${date.format(usDateFormat)}")          // "12/25/2023"

// 24-hour vs 12-hour time
val time24Format = LocalTime.Format {
    hour()
    char(':')
    minute()
}

val time12Format = LocalTime.Format {
    hour()  // Would need 12-hour conversion logic
    char(':')
    minute()
    char(' ')
    amPmMarker()
}

val time = LocalTime(15, 30)
println("24-hour: ${time.format(time24Format)}")  // "15:30"
// 12-hour would need additional conversion logic

Complex Date Formats

import kotlinx.datetime.*

// ISO week date format (would need additional support)
val isoWeekFormat = LocalDate.Format {
    year()
    char('-')
    chars("W")
    // Would need week-of-year support
    dayOfWeek()
}

// Ordinal date format: YYYY-DDD
val ordinalFormat = LocalDate.Format {
    year()
    char('-')
    dayOfYear(padding = Padding.ZERO)  // Pad to 3 digits
}

val date = LocalDate(2023, 12, 25)
println("Ordinal: ${date.format(ordinalFormat)}")  // "2023-359"

// Custom verbose format with literals
val verboseFormat = LocalDate.Format {
    chars("Year ")
    year()
    chars(", Month ")
    monthNumber()
    chars(", Day ")
    dayOfMonth()
}

println("Verbose: ${date.format(verboseFormat)}")  // "Year 2023, Month 12, Day 25"

Error Handling

Parsing operations can fail and throw exceptions:

/**
 * Thrown when date/time parsing fails
 */
class DateTimeParseException : RuntimeException {
    constructor(message: String)
    constructor(message: String, cause: Throwable?)
}

Error Handling Examples:

import kotlinx.datetime.*

val format = LocalDate.Format {
    year()
    char('-')
    monthNumber()
    char('-')
    dayOfMonth()
}

// Safe parsing
val input = "2023-13-45"  // Invalid date
val result = format.parseOrNull(input)  // Returns null instead of throwing

if (result == null) {
    println("Failed to parse: $input")
} else {
    println("Parsed: $result")
}

// Exception-based parsing
try {
    val parsed = format.parse(input)
    println("Parsed: $parsed")
} catch (e: DateTimeParseException) {
    println("Parse error: ${e.message}")
}

// Validate format before parsing
fun safeParse(input: String, format: DateTimeFormat<LocalDate>): LocalDate? {
    return try {
        format.parse(input)
    } catch (e: Exception) {
        null
    }
}

Format Debugging

Generate DSL code for existing formats:

import kotlinx.datetime.*

// Generate code for predefined format
val isoCode = DateTimeFormat.formatAsKotlinBuilderDsl(LocalDate.Formats.ISO)
println("ISO format DSL:")
println(isoCode)

// This would output something like:
// LocalDate.Format {
//     year()
//     char('-')
//     monthNumber()
//     char('-')
//     dayOfMonth()
// }

Install with Tessl CLI

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

docs

arithmetic.md

formatting.md

index.md

instant.md

local-types.md

platform.md

ranges.md

serialization.md

timezones.md

tile.json