Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

zepoch

zepoch logo

简体中文

zepoch is an explicit time library for Zig 0.16. It separates absolute instants, wall time, fixed-offset views, and monotonic clocks into distinct types. External capabilities enter through Zig 0.16 std.Io and std.Tz; the library never guesses a time zone, reads global process state, or hides allocation.

Time model

Type Meaning Supported operations
Instant POSIX/Unix instant that ignores leap seconds Timestamp conversion, exact duration arithmetic, ordering
LocalDateTime Zone-free wall time Gregorian validation, weekday, ordinal day, calendar arithmetic
OffsetDateTime Instant with an explicit fixed UTC offset RFC 3339 and fixed-offset calendar views
MonotonicInstant awake or boot monotonic clock reading Timeout and elapsed-time measurement
TzifZone IANA transition rules from caller-provided TZif data Instant conversion and DST gap/fold resolution

There are no implicit conversions between these types. Instant stores no display offset, LocalDateTime assumes no system time zone, and MonotonicInstant cannot be formatted as calendar time. Operations return new values instead of mutating inputs.

Design rules

  • Instant.now(io) and MonotonicInstant.now(io, clock) receive std.Io explicitly.
  • TzifZone.parse(allocator, identifier, bytes) receives the allocator, IANA identifier, and TZif bytes explicitly. The caller decides how to obtain them.
  • Formatting writes to a caller-provided *std.Io.Writer without allocating a string.
  • Invalid dates, offsets, precision loss, and arithmetic overflow return errors.
  • Month arithmetic requires .reject, .clamp, or .preserve_end_of_month.
  • LocalDateTime.addDays moves a calendar date while preserving wall-clock fields; it does not mean Duration.fromHours(24) across DST.
  • TZif designations are display data only. Lookups require regional IANA identifiers such as Asia/Shanghai, America/New_York, or Etc/UTC.

POSIX time and leap seconds

Instant.now(io) reads std.Io.Clock.now(.real, io).nanoseconds and normalizes it into i64 unix_seconds plus a u32 nanosecond in [0, 1_000_000_000). Floor division and a non-negative remainder are used for negative values, so -1 ns becomes -1 s + 999_999_999 ns.

Like Zig's std.Io.Clock.real, Instant uses the Unix epoch and ignores leap seconds. 2016-12-31T23:59:60Z returns error.InvalidSecond instead of being normalized. TzifZone.leapSecondRecords() exposes TZif leap records but does not apply them to POSIX time. TAI, GPS, UT1, and astronomical applications need a separate time scale and an authoritative leap-second table.

Calendar and TZif boundaries

LocalDateTime uses the proleptic Gregorian calendar with ISO 8601 year numbering, including year zero. It does not model the 1582 Julian-to-Gregorian cutover.

TzifZone delegates RFC 8536 TZif parsing to the Zig standard library and does not maintain a tzdb. To avoid silently ignoring future rules in the TZif POSIX footer, results are available only between adjacent transitions:

  • .unique: one absolute instant;
  • .ambiguous: two instants in an autumn fold;
  • .nonexistent: a local-time gap caused by DST or a date-line change;
  • .outside_coverage: the transition table cannot prove the result.

Precision and formatting

Instant uses i64 seconds plus u32 nanoseconds. Duration uses signed i128 nanoseconds, and timestamps never use floating point. There is no fromDays; write Duration.fromHours(24) when an exact 24-hour duration is intended.

parse.rfc3339 accepts a four-digit year, T, seconds, an optional 1-9 digit fraction, and Z or ±HH:MM. Invalid dates are never normalized. -00:00 returns error.UnknownLocalOffset. Formatting a historical offset with second precision returns error.OffsetPrecisionLoss because RFC 3339 cannot represent it.

The library does not provide translated month or weekday names, 12-hour clocks, or locale-specific week rules. Those policies belong in a caller-selected locale layer.

Installation

zig fetch --save https://github.com/GuangYiL/zepoch/archive/refs/heads/main.tar.gz
const dependency = build_system.dependency("zepoch", .{
    .target = target,
    .optimize = optimize,
});
executable.root_module.addImport("zepoch", dependency.module("zepoch"));

Usage

const std = @import("std");
const zepoch = @import("zepoch");

pub fn main(init: std.process.Init) !void {
    const now = try zepoch.Instant.now(init.io);
    const utc_plus_eight = zepoch.OffsetDateTime{
        .instant = now,
        .offset = try zepoch.UtcOffset.fromSeconds(8 * 3_600),
    };

    var buffer: [64]u8 = undefined;
    var writer = std.Io.Writer.fixed(&buffer);
    try zepoch.format.writeRfc3339(utc_plus_eight, &writer);
}

The caller obtains and caches TZif data for named time zones:

var zone = try zepoch.TzifZone.parse(
    allocator,
    "America/New_York",
    tzif_bytes,
);
defer zone.deinit();

switch (try zone.resolveLocal(wall_time)) {
    .unique => |instant| use(instant),
    .ambiguous => |pair| chooseExplicitly(pair.earlier, pair.later),
    .nonexistent => return error.NonexistentLocalTime,
    .outside_coverage => return error.TimeZoneDataOutOfRange,
}

Development and commits

zig fmt --check build.zig build.zig.zon src examples
zig build test
zig build
zig build run

Tests live at the bottom of their source files. Commit messages follow Conventional Commits 1.0.0:

<type>[optional scope]: <English description> / <Chinese description>

Commit bodies are also bilingual and start after one blank line.

License

Licensed under the MIT License (Expat), the same license used by Zig.

About

Explicit date and time library for Zig with POSIX instants, monotonic clocks, RFC 3339, Gregorian arithmetic, and TZif time zones.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Used by

Contributors

Languages