MpZonedDateTime
The full package: date, time, and timezone. Has the richest feature set of any datetime type because it has all the information needed to do everything correctly.
When to use MpZonedDateTime
- Displaying dates and times to users (with timezone context)
- Scheduling across timezones ("meeting at 3 PM Berlin time")
- Any arithmetic where DST must be handled correctly
- Formatting with timezone offsets
If MpInstant answers "when," MpZonedDateTime answers "when, and what does the clock say?"
Creating
import io.peekandpoke.ultra.datetime.MpZonedDateTime
import io.peekandpoke.ultra.datetime.MpTimezone
// From components
val zoned = MpZonedDateTime.of(
MpLocalDateTime.of(2025, 6, 15, 14, 0),
MpTimezone.of("Europe/Berlin"),
)
// From an ISO string with timezone
val parsed = MpZonedDateTime.parse("2025-06-15T14:00:00+02:00[Europe/Berlin]")
val maybe = MpZonedDateTime.tryParse("not-valid") // null
// From epoch with timezone
val fromMillis = MpZonedDateTime.fromEpochMillis(
millis = 1718452800000L,
timezone = MpTimezone.of("Europe/Berlin"),
)
// Boundaries
val genesis = MpZonedDateTime.Genesis
val doomsday = MpZonedDateTime.Doomsday Properties
MpZonedDateTime exposes all date and time components — because it has a timezone, these are always unambiguous:
val zoned = MpZonedDateTime.of(
MpLocalDateTime.of(2025, 6, 15, 14, 30, 45),
MpTimezone.of("Europe/Berlin"),
)
zoned.year // 2025
zoned.monthNumber // 6
zoned.month // Month.JUNE
zoned.dayOfMonth // 15
zoned.hour // 14
zoned.minute // 30
zoned.second // 45
zoned.milliSecond // 0
zoned.dayOfWeek // DayOfWeek.SUNDAY
zoned.dayOfYear // 166
zoned.timezone // MpTimezone("Europe/Berlin") DST-aware arithmetic
MpZonedDateTime carries its timezone, so all arithmetic handles DST transitions automatically:
import kotlinx.datetime.DateTimeUnit
import kotlin.time.Duration.Companion.hours
val zoned = MpZonedDateTime.of(
MpLocalDateTime.of(2025, 3, 30, 1, 0), // 1 AM
MpTimezone.of("Europe/Berlin"), // DST spring-forward at 2 AM
)
// Calendar "1 day" — same local time tomorrow (24h? 23h? handled correctly)
val tomorrow = zoned.plus(1, DateTimeUnit.DAY)
println(tomorrow.hour) // 1 (same local time, DST-adjusted)
// Absolute "24 hours" — might land on a different local time
val plus24h = zoned.plus(24.hours)
// Months and years
val nextMonth = zoned.plus(1, DateTimeUnit.MONTH)
val nextYear = zoned.plus(1, DateTimeUnit.YEAR)
// Periods
val period = MpDateTimePeriod.of(months = 2, days = 10, hours = 3)
val future = zoned.plus(period)
// Subtraction
val yesterday = zoned.minus(1, DateTimeUnit.DAY)
val past = zoned.minus(period)
// Duration between two zoned datetimes
val other = zoned.plus(3, DateTimeUnit.HOUR)
val diff = other - zoned // Duration Anchoring
Snap to calendar boundaries — all timezone-aware:
val zoned = MpZonedDateTime.of(
MpLocalDateTime.of(2025, 7, 18, 14, 35, 22),
MpTimezone.of("Europe/Berlin"),
)
// Time anchoring
zoned.atStartOfDay() // 2025-07-18T00:00 Europe/Berlin
zoned.atStartOfHour() // 2025-07-18T14:00
zoned.atStartOfMinute() // 2025-07-18T14:35:00
zoned.atStartOfSecond() // 2025-07-18T14:35:22
// Date anchoring
zoned.atStartOfMonth() // 2025-07-01T00:00
zoned.atStartOfYear() // 2025-01-01T00:00
// Day of week navigation
zoned.atStartOfNext(DayOfWeek.MONDAY)
zoned.atStartOfPrevious(DayOfWeek.FRIDAY)
// Set a specific time
zoned.atTime(MpLocalTime.of(9, 0)) // 2025-07-18T09:00 Converting
val zoned = MpZonedDateTime.of(
MpLocalDateTime.of(2025, 6, 15, 14, 0),
MpTimezone.of("Europe/Berlin"),
)
// To absolute time
val instant = zoned.toInstant() // MpInstant (UTC)
val millis = zoned.toEpochMillis()
val seconds = zoned.toEpochSeconds()
// To local types (drops timezone)
val date = zoned.toLocalDate() // MpLocalDate
val time = zoned.toLocalTime() // MpLocalTime
val dateTime = zoned.toLocalDateTime() // MpLocalDateTime
// ISO string
val iso = zoned.toIsoString()
// "2025-06-15T14:00:00.000+02:00[Europe/Berlin]" Formatting
MpZonedDateTime is the only type that can format timezone offsets:
val zoned = MpZonedDateTime.of(
MpLocalDateTime.of(2025, 6, 15, 14, 0),
MpTimezone.of("Europe/Berlin"),
)
// Pattern-based formatting
zoned.format("dd MMM yyyy HH:mm Z") // "15 Jun 2025 14:00 +02:00"
zoned.format("yyyy-MM-dd HH:mm:ss") // "2025-06-15 14:00:00"
// Convenience methods
zoned.formatDdMmmYyyy() // "15 Jun 2025"
zoned.formatHhMm() // "14:00"
zoned.formatDdMmmYyyyHhMm() // "15 Jun 2025 14:00"
zoned.formatDdMmmYyyyHhMmSs() // "15 Jun 2025 14:00:00" Creating ranges
// Range from a duration
val range = zoned.toRange(2.hours) // MpZonedDateTimeRange
// Range from a period
val monthRange = zoned.toRange(MpDateTimePeriod.of(months = 1)) JVM interop
// MpZonedDateTime -> java.time.ZonedDateTime
val javaZoned: java.time.ZonedDateTime = mpZoned.jvm
// java.time.ZonedDateTime -> MpZonedDateTime
val mpZoned: MpZonedDateTime = javaZoned.mp