Core library klyn.time

Date and Time

The klyn.time package separates an absolute instant from the timezone used to display its calendar components. Use DateTime for calendar values, Timestamp for an epoch-based instant, and Duration for elapsed time.

Local and UTC Clocks
import klyn.time

localNow = DateTime.now
utcNow = DateTime.nowUTC

print(localNow.toString("%Y-%m-%d %H:%M:%S %z"))
print(utcNow.toString("%Y-%m-%d %H:%M:%S %z"))
Property Exposed timezone Typical use
DateTime.now TimeZone.local User interfaces, local calendars, and operating-system time.
DateTime.nowUTC TimeZone.UTC Protocols, persistence, logs, and cross-system comparisons.
Timestamp.now None An absolute number of seconds since the Unix epoch.

DateTime.now and DateTime.nowUTC read the current clock separately, so values obtained by two successive calls may differ slightly. To expose one exact instant in two timezones, capture a Timestamp once.

import klyn.time

instant = Timestamp.now
localTime = DateTime(instant, TimeZone.local)
utcTime = DateTime(instant, TimeZone.UTC)

assert localTime.timestamp == utcTime.timestamp

Converting an epoch value or a Timestamp without a timezone also defaults to local display. Pass TimeZone.UTC whenever UTC calendar components are required.

import klyn.time

seconds = time()

localFromSeconds = DateTime(seconds)
utcFromSeconds = DateTime(seconds, TimeZone.UTC)

localFromTimestamp = Timestamp(seconds).toDateTime()
utcFromTimestamp = Timestamp(seconds).toDateTime(TimeZone.UTC)
Constructing Calendar Values
import klyn.time

# Components without an explicit timezone are local.
meeting = DateTime(year=2026, month=8, day=10, hour=9, minute=30)

# Pass UTC when the components describe a universal time.
deadline = DateTime(
    year=2026,
    month=8,
    day=10,
    hour=12,
    timeZone=TimeZone.UTC
)

# ISO 8601 offsets are preserved and converted to the correct instant.
remote = DateTime("2026-08-10T14:00:00+02:00")
Timezone controls interpretation

A timezone supplied with calendar components determines the corresponding absolute instant. A timezone supplied with a Timestamp only determines which calendar components are exposed for an instant that is already known.

TimeZone Values
import klyn.time

utc = TimeZone.UTC
local = TimeZone.local
india = TimeZone("IST", 5, 30)

print(local.offsetMinutes)
print(india)  # IST (UTC+5:30)

TimeZone.local reads the operating system's current UTC offset, including the current daylight-saving adjustment. It is a fixed-offset snapshot: acquire it again after a daylight-saving transition when the new offset matters.

Durations and Arithmetic
import klyn.time

startedAt = DateTime.nowUTC
expiresAt = startedAt + Duration(hours=2, minutes=30)
remaining = expiresAt - startedAt

assert remaining.totalSeconds == 9000.0

A Duration represents elapsed time rather than a calendar date. Date arithmetic preserves the timezone attached to the original DateTime.

Formatting
import klyn.time

now = DateTime.now

print(now.toString())
print(now.toString("%d/%m/%Y %H:%M:%S"))
print(now.toString("%Y-%m-%dT%H:%M:%S%z"))

The default representation is YYYY-MM-DD HH:MM:SS. Custom formats support date, time, locale, and timezone tokens such as %Y, %m, %d, %H, %M, %S, %z, and %Z.

Dates from Databases
Do not assume the server uses the client timezone

SQL types such as DATETIME may contain calendar fields without timezone information. A database session can also run in UTC while the application runs locally. Prefer timezone-aware SQL types or UTC values for persisted instants. For mapping tests, use a fixed date instead of comparing a server-local clock directly with DateTime.now.