People like us, who believe in physics, know that the distinction between past, present, and future is only a stubbornly persistent illusion.
Time representation is a necessity for nearly all applications. The ability to display, reference, track, and manipulate moments of time plays an important role in the development of applications. But when developing a Kotlin multi-platform application, this becomes a difficult task, as there is no notion of a moment of time in the standard library. Waiting for one to be added would be a waste of time, so I decided to create one. This article takes an early look at this new library that is still in development.
Introducing a new Kotlin multi-platform time library.
Kotlin does provide a new experimental duration class which serves as a period of time, but no notion of a moment, or instant, of time. There is already a promising Kotlin multi-platform library called Klock, but this doesn't make use of the new experimental Duration class. So I created a library that expands on the Duration class by provided a
Moment interface. These
Moments are obtained by a
TimeProvider. Getting this correct was pretty difficult and took some time, but, while the library is still in the early stages of development, I am pretty satisfied with the API and it's ease of use. Let's have a look.
TimeProvider interface is the entry point to doing anything time related, such as, obtaining a specific
Moment in time.
val now = timeProvider.now() val later = now + 20.minutes val tomorrow = timeProvider.tomorrow() val diffDuration = later to tomorrow
Moment in time can be obtained by using the
TimeProvider.moment() function and providing the
Duration since the epoch as a parameter. Moments in time for a specific Time Zone can be retrieved by passing in a
TimeZoneRegionId. Without passing in a
TimeZoneRegionId, the default is used, by accessing the
TimeZoneOffsetProvider.defaultTimeZoneRegionId property that is available to the
val moment = timeProvider.moment( durationSinceEpoch = 20_000.hours, regionId = TimeZoneRegionId("America/New_York"))
Each platform target is responsible for providing their own implementation of the
TimeProvider interface. For instance, the
jvmMain source set provides a
JavaTimeProvider implementation. This implementation delegates to the
java.time classes. Then each platform can provide their own platform specific implementations and the Kotlin common code can just reference the interfaces, such as,
@Provides fun provideTimeProvider(): TimeProvider = JavaTimeProvider(locale = Locale.getDefault())
Moment interface represents an instant of time, as a duration since the epoch, with a
TimeOffset from UTC for a specified
TimeZoneRegionId and it's corresponding rules (daylight savings time, etc). A
Moment can also represent UTC/GMT time which has an offset equal to zero, and which can be retrieved for any
Moment using the
Durations can be added or subtracted from a
Moment, and a
Duration between two
Moments can be retrieved using the
to infix function. Also,
TimeOfDay objects can be retrieved from the
val yesterday = timeProvider.yesterday() val later = timeProvider.now() + 3.hours val duration = yesterday to later val date = later.calendarDate val time = later.timeOfDay
CalendarDate class represents the date of a
Moment in a calendar year with no information about the time within the day.
val date = moment.calendarDate date.year date.month date.dayInYear date.dayInMonth date.dayOfWeek
TimeOfDay class is similar to
CalendarDate but instead of providing information about the date within a calendar year, it provides information about the time within a calendar date.
val time = moment.timeOfDay time.elapsedDurationInDay time.minuteInHour time.secondInMinute time.millisecondInSecond time.hourInDay(ClockConvention.TWENTY_FOUR_HOUR_CLOCK)
Parsing and Formatting
The library comes with two interfaces,
MomentParser, which provide a way to transform a
Moment into a
String for a particular pattern and vice-versa. These can be obtained from the
val formatter = timeProvider.formatter(MomentFormatPattern("MM/dd/yyyy")) val string = formatter.format(timeProvider.now()) val parser = timeProvider.parser(MomentFormatPattern("MM/dd/yyyy")) val moment = parser.parse("2/12/2020")
One idea of the library is to have JSON serializers, for popular JSON parsing libaries, that handle common time formats. This way it is simple to pass
Moments between components. These aren't implemented yet, as of writing this article, but I imagine that they would reside in their own modules per library supported.
Why not mimic java.time?
There are some similarities between the two libraries and
java.time has provided some inspiration in the development of this library. But there seems to be a common source of confusion for the components within the
java.time library, such as,
Instant. I wanted to avoid this confusion for a casual user of the library and wanted to provide a more Kotlin-esque API. For this reason, the
Moment interface was created, which acts similar to a combination of the
Instant classes. The
CalendarDateAndTime class corresponds to Java Time's
LocalDateTime class. And a new interface was created,
TimeProvider, that acts as a single source for everything time related.
This new library, still in the early stages of development, provides a promising vision of working with time within Kotlin multi-platform code. Still, implementations need to be finalized, tests need to be written, and other platforms need to be targeted. And since the library uses the experimental
Duration class, the library is experimental as well. The implementation of time related code isn't as trivial as one might expect, but, overall, the future of this Kotlin time library looks bright, however, only time will tell.