Kotlin
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Null Safety
-
Section 4: Object-Oriented Kotlin
-
Section 5: Functional Kotlin
-
Section 6: Coroutines
-
Section 7: Collections Deep Dive
-
Section 8: Type System Deep Dive
-
Section 9: Interop and Tooling
-
Section 10: Kotlin DSLs and Patterns
-
Section 11: Testing and Quality
-
Section 12: Server-Side Kotlin
-
Section 13: Practical Projects
-
Section 14: Interview Practice
-
Section 15: More Practice Exercises
-
Section 16: More Standard Library
-
Section 17: Multiplatform Kotlin
-
Section 18: kotlin.collections In Depth
-
Section 19: kotlin.text In Depth
-
Section 20: kotlin.ranges and kotlin.sequences
-
Section 21: kotlin.io and File Handling
-
Section 22: kotlinx.coroutines Deep Dive
-
Section 23: kotlin.reflect
-
Section 24: Android Development with Kotlin Overview
-
Section 25: Kotlin Multiplatform Deep Dive
-
Section 26: Kotlin for Backend Deep Dive
-
Section 27: Kotlin Design Patterns
-
Section 28: Advanced Language Features
-
Section 29: More Practice Exercises
-
Section 30: More Interview Practice
-
Section 31: Kotlin Type System Deep Dive
-
Section 32: Kotlin Null Safety Advanced
-
Section 33: Kotlin Testing Deep Dive
-
Section 34: Kotlin Build Tooling Deep Dive
-
Section 35: Kotlin Serialization
-
Section 36: Kotlin Performance Considerations
-
Section 37: Kotlin Native Overview
-
Section 38: Kotlin for Data and Scripting
-
Section 39: More Coroutines Practice
-
Section 40: More Android-Adjacent Patterns
-
Section 41: More Practical Projects
-
Section 42: More Design and Architecture Practice
-
Section 43: Kotlin Language Evolution
-
Section 44: More Interview and Review
-
Section 45: Kotlin Delegation Patterns Deep Dive
-
Section 46: Kotlin Annotations Deep Dive
-
Section 47: Kotlin for Gradle Plugin Development
-
Section 48: Kotlin Concurrency Beyond Coroutines
-
Section 49: Kotlin Compiler Internals
-
Section 50: Real-World Kotlin Case Studies
-
Section 51: Final Practice Projects
-
Section 52: Kotlin for Server-Side Reactive Programming
-
Section 53: More Practice and Drills
-
Section 54: Kotlin Security Practices
78: Working with Dates and Times in Kotlin
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
ZonedDateTimefor 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
DateTimeFormatterthat shows the day of the week, the date, and the time (e.g., "Wednesday, Oct 25, 18:00"). - Calculate and print the
Durationbetween the host's meeting time and the currentInstant.now()to show how many hours/minutes remain until the meeting.
There are no comments for now.