Get up to 80 % extra points for free! More info:

Lesson 12 - Date and Time in Kotlin - Modifying and intervals

In the previous lesson, Date and Time in Kotlin - Creating and formatting, we learned to create LocalDate, LocalTime, and LocalDateTime instances and format their value. In today's tutorial of our Kotlin course, we're going to modify the value and introduce time intervals.

Conversions

First of all, we'll learn how to convert between the LocalDate, LocalTime, and LocalDateTime data types.

Converting from LocalDateTime

We convert from LocalDateTime easily by using the toLocalDate() and toLocalTime() methods.

Converting to LocalDateTime

We create LocalDateTime instances using one of the of*() methods where we specify the date and time separately:

val beginning = LocalDate.of(1939, 9, 1)
val dateTime = LocalDateTime.of(beginning, LocalTime.of(10, 0))

If we want to set the time at the very beginning of the day, we can use the atStartOfDay() method. Another method, which allows us to take a date and attach a time to it, is atTime(). Here’s an alternative approach for the example above:

val beginning = LocalDate.of(1939, 9, 1)
val dateTime = beginning.atStartOfDay()
val dateTime2 = beginning.atTime(0, 0)

Modifying the value

We can add a particular number of days, hours and so on to an existing instance. We use the methods with the plus...() or minus...() prefix to do just that. I'm sure we don't have to explain which does what. The important thing to remember is that they return a new instance with the modified value. The instance is completely immutable (unchangeable) and any changes are made by replacing the original instance with a new one (as we do with Strings).

Here’s an example where we add three more days to the current date:

val dateTime = LocalDateTime.now()
dateTime = dateTime.plusDays(3)
println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)))

The result:

Dec 9, 2016

Here's a list of the available methods:

  • minusDays()
  • minusHours()
  • minusMinutes()
  • minusMonths()
  • minusNanos()
  • minusSeconds()
  • minusWeeks()
  • minusYears()
  • plusDays()
  • plusHours()
  • plusMinutes()
  • plusMonths()
  • plusNanos()
  • plusSeconds()
  • plusWeeks()
  • plusYears()

Periods and Durations

Aside from the methods we've already mentioned, there are also four general minus() and plus() methods which receive an interval that is to be added or subtracted. They come in handy when we don't know whether we're going to add days or years at a specific point in the application, so they spare us from having to implement complex branching. There are also Duration and Period classes available, which provide us objects representing time intervals.

When we get to interfaces, you can check that both classes implement the TemporalAmount interface. However, don't worry about it too much for now.

Here's a modified version of the example code from before:

val dateTime = LocalDateTime.now()
dateTime = dateTime.plus(Period.ofDays(3))
println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)))

Because Kotlin allows us to overload operators (see further in the course), we can rewrite the code above like this:

var dateTime = LocalDateTime.now()
dateTime += Period.ofDays(3)
println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)))

The output will remain the same as with the previous example. The of...*() methods have the same "suffixes" as the plus()/minus() methods listed above.

The difference between Period and Duration is that Duration represents a time interval which isn't related to the calendar anyhow (e.g. how long it takes to manufacture a car), a day always lasts 24 hours there. Whereas, Period also takes daylight saving time into consideration, so a day may sometimes be 23 or 25 hours long. We use Period to work with LocalDate/LocalDateTime and Duration to work exclusively with time.

ChronoUnit

To make units (such as days, hours, minutes and similar) easier to work with, there's the ChronoUnit class. It uses the Duration class internally, so all it provides is a different syntax for the tasks we demonstrated above. For completeness' sake, we'll go over an example of its use:

var dateTime = LocalDateTime.now()
dateTime = dateTime.plus(3, ChronoUnit.DAYS)
println(dateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.MEDIUM)))

ChronoUnit implements the TemporalUnit interface, in case you meet it later on. We'll introduce interfaces later in the course.

As you can see, the implementation of date and time in Kotlin is quite complex. We won't go into unnecessary details. Instead, we'll focus on practical use, as we always do here at ICT.social.

Between()

The last method worth mentioning is the static between() method in the Period class. It allows us to compute the difference (interval) between 2 dates. More accurately, it computes the difference between two objects implementing the Temporal interface, which is the common data type for the LocalDate, LocalDateTime, and LocalTime classes.

val started = LocalDate.of(1939, 9, 1)
val ended = LocalDate.of(1945, 9, 2)
val period = Period.between(started, ended)
println("The World War II lasted for " + period.get(ChronoUnit.YEARS) + " years and " + period.get(ChronoUnit.DAYS) + " days")

The output:

The World War II lasted for 6 years and 1 days

The same method is available in the Duration class, however, that one works with LocalDateTime rather than LocalDate. We wouldn’t be able to extract the number of years from an interval since years don't have a fixed amount of days and Duration isn't related to calendar-based time.

Setting the value

We set the value using the with...*() methods, they all have the same suffixes as the methods mentioned earlier. As always, remember that they only return a new instance and don't modify the current one.

val started = LocalDate.of(1939, 9, 1)
started = started.withYear(1945) // Sets the year to 1945

Method chaining

The fact that all of the methods return new instances, so as to keep classes immutable, also allows us to use the fluent interface, aka "method chaining". It really isn’t all that complicated, all it means is that we’re able to call multiple methods on a single line.

Let's set the value to programmer Christmas, i.e. Halloween (since, 31 OCT = 25 DEC).

var started = LocalDate.of(1939, 9, 1)
started = started.withMonth(9).withDayOfMonth(31)

We'll continue in the next lesson, Date and Time in Kotlin- Parsing and comparing, where we'll finish up with date and time in Kotlin. We'll learn how to parse date and time and how to access inner values.


 

Previous article
Date and Time in Kotlin - Creating and formatting
All articles in this section
Object-Oriented Programming in Kotlin
Skip article
(not recommended)
Date and Time in Kotlin- Parsing and comparing
Article has been written for you by Samuel Kodytek
Avatar
User rating:
1 votes
I'm intereseted in JVM languages and Swift
Activities