Skip to Content
Course content

78: Working with Dates and Times in Kotlin

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I once spent an entire Friday night debugging a "ghost" bug where users in Australia were seeing their appointment reminders arrive a day early. The culprit? I was using LocalDateTime on the server, which completely ignored the user's timezone offset. I thought I was being clever by just storing the "wall clock" time, but in a distributed system, that's a recipe for disaster. If you don't explicitly handle timezones, you're essentially guessing where your user is standing on the planet.

In Kotlin, we don't have a built-in date library in the standard library; instead, we lean on the java.time package (introduced in Java 8). It's a robust, immutable API that separates "human time" from "machine time." Understanding this distinction is the key to avoiding those late-night debugging sessions.

Choosing the Right Temporal Type

The biggest mistake I see developers make is grabbing the first "Date" class they see. You need to choose your tool based on the context of the data. If you're recording a user's birthday, you don't care about the time or the timezone—you just need LocalDate. If you're scheduling a store's opening hours, LocalTime is your friend.

However, for almost everything else—logs, transaction timestamps, or event scheduling—you want Instant. An Instant represents a single point on the timeline in UTC. It's the "truth" of when something happened, regardless of where the observer is located. When you need to show that Instant to a human, you convert it to a ZonedDateTime.

import java.time.*

fun main() {
    // The "Machine Time": Absolute point in UTC
    val now = Instant.now() 
    println("UTC Instant: $now")

    // The "Human Time": Adjusting that instant to a specific region
    val tokyoTime = now.atZone(ZoneId.of("Asia/Tokyo"))
    val nyTime = now.atZone(ZoneId.of("America/New_York"))

    println("Tokyo: $tokyoTime")
    println("New York: $nyTime")
}

Calculating Gaps and Durations

You'll often need to find the difference between two points in time. This is where it gets tricky because there's a difference between a Duration and a Period. I remember mixing these up in a billing project, and it resulted in some very confused customers.

Use Duration when you're dealing with time based on seconds and nanoseconds (machine time). Use Period when you're dealing with conceptual calendar time—years, months, and days. Why the distinction? Because a "day" isn't always 24 hours (thanks, Daylight Savings Time). If you add a Period of one day to a date, it moves to the next calendar day, regardless of whether that day was 23 or 25 hours long.

val start = LocalDate.of(2023, 1, 1)
val end = LocalDate.of(2023, 12, 25)
val christmasWait = Period.between(start, end)
println("Wait until Christmas: ${christmasmasWait.months} months and ${christmasWait.days} days")

val time1 = LocalTime.of(10, 0)
val time2 = LocalTime.of(14, 30)
val workGap = Duration.between(time1, time2)
println("Hours worked: ${workGap.toHours()}h ${workGap.toMinutesPart()}m")

Formatting for Humans

Printing a ZonedDateTime directly to a UI is a great way to make your app look like a raw database dump. To make dates readable, we use DateTimeFormatter. I highly recommend using the predefined ISO constants if you're sending data to an API, but for the UI, you'll want a custom pattern.

Just a heads-up: be careful with the pattern letters. 'm' is for minutes, while 'M' is for months. I've seen plenty of developers accidentally tell their users that a meeting is in "October minutes" because of a lowercase letter.

import java.time.format.DateTimeFormatter

val current = LocalDateTime.now()
val formatter = DateTimeFormatter.ofPattern("EEEE, MMM dd, yyyy 'at' hh:mm a")
val formatted = current.format(formatter)
println("The current time is: $formatted") 
// Example output: Monday, Oct 23, 2023 at 02:45 PM



📋 Practical Task

Exercise: International Meeting Sync Tool

You are building a small utility for a global team. Your task is to create a program that takes a specific "Meeting Time" in one timezone and calculates what time that meeting occurs for three other team members in different parts of the world.

Requirements:

  • Define a meeting time using ZonedDateTime for the host in "America/Los_Angeles" (e.g., October 25th, 2023, at 10:00 AM).
  • Convert this specific meeting time to the local times of "Europe/London", "Asia/Tokyo", and "Australia/Sydney".
  • Format the output for each person using a DateTimeFormatter that shows the day of the week, the date, and the time (e.g., "Wednesday, Oct 25, 18:00").
  • Calculate and print the Duration between the host's meeting time and the current Instant.now() to show how many hours/minutes remain until the meeting.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.