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.
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)
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")
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.
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.
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.
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.
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.