preface

Kotlinx-datetime is the official Kotlin date and time library. Personally, I first learned of the library as a wrapper around Kotlin’s date and time utility classes, when the extension library was packaged with Java8’s LocalDateTime. Later, I came across Kotlin’s official date and time library. After learning about it, I found that it was simpler and easier to use than Java8’s. So I replaced the date and time tool classes that were packaged in Java8 with a new implementation method. The following will take you to learn the Kotlinx-DateTime library.

This article seems to be the first in the country to cover Kotlinx-datetime, and probably the most in-depth on the web. We will not only show you how to use the library, but also show you how to encapsulate and optimize Kotlinx-DateTime to make it more complete and useful. There will also be a caveat that most people find hard to spot. Finally, we will use an example of wechat time to practice.

Java and Kotlin library API differences

Before learning about Kotlinx-DateTime, it’s important to understand the differences between the date and time apis of Java7, Java8, and the Kotlin library.

Java 7 and Java8

Most people still use the Java7 datetime API, but Java8 introduced a more useful API with the following differences:

  • Java7 is defined injava.utilPackage, Java8 is defined injava.timeThe package.
  • Java7 mainly includesDate,CalendarTimeZoneJava8 mainly includes these classesLocalDateTime,ZonedDateTime,ZoneIdAnd so on.
  • Java 7 useSimpleDateFormatFormatting is not thread safe. Java8 useDateTimeFormatterFormatting is thread-safe and you can create only one instance to reference everywhere.
  • Java8 fixes the unreasonable constant design, with values from 1 to 12 from January to December and from 1 to 7 from Monday to Sunday. Java7 doesn’t, and it’s a little awkward to use.
  • Java8 makes it easy to adjust dates and times, or to add and subtract dates and times.

Of course, the date and time API of Java8 is preferred.

Java8 and Kotlin library

The KOtlinx-DateTime API references Java8 and has many of the same or similar classes or apis, though there are some differences:

  • Java8 is defined injava.timePackage, Kotlin’s definition iskotlinx.datetimeThe package.
  • kotlinx.datetimeIs a multi-platform library, implemented on the JVM platform based on Java8. Due to the multi-platform nature, each API takes into account each platform, sokotlinx.datetimeThere are no fully introduced Java8 apis, and currently only common functionality.
  • kotlinx-datetimeKotlin language implementation, API more concise and easy to use.

Both are actually very similar, each has its advantages and disadvantages. Kotlinx-datetime features are not as complete as Java8, but the API will be simpler and easier to use, and it will be a multi-platform library. Using Kotlin, I personally recommend using Kotlinx-DateTime, because it’s official Kotlin stuff. However, there are some problems that need to be solved, and a perfect solution will be provided later.

Begin to use

The preparatory work

The first step is to increase the kotlinx-dateTime dependency and configure API desugaring. Since Java8 apis are not available until SDK 26 or later, desugar can get rid of this limitation and make Java8 apis available in lower versions as well.

android {
    defaultConfig {
        // Enable minSdkVersion if minSdkVersion 20 or later
        multiDexEnabled true
    }

    compileOptions {
        // Enable support for new language apis
        coreLibraryDesugaringEnabled true
        // Java 8
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    coreLibraryDesugaring 'com. Android. The tools: desugar_jdk_libs: 1.1.5'
    implementation 'org. Jetbrains. Kotlinx: kotlinx - a datetime: 0.3.2'
}
Copy the code

type

Instant

Represents a time at which an object can be created with a timestamp.

val instant = Instant.fromEpochSeconds(164367360)
// val instant = Instant.fromEpochMilliseconds(164367360000)
Copy the code

Instant keeps timestamps in seconds and more accurate nanoseconds.

val second = instant.epochSecond
val nano = instant.nanosecondsOfSecond
Copy the code

LocalDateTime

Represents a local date and time that holds information about year, month, day, hour, minute, second, nanosecond.

val localDateTime = LocalDateTime(2022.2.1.8.0.0)
val year = localDateTime.year
val hour = localDateTime.hour
Copy the code

LocalDate

Represents a local date that holds year, month and day information.

val springFestival = LocalDate(2022.2.1)
val year = springFestival.year
val month = springFestival.month.value
val dayOfMonth = springFestival.dayOfMonth
Copy the code

LocalDate is the date component of LocalDateTime.

val localDate = localDateTime.date
Copy the code

To convert LocalDate to LocalDateTime, you need to add the time information.

val localDateTime = localDate.atTime(10.8)
Copy the code

Clock

Represents a clock, which can be understood as an electronic clock in life. It is used to view the current time and today’s date.

val now: Instant = Clock.System.now()
val timeZone: TimeZone = TimeZone.currentSystemDefault()
val today: LocalDate = Clock.System.todayAt(timeZone)
Copy the code

DayOfWeek/Month

It can be obtained from the LocalDateTime or LocalDate object, or by using enumeration variables such as dayofweek. MONDAY or month. JANUARY.

val localDate = LocalDate(2022.2.1)

val dayOfWeek: DayOfWeek = localDate.dayOfWeek
dayOfWeek.getDisplayName(TextStyle.FULL, Locale.CHINA)     / / Tuesday
dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.CHINA)    / / on Tuesday
dayOfWeek.getDisplayName(TextStyle.NARROW, Locale.CHINA)   / / 2
dayOfWeek.getDisplayName(TextStyle.FULL, Locale.ENGLISH)   // Tuesday
dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.ENGLISH)  // Tue
dayOfWeek.getDisplayName(TextStyle.NARROW, Locale.ENGLISH) // T

val month: Month = localDate.month
month.getDisplayName(TextStyle.FULL, Locale.CHINA)     / / February
month.getDisplayName(TextStyle.SHORT, Locale.CHINA)    / / 2 months
month.getDisplayName(TextStyle.NARROW, Locale.CHINA)   / / 2
month.getDisplayName(TextStyle.FULL, Locale.ENGLISH)   // February
month.getDisplayName(TextStyle.SHORT, Locale.ENGLISH)  // Feb
month.getDisplayName(TextStyle.NARROW, Locale.ENGLISH) // F
Copy the code

It used to be nice to draw the week and month axes without having to figure out what text to display. Text style can be long or short, but also support multiple languages, directly in line with the NEEDS of UI.

usage

Kotlinx-datetime provides a number of classes for handling dates and times, but our development focuses on handling timestamps and specific dates and times, so we focus on Instant, LocalDateTime and LocalDate, and the rest of the class is basically for auxiliary use.

Here are some basic official recommendations for choosing which type to use in what situations:

  • Instant is used to indicate the time stamp of an event that has occurred in the past (such as the timestamp of a chat) or is certain to occur at a clearly defined time in the near future (such as an order confirmation deadline in one hour).

  • LocalDateTime is used to indicate the time when an event is scheduled to occur at some point in the long future (such as a scheduled meeting in a few months). Time zones for scheduled events must be tracked separately. Try to avoid converting future events to Instant ahead of time because the time zone rules may change unexpectedly in the future. In addition, converting Instant to LocalDateTime can be used to display the time on the UI.

  • Use LocalDate to represent the date of an event (such as a birth date) that is not associated with a specific time.

Time to calculate

Instant calculation

To add or subtract a specified number of days, units of time, or periods:

val now = Clock.System.now()
val timeZone = TimeZone.currentSystemDefault()
val tomorrow = now.plus(2, DateTimeUnit.DAY, timeZone)
val threeYearsAndAMonthLater = now.plus(DateTimePeriod(years = 3, months = 1), timeZone)
Copy the code

Invoke Instant. PeriodUntil (Instant, TimeZone) function can be two times vary the time period.

val period: DateTimePeriod = instantInThePast.periodUntil(Clock.System.now(), TimeZone.UTC)
val hours = period.hours   // By how many hours
Copy the code

Until (Instant, dateTimeUnit.timebased, TimeZone) can also be used to calculate the difference as the number of units of a specified date or time:

val diffInMonths: Int = instantInThePast.until(Clock.System.now(), DateTimeUnit.MONTH, TimeZone.UTC)
Copy the code

YearsUntil (…) is also provided. , monthsUntil (…). , daysUntil (…). The function directly yields that the two moments are years, months, and days apart.

Note that plus and… TimeZone is required for the until operation because the calendar interval between two specific moments can be different when calculating in different time zones.

LocalDate calculation

LocalDate has the same plus(…) as Instant. , until (…). , periodUntil (…). , yearsUntil (…). , monthUntil (…). , daysUntil (…). Function. Datetimeunit. DateBased, DatePeriod, and time zone do not need to be transmitted.

LocalDateTime calculation

LocalDateTime does not perform this calculation because the daylight saving time (DST) conversion can cause uncertainty. Areas that use daylight saving Time will move it forward one hour toward the start of spring and back to normal time in the fall.

Because LocalDateTime represents a date and time independent of the time zone, a day may be added instead of 24 hours, so it cannot be directly calculated using LocalDateTime. You need to convert to Instant for calculation, and then go back to LocalDateTime to get the date and time of a certain time zone, so that there is no error.

val timeZone = TimeZone.of("Europe/Berlin")
val localDateTime = LocalDateTime.parse("2021-03-27T02:16:20")
val instant = localDateTime.toInstant(timeZone)

val instantOneDayLater = instant.plus(1, DateTimeUnit.DAY, timeZone)
val localDateTimeOneDayLater = instantOneDayLater.toLocalDateTime(timeZone)
// 2021-03-28T03:16:20, the same time at 02:16:20

val instantTwoDaysLater = instant.plus(2, DateTimeUnit.DAY, timeZone)
val localDateTimeTwoDaysLater = instantTwoDaysLater.toLocalDateTime(timeZone)
// 2021-03-29T02:16:20
Copy the code

A little time

Due to Kotlin’s syntax for operator overloading, Instant, LocalDateTime, and LocalDate can be directly compared to the size of the time.

if (instant1 < instant2) {
  // ...
}
Copy the code
if (localDateTime1 >= localDateTime2) {
  // ...
}
Copy the code

Time transformation

The date and time obtained at the same time in different time zones are different, so Instant and LocalDateTime transfer each other with a time zone parameter.

val instant = Clock.System.now()
val timeZone = TimeZone.currentSystemDefault()
val localDateTime = instant.toLocalDateTime(timeZone)
Copy the code
val localDateTime = LocalDateTime(2022.2.1.8.0)
val timeZone = TimeZone.currentSystemDefault()
val instant = localDateTime.toInstant(timeZone)
Copy the code

The most common thing we develop is timestamps and string conversions, and Instant stores timestamps, so we care about Instant, LocalDateTime, and string conversions.

However, Instant, LocalDateTime, and LocalDate support only ISO-8601 formats. So there is no format() function, only the toString() function is called to convert the string into the corresponding format.

instant.toString()        / / the T12:2022-02-01 30:00. 048 z
localDateTime.toString()  // 2022-02-01T12:30:00
localDate.toString()      / / 2022-02-01
Copy the code

Similarly, only isO-8601 characters can be converted into Instant, LocalDateTime, and LocalDate.

"The 2022-02-01 T12:30:00. 048 z".toInstant()
"2022-02-01T12:30:00".toLocalDateTime()
"2022-02-01".toLocalDate()
Copy the code

Because Kotlinx-DateTime is a multi-platform date and time library, it is not easy to implement in Java, but it is not easy to implement in other platforms that require tools from other platforms.

It will take years for Kotlin to officially implement the formatting function, but after some time of research, we found that there is a way to improve it ourselves. Let me share with you the perfect solution I found.

Encapsulation optimization

Improve formatting and parsing capabilities

Above all, of course, it is to search the net to have it doesn’t matter to solve train of thought. Since the library is a bit new, there are very few articles to explain, so I searched for a long time and found only one useful solution:

"The 2010-06-01 22:19:44".replace(""."T").toLocalDateTime()
Copy the code

It does work, but only if the format is YYYY-MM-DD HH: MM: SS, and it doesn’t work if you change the format.

Since there are no good solutions online, do your own research. A deep dive into the source code shows that kotlinx-DateTime’s API is proxying to the corresponding Java8 object in the JVM. LocalDateTime = LocalDateTime

import java.time.LocalDateTime as jtLocalDateTime

@Serializable(with = LocalDateTimeIso8601Serializer::class)
public actual class LocalDateTime internal constructor(internal val value: jtLocalDateTime) : Comparable<LocalDateTime> {

  public actual constructor(year: Int, monthNumber: Int, dayOfMonth: Int, hour: Int, minute: Int, second: Int, nanosecond: Int) :
          this(try {
            jtLocalDateTime.of(year, monthNumber, dayOfMonth, hour, minute, second, nanosecond)
          } catch (e: DateTimeException) {
            throw IllegalArgumentException(e)
          })
  
  public actual val year: Int get() = value.year
  public actual val monthNumber: Int get() = value.monthValue
  public actual val month: Month get() = value.month
  public actual val dayOfMonth: Int get() = value.dayOfMonth
  public actual val dayOfWeek: DayOfWeek get() = value.dayOfWeek
  public actual val dayOfYear: Int get() = value.dayOfYear

  public actual val hour: Int get() = value.hour
  public actual val minute: Int get() = value.minute
  public actual val second: Int get() = value.second
  public actual val nanosecond: Int get() = value.nano
  
  // Omit some code
}
Copy the code

JtLocalDateTime is an alias for Java8’s java.time.LocalDateTime, which is passed in the constructor. Kotlin’s LocalDateTime functionality is all implemented by proxy to Java8 objects.

We can do the same with Java8 objects for formatting and then Kotlin objects. The problem was that Java8 objects were internal and not public, and it was not practical to manually implement a set of time formatting functions, so the idea got stuck. After thinking for a long time, WE came up with a curve to save the country. Since we can’t get java8 objects directly, we will manually create one ourselves.

ToLocalDateTime () to support any format when converting, you must pass an extra parameter and optimize it for the following usage.

"February 01, 2022 22:19:44".toLocalDateTime("Yyyy yyyy MM dd day HH: MM :ss")
Copy the code

This can be done by adding an extension function. Java8’s LocalDateTime is first resolved, and then Kotlin’s LocalDateTime is created using year, month, day, hour, minute, second.

fun String.toLocalDateTime(pattern: String): LocalDateTime =
  java.time.LocalDateTime.parse(this, DateTimeFormatter.ofPattern(pattern))
    .run { LocalDateTime(year, month, dayOfMonth, hour, minute, second, nano) }
Copy the code

The test really got the results we wanted!! You can use this idea to implement other formatting and parsing functions.

It turns out that this idea is slightly flawed, namely that we create Java8 objects repeatedly, once manually, and then again in the constructor, which feels too boring.

A bit of a perfectionist, I went back to the library source code to see if this was the only way to do it, only to find a converters.kt file in the JVM module containing various extensions to Kotlin and Java8’s date and time classes. The Java8 object is internal modified by extension methods.

/** * Converts this [kotlinx.datetime.LocalDateTime][LocalDateTime] value to a [java.time.LocalDateTime][java.time.LocalDateTime] value. */
public fun LocalDateTime.toJavaLocalDateTime(a): java.time.LocalDateTime = this.value

/** * Converts this [java.time.LocalDateTime][java.time.LocalDateTime] value to a [kotlinx.datetime.LocalDateTime][LocalDateTime] value. */
public fun java.time.LocalDateTime.toKotlinLocalDateTime(a): LocalDateTime = LocalDateTime(this)
Copy the code

Instead of creating Kotlin’s LocalDateTime code with year, month, day, hour, minute and second, we’ll call the official toKotlinLocalDateTime() function.

fun String.toLocalDateTime(pattern: String): LocalDateTime =
  java.time.LocalDateTime.parse(this, DateTimeFormatter.ofPattern(pattern)).toKotlinLocalDateTime()
Copy the code

This eliminates the need to create Java8 objects repeatedly, eliminating formatting problems perfectly.

We can also use this idea to add more formatting and parsing capabilities for everyday use.

fun Instant.Companion.parse(text: String, pattern: String, timeZone: TimeZone): Instant =
  java.time.ZonedDateTime.parse(text, DateTimeFormatter.ofPattern(pattern).withZone(timeZone.toJavaZoneId())).toInstant().toKotlinInstant()

fun LocalDateTime.Companion.parse(text: String, pattern: String): LocalDateTime =
  java.time.LocalDateTime.parse(text, DateTimeFormatter.ofPattern(pattern)).toKotlinLocalDateTime()

fun LocalDate.Companion.parse(text: String, pattern: String): LocalDate =
  java.time.LocalDate.parse(text, DateTimeFormatter.ofPattern(pattern)).toKotlinLocalDate()

fun String.toInstant(pattern: String, timeZone: TimeZone): Instant = Instant.parse(this, pattern, timeZone)

fun String.toLocalDateTime(pattern: String): LocalDateTime = LocalDateTime.parse(this, pattern)

fun String.toLocalDate(pattern: String): LocalDate = LocalDate.parse(this, pattern)

fun Instant.format(pattern: String, timeZone: TimeZone): String =
  DateTimeFormatter.ofPattern(pattern).withZone(timeZone.toJavaZoneId()).format(toJavaInstant())

fun LocalDate.format(pattern: String): String =
  DateTimeFormatter.ofPattern(pattern).format(toJavaLocalDate())

fun LocalDateTime.format(pattern: String): String =
  DateTimeFormatter.ofPattern(pattern).format(toJavaLocalDateTime())
Copy the code

Simplify default time zone parameters

The other thing about Kotlinx-DateTime that is a bit cumbersome to use is that the time zone parameters are mandatory. In most cases will go to get the default time zone and the call TimeZone. CurrentSystemDefault () code is a bit long.

Originally I wanted to write an extension function to override it.

fun LocalDateTime.toInstant(a): Instant = toInstant(TimeZone.currentSystemDefault())
Copy the code

But on second thought, the official can give the default parameter without us, and the official did not do so. So personal speculation is not official suggested that we frequently called TimeZone. CurrentSystemDefault () to obtain the default TimeZone, later found a pull request confirmed my guess.

This is a the TimeZone. The SYSTEM constants to the TimeZone. CurrentSystemDefault pr () method, the reason is that in the original environment query time zone is an expensive operation, considering the most JRE implementations would not update the SYSTEM time zone, So it was originally defined to get a constant only once. However, the problem with doing this, at least on Android, is that it is not feasible to assume the same time zone.

Note the following when passing the default time zone parameters:

  • TimeZone.currentSystemDefault()It should be called as infrequently as possible, and that should be cached.
  • Android takes time zone changes into account.

It’s hard to find this detail on your own, because the API for getting the default time zone is deliberately long and mandatory. This is more cumbersome to use, and you might want to consider caching the default time zone.

We can use property delegates for encapsulation. Declare a TimeZone attribute in the properties of entrust a TimeZone variable declared in a class, only at the time of initialization and time zone change CaiFu value TimeZone. CurrentSystemDefault (). The delegate code is as follows:

val systemTimeZone: TimeZone by object: ReadOnlyProperty<Any? , TimeZone> {private lateinit var timeZone: TimeZone

  override fun getValue(thisRef: Any? , property:KProperty< * >): TimeZone {
    if(! ::timeZone.isInitialized) { timeZone = TimeZone.currentSystemDefault() application.registerReceiver(object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent?). {
          if(intent? .action == Intent.ACTION_TIMEZONE_CHANGED) { timeZone = TimeZone.currentSystemDefault() } } }, IntentFilter(Intent.ACTION_TIMEZONE_CHANGED)) }return timeZone
  }
}
Copy the code

You can then override an extension to the function that requires the time zone argument, passing in the above attributes.

fun LocalDateTime.toInstant(a): Instant = toInstant(systemTimeZone)
Copy the code

When we do not pass the TimeZone parameter, we will get the default TimeZone for the cache, and this cache will change with the TimeZone.

If you are not familiar with attribute delegation, you can read my article “The Nature of attribute delegation and the Application of MMKV”.

Final plan

Finally, a personal encapsulation of the Kotlin tool library, Longan. Probably the most useful Kotlin library, because Kotlin syntax is a lot of sugar, I think the API design of the tool class is very important. So each usage is a lot of personal thought and reference to the official KTX library naming conventions and usage, and is much simpler and easier to use than the Kotlin utility classes most people package, and the functionality is as simple and lightweight as possible. After several iterations, there are now over 500 common methods or attributes that can greatly improve development efficiency.

The latest version has integrated the Kotlinx-DateTime dependency with the aforementioned encapsulation, providing a complete set of handy date-time functionality. Compared to using Kotlinx-dateTime directly, there are the following improvements:

  • Supports any time format conversion, not limited to ISO-8601 format.
  • If the time zone is not sent, the default time zone will be obtained in an optimal way.
  • Added more Java8 features.

Begin to use

Add dependency and desugar configuration:

allprojects {
    repositories {
        // ...
        maven { url 'https://www.jitpack.io'}}}Copy the code
android {
    compileOptions {
        coreLibraryDesugaringEnabled true
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
    coreLibraryDesugaring 'com. Android. The tools: desugar_jdk_libs: 1.1.5'
    implementation 'com. Making. DylanCaiCoding. Longan, Longan, 1.0.5'
}
Copy the code

Time stamps, strings, Instant, and LocalDateTime can be exchanged more easily without passing time zone parameters.

Instant.fromEpochSeconds(1643673600).format("yyyy-MM-dd HH:mm:ss") // Timestamp to string
Instant.fromEpochSeconds(1643673600).toLocalDateTime()             // Go to LocalDateTime
Instant.fromEpochSeconds(1643673600)                               // Go to Instant
"The 2022-02-01 08:00:00".toEpochSeconds("yyyy-MM-dd HH:mm:ss")        // String to timestamp
"The 2022-02-01 08:00:00".toLocalDateTime("yyyy-MM-dd HH:mm:ss")       // The string goes to LocalDateTime
"The 2022-02-01 08:00:00".toInstant("yyyy-MM-dd HH:mm:ss")             // String to Instant
localDateTime.toInstant().epochSeconds                             // LocalDateTime turn to timestamp
localDateTime.format("The 2022-02-01 08:00:00")                        // LocalDateTime to a string
localDateTime.toInstant()                                          / / LocalDateTime Instant
instant.epochSeconds                                               // Instant turn to timestamp
instant.format("yyyy-MM-dd HH:mm:ss")                              // Instant to string
instant.toLocalDateTime()                                          / / Instant LocalDateTime
Copy the code

Added more features available in Java8 that kotlinx-datetime does not:

val localDate = LocalDate(2022.2.15)
localDate.withYear(2021)               // 2021-02-15, adjust year
localDate.withMonth(5)                 // 2021-05-15, adjust month
localDate.withDayOfMonth(18)           // 2021-02-18, adjust date
localDate.withDayOfYear(60)            // 2021-03-01, adjust the number of days this year
localDate.firstDayOfMonth()            // 2022-02-01, first day of the month
localDate.lastDayOfMonth()             // 2022-02-28, last day of the month
localDate.firstDayOfNextMonth()        // 2022-03-01, first day of next month
localDate.firstDayOfLastMonth()        // 2022-01-01, first day of last month
localDate.firstDayOfYear()             // 2022-01-01, first day of the year
localDate.lastDayOfYear()              // 2022-12-31, last day of the year
localDate.firstDayOfNextYear()         2023-01-01, the first day of tomorrow
localDate.firstDayOfLastYear()         // 2021-01-01, the first day of last year
localDate.firstInMonth(TUESDAY)        // 2022-02-01, first Tuesday of the month
localDate.lastInMonth(TUESDAY)         // 2022-02-22, last Tuesday of the month
localDate.dayOfWeekInMonth(2, TUESDAY) // 2022-02-08, second Tuesday of the month
localDate.next(TUESDAY)                // 2022-02-22, next Tuesday, not today
localDate.previous(TUESDAY)            // 2022-02-08, last Tuesday, not including today
localDate.nextOrSame(TUESDAY)          // 2022-02-15, next Tuesday, including today
localDate.previousOrSame(TUESDAY)      // 2022-02-15, last Tuesday, including today
Copy the code

Package ideas and similar to the front, interested in their own look at the source code.

The practical application

Finally, use an example of wechat time to combat, personal summary of the wechat time display has the following rules:

  1. Today’s shows only the time, likeAt 10:08.
  2. Yesterday shows yesterday + time, for example18:00 yesterday.
  3. Shows week + time earlier than yesterday and within the week, for exampleOn Tuesday, 06:30.
  4. Not this week but in this year’s month + time + time, for exampleFebruary 1st 00:01 in the morning.
  5. If none of the preceding conditions are met, the system displays year, month, day + time segment + time segment, for exampleOctober 1, 2021, 10:00 a.m.

The above logic would have been a lot of trouble to calculate with Date, but with Kotlinx-DateTime and the personally wrapped extension method, it only takes a little code.

fun getFriendlyTimeString(millis: Long): String {
  val localDateTime = Instant.fromEpochMilliseconds(millis).toLocalDateTime()
  val today = Clock.System.today
  val pattern = when {
    localDateTime.date == today -> "HH:mm"
    localDateTime.date == today.minus(1, DAY) -> "Yesterday, HH: mm"
    localDateTime.date >= today.previousOrSame(MONDAY) -> "EE HH:mm"
    localDateTime.year == today.year -> "On dd MM${localDateTime.timeRange} HH:mm"
    else -> "Yyyy MM month DD day${localDateTime.timeRange} HH:mm"
  }
  return localDateTime.format(pattern, Locale.CHINA)
}

private val LocalDateTime.timeRange: String
  get() = when (hour) {
    in 0.. 5 -> "Morning"
    in 6.12. -> "Morning"
    in 13.17. -> "Afternoon"
    else -> "Night"
  }
Copy the code

Is it very easy to use, hurry to try it!!

reference

  • Kotlinx-datetime official document
  • LocalDataTime tutorial by liao xuefeng
  • Java 8 and later API deicing support

An article on packaging ideas

  • How to Better Use the Kotlin Syntax Sugar Wrapper Utility Class
  • The Nature of Attribute Delegation and the Application of MMKV
  • Elegantly encapsulating and using ViewBinding, time to replace Kotlin Synthetic and ButterKnife
  • ViewBinding cleverly encapsulates ideas and ADAPTS BRVAH in this way
  • Gracefully Handling Data Returned from the background

conclusion

This article introduces the differences between the time and date apis of Java7, Java8 and Kotlinx-DateTime libraries. It also introduces the usage of the kotlinx-dateTime type. If you read the official kotlinx-DateTime document, you may not know how to convert the various time and date formats, and you may frequently call the method to get the default time zone. I have provided a perfect solution to this problem.

Finally share personal encapsulation Kotlin tool library Longan, based on Kotlinx-DateTime encapsulation of a complete set of useful date and time functions, and use a wechat time example to practice. If you feel helpful, I hope you can click a star to support yo ~ I will share more encapsulation related articles to you later.

Any use of the personal package library can add wechat DylanCaiCoding direct feedback, some packaging problems can also be discussed together oh ~