
Localization library for date/time objects, offering localizer classes, options and localize() extensions, with standalone vs absolute formatting for months, weekdays, time zones, dates and durations.
Multiplatform localization library for Kotlin date/time objects, either from stdlib or kotlinx-datetime.
The library uses a different localization backend depending on the platform:
| Platform | Localization backend |
|---|---|
| JVM | ICU4J |
| Android | android.icu |
| JS (Browser + Node) | Intl |
| WASM (Browser) | Intl |
[!NOTE] While the library strives to provide a uniform API that mostly returns consistent values, subtle differences between various localization backends exist. You should not rely on localized strings being identical between platforms.
Add to your dependencies:
dependencies {
implementation("dev.mmauro:datetime-polyglot:<version>")
}See latest version in badge above or look directly at Maven Central page.
Snapshot builds are published on every commit in mainline.
To use, add in your settings.gradle.kts:
dependencyResolutionManagement {
repositories {
maven("https://central.sonatype.com/repository/maven-snapshots")
}
}Then add to your dependencies:
dependencies {
implementation("dev.mmauro:datetime-polyglot:<version>")
}See latest version in badge above or look at maven-metadata.xml.
In general, each type of data that can be localized will have:
localize() extension function on the data type that hides the construction of the localizer classAnything marked with a 🧪 means that the feature is experimental: it could be changed or dropped at any time. An opt-in annotation is required to use such features.
These should be used when the component to localize is standalone (e.g. calendar header), and should not be mixed with other date components.
| Data type | Localizer class / Extension function | Examples |
|---|---|---|
Month |
MonthLocalizer Month.localize()
|
January Jan J 1
|
DayOfWeek |
DayOfWeekLocalizer DayOfWeek.localize()
|
Monday Mon Mo M
|
TimeZone |
TimeZoneLocalizer TimeZone.localize()
|
America/Los_Angeles PT Pacific Time Los Angeles Time
|
These should be used when you want to localize an absolute date/time object to show the user. Avoid concatenating values from these localizers, always use the output of a localizer in full.
If you need only partial information, convert first to the appropriate type and then localize that.
For instance, if you have an Instant but are only interested in the time component, you should first convert to
LocalDateTime, then get the LocalTime part, and finally localize it.
| Data type | Localizer class / Extension function | Examples |
|---|---|---|
Zoned<Instant> |
ZonedInstantLocalizer ZonedInstantLocalizer.localize()
|
1/8/26 9:05 PM PST Jan 8, 2026, 9 at night Pacific Daylight Time January 8, 2026 at 9:31:45 PM GMT-07:00 Thursday, January 8, 2026 at 21:05 Los Angeles Time
|
LocalDateTime |
LocalDateTimeLocalizer LocalDateTime.localize()
|
1/8/26 9:05 PM Jan 8, 2026, 9 at night January 8, 2026 at 9:31:45 PM Thursday, January 8, 2026 at 21:05
|
LocalDate |
LocalDateLocalizer LocalDate.localize()
|
1/8/26 Jan 8, 2026 January 8, 2026 Thursday, January 8, 2026
|
LocalTime |
LocalTimeLocalizer LocalTime.localize()
|
9:05 PM 9:05:08 PM 21:05 21:05:08.123 9 at night
|
YearMonth |
YearMonthLocalizer YearMonth.localize()
|
January 2026 Jan 26 01/2026
|
Year (Int) |
YearLocalizer No extension function |
2026 26 2026 AD 2026 Anno Domini
|
Duration |
DurationLocalizer / 🧪 TickingDurationLocalizer Duration.localize() / 🧪 Duration.localizeTicking()
|
1h 5m 1 hr, 5 min 1 hour, 5 minutes
|
These should be used whenever you always want to localize a date/time object in a relative way. Avoid concatenating values from these localizers, always use the output of a localizer in full.
All these functions return
a TickingValue,
class that holds the localized value and a "next tick" duration, which indicates for how long the value is valid for.
When the "next tick" expires, it means that the localized value now needs recomputation.
Most of these classes
implement
PolyglotReferenceValueLocalizer,
which allows to pass in a reference point (usually the current time) to use for relative localization.
As a convenience,
the
localizeAsFlow
extension function will return
a Flow that
automatically emits a new relative value when it is due.
| Data type | Has reference point | Localizer class / Extension function | Examples |
|---|---|---|---|
Duration |
No |
RelativeDurationLocalizer Duration.relativeLocalize()
|
10 minutes ago in 1 hour 4h ago
|
Instant |
Yes |
RelativeInstantLocalizer Instant.localizeRelative() Instant.localizeRelativeAsFlow()
|
10 minutes ago in 1 hour 4h ago
|
LocalDateTime |
Yes |
RelativeDateAbsoluteTimeLocalizer LocalDateTime.localizeRelativeDateAbsoluteTime() LocalDateTime.localizeRelativeDateAbsoluteTimeAsFlow()
|
yesterday at 9:00 PM next Sunday at 4:00 AM in 15 days, 3:00 AM 21 days ago at 7:00 PM
|
LocalDate |
Yes |
RelativeLocalDateLocalizer LocalDate.localizeRelative() LocalDate.localizeRelativeAsFlow()
|
today yesterday this Monday next Friday in 54 days 5 days ago
|
YearMonth |
Yes |
RelativeYearMonthLocalizer YearMonth.localizeRelative() YearMonth.localizeRelativeAsFlow()
|
this month last mo. next month 4 months ago in 34mo
|
Year (Int) |
Yes |
RelativeYearLocalizer No extension functions |
last yr. this year next year 1 year ago in 5y
|
Multiplatform localization library for Kotlin date/time objects, either from stdlib or kotlinx-datetime.
The library uses a different localization backend depending on the platform:
| Platform | Localization backend |
|---|---|
| JVM | ICU4J |
| Android | android.icu |
| JS (Browser + Node) | Intl |
| WASM (Browser) | Intl |
[!NOTE] While the library strives to provide a uniform API that mostly returns consistent values, subtle differences between various localization backends exist. You should not rely on localized strings being identical between platforms.
Add to your dependencies:
dependencies {
implementation("dev.mmauro:datetime-polyglot:<version>")
}See latest version in badge above or look directly at Maven Central page.
Snapshot builds are published on every commit in mainline.
To use, add in your settings.gradle.kts:
dependencyResolutionManagement {
repositories {
maven("https://central.sonatype.com/repository/maven-snapshots")
}
}Then add to your dependencies:
dependencies {
implementation("dev.mmauro:datetime-polyglot:<version>")
}See latest version in badge above or look at maven-metadata.xml.
In general, each type of data that can be localized will have:
localize() extension function on the data type that hides the construction of the localizer classAnything marked with a 🧪 means that the feature is experimental: it could be changed or dropped at any time. An opt-in annotation is required to use such features.
These should be used when the component to localize is standalone (e.g. calendar header), and should not be mixed with other date components.
| Data type | Localizer class / Extension function | Examples |
|---|---|---|
Month |
MonthLocalizer Month.localize()
|
January Jan J 1
|
DayOfWeek |
DayOfWeekLocalizer DayOfWeek.localize()
|
Monday Mon Mo M
|
TimeZone |
TimeZoneLocalizer TimeZone.localize()
|
America/Los_Angeles PT Pacific Time Los Angeles Time
|
These should be used when you want to localize an absolute date/time object to show the user. Avoid concatenating values from these localizers, always use the output of a localizer in full.
If you need only partial information, convert first to the appropriate type and then localize that.
For instance, if you have an Instant but are only interested in the time component, you should first convert to
LocalDateTime, then get the LocalTime part, and finally localize it.
| Data type | Localizer class / Extension function | Examples |
|---|---|---|
Zoned<Instant> |
ZonedInstantLocalizer ZonedInstantLocalizer.localize()
|
1/8/26 9:05 PM PST Jan 8, 2026, 9 at night Pacific Daylight Time January 8, 2026 at 9:31:45 PM GMT-07:00 Thursday, January 8, 2026 at 21:05 Los Angeles Time
|
LocalDateTime |
LocalDateTimeLocalizer LocalDateTime.localize()
|
1/8/26 9:05 PM Jan 8, 2026, 9 at night January 8, 2026 at 9:31:45 PM Thursday, January 8, 2026 at 21:05
|
LocalDate |
LocalDateLocalizer LocalDate.localize()
|
1/8/26 Jan 8, 2026 January 8, 2026 Thursday, January 8, 2026
|
LocalTime |
LocalTimeLocalizer LocalTime.localize()
|
9:05 PM 9:05:08 PM 21:05 21:05:08.123 9 at night
|
YearMonth |
YearMonthLocalizer YearMonth.localize()
|
January 2026 Jan 26 01/2026
|
Year (Int) |
YearLocalizer No extension function |
2026 26 2026 AD 2026 Anno Domini
|
Duration |
DurationLocalizer / 🧪 TickingDurationLocalizer Duration.localize() / 🧪 Duration.localizeTicking()
|
1h 5m 1 hr, 5 min 1 hour, 5 minutes
|
These should be used whenever you always want to localize a date/time object in a relative way. Avoid concatenating values from these localizers, always use the output of a localizer in full.
All these functions return
a TickingValue,
class that holds the localized value and a "next tick" duration, which indicates for how long the value is valid for.
When the "next tick" expires, it means that the localized value now needs recomputation.
Most of these classes
implement
PolyglotReferenceValueLocalizer,
which allows to pass in a reference point (usually the current time) to use for relative localization.
As a convenience,
the
localizeAsFlow
extension function will return
a Flow that
automatically emits a new relative value when it is due.
| Data type | Has reference point | Localizer class / Extension function | Examples |
|---|---|---|---|
Duration |
No |
RelativeDurationLocalizer Duration.relativeLocalize()
|
10 minutes ago in 1 hour 4h ago
|
Instant |
Yes |
RelativeInstantLocalizer Instant.localizeRelative() Instant.localizeRelativeAsFlow()
|
10 minutes ago in 1 hour 4h ago
|
LocalDateTime |
Yes |
RelativeDateAbsoluteTimeLocalizer LocalDateTime.localizeRelativeDateAbsoluteTime() LocalDateTime.localizeRelativeDateAbsoluteTimeAsFlow()
|
yesterday at 9:00 PM next Sunday at 4:00 AM in 15 days, 3:00 AM 21 days ago at 7:00 PM
|
LocalDate |
Yes |
RelativeLocalDateLocalizer LocalDate.localizeRelative() LocalDate.localizeRelativeAsFlow()
|
today yesterday this Monday next Friday in 54 days 5 days ago
|
YearMonth |
Yes |
RelativeYearMonthLocalizer YearMonth.localizeRelative() YearMonth.localizeRelativeAsFlow()
|
this month last mo. next month 4 months ago in 34mo
|
Year (Int) |
Yes |
RelativeYearLocalizer No extension functions |
last yr. this year next year 1 year ago in 5y
|