Write a simple multiplatform date formatter using 1) native libraries or 2) kotlinx.datetime
Formatting dates often feels borderline tiresome to implement. Personally, every time I have to convert a date to a certain format, I think to myself — now again? Didn’t we do this before? There should be a way of writing this sort of code once and not having to bother with it again.
A simple example of a date formatting requirement could be that we must display the text 18.06.2022 if (you guessed it) the current date is June 18th, 2022. Should be easy enough to do on multiple platforms, right? Sure. But you have to write the “same” formatting logic twice if you write code for Android and iOS, for example, in two separate code bases.
Luckily for us, we can utilize Kotlin Multiplatform Mobile (KMM) which enables us to write the same code once and use it across multiple platforms.
I won’t go into detail about KMM in this post. Let’s go straight to the point and dive into the code instead.
In this post I will present two alternatives:
- A generic formatter written purely in Kotlin, where we will add code to
iosMain, thereby introducing platform-specific logic;
- Using a multiplatform library called
kotlinx-datetime(check the repo here), where we will keep all of our code in
For brevity, I will only focus on supporting timestamps in ISO 8601 format, as well as only supporting one date format, namely
Let’s define this simple class which we put in
DateTime isn’t a perfect name for such a class. We could name it
Iso8601TimestampFormatter or similarly, but I chose to name it differently for brevity.)
It’s quite basic. We pass in an ISO 8601 timestamp as well as a format (
dd.MM.yyyy), and it should return the formatted date.
So how does it look on Android?
The following should be placed in
We are parsing our timestamp using the
ZonedDateTime API, and subsequently formatting it with our format via
Then how about iOS?
Instead of using Java libraries, which aren’t accessible on iOS, we will instead refer to the
Foundation framework. It contains all the things we need for date formatting (and more, of course).
Let’s put the following in
We create an instance of
NSDateFormatter and set the time zone, locale, and format. Finally, we invoke
stringFromDate() to get the formatted string.
You may ask — why not use the Swift APIs like
TimeZone , etc.? The TL;DR is that we are unable to import any pure Swift modules from Kotlin code in the current state of KMM. Importing Objective-C APIs (
NS…), however, works just fine. See this link for more info.
Let’s test it! ✅
As our tests are platform-independent, it is sufficient to place them in
When we ask Android Studio to run the tests, we are asked to use a specific target (depending on how our project is configured):
Normally you’d choose between
iosX64 . Running either, we can see that the tests pass:
If you don’t want to run the tests via Android Studio’s popup (or having to waste precious time selecting different options in a popup, for that matter), you can simply run the command
$ ./gradlew :shared:allTests which will execute all tests in the project across all possible targets.
Alright, cool, but I don’t really want to write platform-dependent code if it can be avoided
Let’s see if we can avoid that, then! The good people over at Kotlin/JetBrains created the
kotlinx-datetime library, which we’ll look at next.
I recommend reading the documentation on the GitHub page for this library. As for our work, let’s get right down to it by adding the dependency to our
commonMain source set:
Now let’s use
LocalDateTime to find the day, month, and year from the timestamp, and finally return the formatted date as a string:
zeroPrefixed()extension function is one I created to circumvent the fact that there’s no non-JVM
String.format()equivalent in Kotlin’s standard library at this moment, which would otherwise enable us to easily format integers as strings with prefixed zeros. You can find the code for
Write the tests (why wouldn’t you?)
We looked at two approaches to writing date formatting logic that works on both Android and iOS.
Requiring platform-specific logic, the first approach enables us to use date time patterns/formats directly. However, we are forced to write code that caters to each individual platform.
Evidently, the approach needing less code is the latter. It relies on a third-party library that doesn’t at this moment support formatting various date time patterns/formats out of the box, which is why we have to write that part ourselves. On the bright side, it’s a multiplatform library, and we don’t have to worry about any platform-specific APIs.
Hope you have fun coding in Kotlin for multiple platforms!