KmpDateTime
2.2.1indexedDesigned to address limitations in existing date-time libraries, focuses on providing simple data classes for date-time handling with minimal logic. Offers familiar API, ISO string parsing, and serialization to ISO 8601.
Designed to address limitations in existing date-time libraries, focuses on providing simple data classes for date-time handling with minimal logic. Offers familiar API, ISO string parsing, and serialization to ISO 8601.
Why another DateTime library?
kotlinx-datetime is great and in most cases you should use that one, but it has the following flaws:
So in cases where you want to avoid above circumstances and need only pure data classes to hold date time values and send it over the wire with almost no logic like date time calculations, this library's for you.
It features:
implementation("net.dankito.datetime:kmp-datetime:2.2.1")
<dependency>
<groupId>net.dankito.datetime</groupId>
<artifactId>kmp-datetime-jvm</artifactId>
<version>2.2.1</version>
</dependency>
// month as number from 1 - 12
date = LocalDate(, , )
date2 = LocalDate(, Month.October, )
date3 = LocalDate()
today = LocalDate.today()
fromIsoString = LocalDate.parse()
fromIsoStringLenient = LocalTime.parseOrNull()
val instant = Instant(1_445_418_487)
// components
epochSeconds: = instant.epochSeconds
nanosecondsOfSecond: = instant.nanosecondsOfSecond
epochMillis: = instant.toEpochMilliseconds()
dateTimeAtUtc: LocalDateTime = instant.toLocalDateTimeAtUtc()
dateTimeAtSystemTimeZone: LocalDateTime = instant.toLocalDateTimeAtSystemTimeZone()
isoString = instant.isoString
isoStringAtSystemTimeZone = instant.isoStringAtSystemTimeZone
OffsetDateTime is in experimental stage, its API may change in the future.
Supports both kotlinx-serialization and Jackson out of the box.
For Jackson simply call ObjectMapper().findAndRegisterModules() - it finds and registers our module automatically -
or register it manually with ObjectMapper().registerModule(KmpDateTimeModule()).
By default values are serialized to and from ISO 8601 strings.
But you can configure this via SerializationConfig, e.g.
SerializationConfig.LocalDateDefaultFormat = DateTimeSerializationFormat.Components
SerializationConfig.InstantDefaultFormat = InstantSerializationFormat.EpochMilliseconds
// you can also configure your custom serializer
SerializationConfig.LocalTimeDefaultFormat = DateTimeSerializationFormat.Custom // to enable that `SerializationConfig.LocalTimeCustomSerializer` is used
SerializationConfig.LocalTimeCustomSerializer = MyLocalTimeSerializer
Copyright 2025 dankito
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https:
Unless applicable law agreed to writing, software
distributed under the License distributed an BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express implied.
See the License the specific language governing permissions
limitations under the License.
DateTimeFormatter and DateTimeParser.now() methods (Instant.now(), LocalDate.today(), ...) and converting an Instant to LocalDateTime at UTC and back.{"year":2020,"month":12,"day":9}) and Instant to and from Epoch milliseconds.val date = LocalDate(2015, Month.October, 21)
// components
val year: Int = date.year // returns 2015
val month: Month = date.month // returns Month.October
val monthNumber: Int = date.monthNumber // returns 10
val day: Int = date.day // returns 21
// the day of week of this date; returns null in case of an invalid date
val dayOfWeek: DayOfWeek? = date.dayOfWeek // returns DayOfWeek.Wednesday
// to LocalTimeTime (from there you can convert it further to Instant, see LocalDateTime examples)
val atMidnight: LocalDateTime = date.atStartOfDay()
val byHourMinutesSeconds: LocalDateTime = date.atTime(12, 15, 30)
val byLocalTime: LocalDateTime = date.atTime(LocalTime.Noon)
// to ISO 8601 string
val isoString = date.isoString // returns "2015-10-21"
val isoStringDotSeparated = date.isoStringDotSeparated // variant that uses '.' instead of '-' as separator; returns "2015.10.21"
val time = LocalTime(hour = 12, minute = 15, second = 30, nanosecondOfSecond = 123)
// with default values
val time2 = LocalTime(0) // default values for minute, second and nanosecond of second are 0; returns LocalTime(0, 0, 0, 0)
// current time
val now = LocalTime.now()
// time constants
val midnight = LocalTime.Midnight // synonym for LocalTime.StartOfDay
val noon = LocalTime.Noon
val endOfDay = LocalTime.EndOfDay // equals LocalTime(23, 59, 59, 999_999_999)
// creating from ISO 8601 time string
val fromIsoString = LocalTime.parse("12:15:30.654")
// lenient parsing, returns null in case of invalid ISO string (LocalTime.parse() throws an exception in case of invalid ISO string)
val fromIsoStringLenient = LocalTime.parseOrNull("12:15:30.654+02:00") // returns null, '+02:00' is not a valid part of an ISO time string
val time = LocalTime(12, 15, 30, nanosecondOfSecond = 654_000_000)
// components
val hour: Int = time.hour // returns 12
val minute: Int = time.minute // returns 15
val second: Int = time.second // returns 30
val nanosecondOfSecond: Int = time.nanosecondOfSecond // returns 654_000_000
// to LocalTimeTime (from there you can convert it further to Instant, see LocalDateTime examples)
val byYearMonthDay: LocalDateTime = time.atDate(2015, Month.October, 21)
val byLocalDate: LocalDateTime = time.atDate(LocalDate(2015, Month.October, 21))
// to ISO 8601 string
val isoString = time.isoString // returns "12:15:30.654"
// month as number from 1 - 12
val dateTime = LocalDateTime(year = 2015, monthNumber = 10, day = 21, hour = 12, minute = 15, second = 30, nanosecondOfSecond = 654)
// month as enum
val dateTime2 = LocalDateTime(2015, Month.October, 21, 12, 15)
// with default values
val dateTime3 = LocalDateTime(2015) // default values for month and day are January and 1, for all other values 0; returns LocalDateTime(2015, Month.January, 1, 0, 0, 0, 0)
// by date and time
val dateTime4 = LocalDateTime(LocalDate(2015, Month.October, 21), LocalTime(12, 15, 30, 654))
// current datetime
val now = LocalDateTime.now()
// creating from ISO 8601 datetime string
val fromIsoString = LocalDateTime.parse("2015-10-21T12:15:30.654")
// lenient parsing, returns null in case of invalid ISO string (LocalDateTime.parse() throws an exception in case of invalid ISO string)
val fromIsoStringLenient = LocalTime.parseOrNull("2015-10-21T12:15:30.654GMT") // returns null, 'GMT' is not a valid part of an ISO datetime string
val dateTime = LocalDateTime(2015, Month.October, 21, 12, 15, 30)
// get date or time
val date = dateTime.date
val time = dateTime.time
// components
val year: Int = dateTime.year // returns 2015
val month: Month = dateTime.month // returns Month.October
val monthNumber: Int = dateTime.monthNumber // returns 10
val day: Int = dateTime.day // returns 21
// the day of week of this date; returns null in case of an invalid date
val dayOfWeek: DayOfWeek? = dateTime.dayOfWeek // returns DayOfWeek.Wednesday
val hour: Int = dateTime.hour // returns 12
val minute: Int = dateTime.minute // returns 15
val second: Int = dateTime.second // returns 30
val nanosecondOfSecond: Int = dateTime.nanosecondOfSecond // returns 0
// to Instant
val instantAtUtc: Instant = dateTime.toInstantAtUtc()
val instantAtSystemTimeZone: Instant = dateTime.toInstantAtSystemTimeZone()
// to ISO 8601 string
val isoString = dateTime.isoString // returns "2015-10-21T12:15:30"
// by seconds since epoch (1970-01-01 midnight)
val instant = Instant(epochSeconds = 1_745_000_000, nanosecondsOfSecond = 654)
// by milliseconds since epoch
val instant2 = Instant.ofEpochMilli(1_745_000_000_654) // returns Instant(1_745_000_000, 654_000_000)
// with default values
val instant3 = Instant(1_745_000_000) // default values for nanosecondsOfSecond is 0; returns Instant(1_745_000_000, 0)
// by datetime
val instant4 = LocalDateTime(2015, Month.October, 21, 12, 15).toInstantAtUtc()
// current instant
val now = Instant.now()
// Instant constants
val epoch = Instant.Epoch
// creating from ISO 8601 instant string
val fromIsoString = Instant.parse("2015-10-21T12:15:30.654Z")
// lenient parsing, returns null in case of invalid ISO string (Instant.parse() throws an exception in case of invalid ISO string)
val fromIsoStringLenient = LocalTime.parseOrNull("2015-10-21T12:15:30.654") // returns null, does not end with 'Z'
Surfaced from shared tags and platforms — no rankings paid for.