loading...

Island Time 0.2.0 is out

erikc5000 profile image Erik Christensen ・4 min read

I'm pleased to announce that Island Time 0.2.0 is now available. If you're not familiar with Island Time, you might want to first check out this introductory post. In summary, it lets you write date and time code that'll run on the JVM, Android, iOS, and all other Apple platforms while offering a nice Kotlin API that's heavily inspired by the java.time library.

In addition to support for Kotlin 1.3.70, a number of new features have been added -- and bugs squashed. You can find the full release notes here, but I'll run through some of the notable features and talk a little about where things are going.

Locale support

The biggest new feature is support for localized text and week definitions.

While most platforms these days are using data from the Unicode CLDR under the hood, what version they're using and how much of it is exposed through their APIs varies considerably. Island Time attempts to provide a common interface to these platform APIs while also giving you the flexibility to use data from different sources or customize the behavior where needed via DateTimeTextProvider and TimeZoneTextProvider interfaces.

Localized text

It's now possible to access the localized names of months, days of the week, time zones, and more.

// Get the system default locale. We'll assume this is "en_US".
val locale = defaultLocale()

// "Feb"
val shortMonthName = Month.FEBRUARY.localizedName(TextStyle.SHORT_STANDALONE, locale)

// "Eastern Daylight Time"
val tzName = TimeZone("America/New_York").displayName(TimeZoneTextStyle.DAYLIGHT, locale)

For applicable classes, you'll find a localizedName() method that returns null if text is unavailable for the provided style and locale. And then a displayName() method that will instead return a default value if localized text is unavailable, such as the month or day of week number.

Island Time's Locale is simply a typealias for java.util.Locale or NSLocale. The defaultLocale() method allows you to access the system default locale in common code. If you want to use a specific locale, you should create it in platform-specific code and inject it.

You can also parse localized text, though results may vary between different platforms and versions -- and writing locale-agnostic parsers is non-trivial, so please be mindful of that. While it can be useful in some situations (which is why this feature is available), it should be avoided where possible.

val customParser = dateTimeParser {
    localizedMonth(setOf(TextStyle.SHORT, TextStyle.LONG))
    +' '
    dayOfMonth()
    +", "
    year()
}

val date: Date = "Feb 29, 2020".toDate(customParser) // 2020-02-29

Localized week definitions

In addition to localized text, there's also support for localized week definitions. Depending on the locale, the week might start on Sunday, Monday, or Saturday -- and some platforms, such as macOS and iOS, allow the user to customize this independently from the locale settings.

A WeekSettings class has been introduced to provide control over this behavior when using week-related methods. WeekSettings.systemDefault() will usually be the most desirable construction method since it respects the user's system settings.

// Start of ISO week (Monday start)
val isoStart = Date.now().startOfWeek

// Start of week using Sunday as start
val sundayStart = Date.now().startOfWeek(WeekSettings.SUNDAY_START)

// Respect the user's system settings
val systemStart = Date.now().startOfWeek(WeekSettings.systemDefault())

// Use the default associated with a particular locale
val localeStart = Date.now().startOfWeek(explicitLocale)

Week range/interval operators

New operators have also been added to make it easier to get the range of the week from a date or date-time. As an example, you could obtain an interval between the starting and ending instants of a week by doing the following:

// Get the date range of the current week
val weekRange: DateRange = Date.now().weekRange(WeekSettings.systemDefault())

// Convert it into the interval between the starting and ending instants of that week
val weekInterval: InstantInterval = weekRange.toInstantIntervalAt(TimeZone.systemDefault())

Serializers for Kotlin Serialization

The serialization-extensions artifact provides a set of custom serializers ready to use with kotlinx.serialization. These will allow you to serialize all date-time primitives, durations, and ranges as ISO-compatible strings, well-suited for JSON.

@Serializable
data class MyDto(
    val name: String,
    @Serializable(with = DateRangeSerializer::class) val dateRange: DateRange
)

Parcelers for @Parcelize in the Kotlin Android Extensions

Similarly, the parcelize-extensions artifact provides a set of custom parcelers ready to use with the Parcelable implementation generator provided by the Kotlin Android Extensions.

@Parcelize
@TypeParceler<Date, DateParceler>()
data class MyParcelable(
    val name: String,
    val date: Date
) : Parcelable

@Parcelize
@TypeParceler<Date?, NullableDateParceler>()
data class MyParcelableWithNull(
    val name: String,
    val date: Date?
) : Parcelable

Future directions

At KotlinConf, JetBrains announced that they're working on their own date-time library. At this time, it's unclear what the feature set will look like and when it'll be ready.

Island Time is quite usable today and will continue to live on for the foreseeable future, serving as an alternative that will perhaps better satisfy certain needs. A number of new features and enhancements are in the pipeline already and will be making their way out in the coming months, including support for custom date-time formats. Stay tuned and coronavirus-free.

Posted on by:

erikc5000 profile

Erik Christensen

@erikc5000

C++ developer by day, Kotlin enthusiast by night. Rock climbing, skiing, and hiking to keep me sane.

Discussion

markdown guide