almanac

    A date and time library for MoonBit

    date
    time
    datetime
    timezone
    duration
    iana-tzdata
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    11 hours ago
    Downloads
    1

    #almanac

    CI License: Apache-2.0 docs

    A date and time library for MoonBit: calendar and clock values, durations, IANA time zones, strftime-style formatting and parsing, and cron schedules.

    #Packages

    PackageImport aliasDescription
    connect0459/almanac@almanacRe-exports of the everyday types: Weekday, Month, NaiveDate, NaiveTime, NaiveDateTime, TimeDelta, TimeZone, Utc, FixedOffset, Location, DateTime, MappedLocalTime
    connect0459/almanac/core@coreCalendar and clock primitives with no time zone: NaiveDate, NaiveTime, NaiveDateTime, TimeDelta, Weekday, WeekdaySet, Month, IsoWeek, NaiveWeek
    connect0459/almanac/tz@tzTime zones: the TimeZone trait, Utc, FixedOffset, FixedZone, Location (embedded IANA tz database), PosixTz, DateTime[Tz], MappedLocalTime, and Local on the native backend only
    connect0459/almanac/format@formatstrftime-style formatting and parsing, RFC 3339, RFC 2822 and HTTP dates, plus the default-layout and duration parsers
    connect0459/almanac/cron@cronCron expressions: Cron::parse, then matches and next over a zoned DateTime[Tz]

    #Installation

    moon add connect0459/almanac

    Then declare the packages you need in your moon.pkg:

    import {
    "connect0459/almanac", // everyday types
    "connect0459/almanac/format", // formatting and parsing
    // "connect0459/almanac/core",
    // "connect0459/almanac/tz",
    // "connect0459/almanac/cron",
    }

    @core is also the default alias of the standard library's moonbitlang/core. The root package README shows how to import a package under another alias.

    #Usage

    Build a zoned value, format it, and ask a cron schedule for its next fire time:

    ///|
    test {
    let tokyo = @tz.Location::load("Asia/Tokyo").unwrap()
    let dt = @tz.DateTime::from_ymd_hms(2024, 3, 8, 9, 40, 0, tokyo)
    .single()
    .unwrap()
    assert_eq(@format.to_rfc3339(dt), "2024-03-08T09:40:00+09:00")
    let weekdays = @cron.Cron::parse("30 9 * * mon-fri")
    let next = weekdays.next(dt).unwrap()
    assert_eq(@format.to_rfc3339(next), "2024-03-11T09:30:00+09:00")
    }

    A local reading can fall in a DST gap or fold, so constructors from local components return a MappedLocalTime that you reduce with single, earliest or latest.

    #Compatibility

    • The library is tested on the js, wasm, wasm-gc and native backends. Local, the host's zone, exists on native only.
    • The embedded tz database is a snapshot; regenerate it with just gen-tzdata <zoneinfo dir>.
    • While the major version is 0, a minor release may contain breaking changes to the public API.

    #Documentation

    Each public package has a README.mbt.md with a key-types overview, usage examples and a full API reference. Start with core for the value types and tz for zones.

    #Contributing

    #License

    #connect0459/almanac (root package)

    A thin entry point over the packages below. Importing this package alone gives the everyday date, time, duration and zoned-datetime types; the functions and the rest of each API live in the packages that define them.

    PackageImportContents
    connect0459/almanac@almanacRe-exports of the everyday types (see below)
    connect0459/almanac/core@coreCalendar and clock primitives with no time zone: Weekday, WeekdaySet, Month, IsoWeek, NaiveDate, NaiveWeek, NaiveTime, TimeDelta, NaiveDateTime, RoundingError
    connect0459/almanac/tz@tzTime zones: the TimeZone trait, Utc, FixedOffset, FixedZone, Location (IANA tzdata), PosixTz, DateTime[Tz], MappedLocalTime, and on the native backend only, Local (the host's zone)
    connect0459/almanac/format@formatstrftime-style formatting and parsing, RFC 2822 and RFC 3339, plus the default-layout and duration parsers
    connect0459/almanac/cron@cronCron expressions: Cron::parse, then matches and next over a zoned DateTime[Tz]

    #Re-exported types

    Weekday, Month, NaiveDate, NaiveTime, NaiveDateTime and TimeDelta (from core), and TimeZone, Utc, FixedOffset, Location, DateTime and MappedLocalTime (from tz). They are aliases of the original types, so a value from @almanac is interchangeable with the same type from @core or @tz. Functions such as format_date_time and parse_rfc3339 are not re-exported; import connect0459/almanac/format for them.

    #Quick start

    ///|
    test {
    let date = @almanac.NaiveDate::from_ymd(2024, 3, 5).unwrap()
    let time = @almanac.NaiveTime::from_hms(9, 5, 7).unwrap()
    let naive = @almanac.NaiveDateTime::new(date, time)
    assert_eq(naive.to_string(), "2024-03-05 09:05:07")
    let tokyo = @almanac.FixedOffset::east(9 * 3600).unwrap()
    let dt = @almanac.DateTime::from_timestamp(0L, 0, tokyo).unwrap()
    assert_eq(dt.hour(), 9)
    }

    #Package aliases

    A package imported as connect0459/almanac/core is referred to as @core by default. That is also the name of the standard library's moonbitlang/core, so a project that mentions both can give this one its own alias in moon.pkg:

    import { "connect0459/almanac/core" @almanac_core, "connect0459/almanac/tz" @almanac_tz, }

    DateTime

    A datetime with an associated time zone.

    Internally stores the UTC naive datetime plus the zone value tz; the local (wall-clock) representation is derived on demand via tz.offset_from_utc, never stored redundantly.

    Identity is the UTC instant: Eq, Hash and Compare all ignore the zone value, so the same instant expressed in different zones is equal, hashes alike and compares as 0.

    FixedOffset

    A fixed UTC offset, constant year-round (no daylight saving).

    Represented as the signed number of seconds added to UTC to obtain the local time, within ±23:59:59 (±86399 seconds).

    Location

    A named IANA time zone, backed by parsed TZif (RFC 8536) data plus, when the file provides one, the POSIX TZ rule used to extrapolate offsets past the file's last recorded transition.

    Equality and hashing cover the parsed TZif data, the POSIX rule and name(), so a zone reached through an alias, or built without a name, is a different Location from the canonical one even when it resolves identically.

    MappedLocalTime

    The result of resolving a local (wall-clock) reading against a time zone: it can map to a single result, to two results (the "fold" at a backward DST transition, where the same wall-clock reading occurs twice), or to no result at all (the "gap" at a forward DST transition, where that wall-clock reading never occurs). T is usually a FixedOffset (see TimeZone::offset_from_local) or a DateTime[Tz] (see DateTime::from_local).

    Absent also reports components that do not form a valid reading at all (for example month 13) when a MappedLocalTime is built from components, as DateTime::from_ymd_hms and DateTime::with_* do; a caller that must tell the two apart validates the components first with NaiveDate::from_ymd and NaiveTime::from_hms.

    Month

    A month of the year.

    NaiveDate

    A proleptic Gregorian calendar date, without a time-of-day or time zone.

    Internally represented as a day count relative to the Unix epoch (1970-01-01 is day 0).

    NaiveDateTime

    A date and time of day, without a time zone.

    NaiveTime

    A time of day, without a date or time zone.

    Internally represented as whole seconds since midnight (0..=86399) plus a nanosecond component. The nanosecond component is normally 0..=999_999_999, but may reach 1_999_999_999 to represent a leap second at second() == 59 (see nanosecond).

    TimeDelta

    A signed duration, precise to the nanosecond.

    Internally represented as whole seconds plus a non-negative nanosecond remainder (0..=999_999_999); the sign of the duration is carried entirely by the seconds component.

    TimeZone

    A time zone: given a naive datetime, resolves it to a concrete UTC offset.

    The trait is readonly: code outside this package can use it as a bound but cannot implement it, so the zones are the ones this package provides (Utc, FixedOffset, FixedZone, Location, PosixTz and, on native, Local).

    Every NaiveDateTime argument is a UTC reading except the one taken by offset_from_local, which is a local (wall-clock) reading; the type does not distinguish them, so pass DateTime::naive_utc for the former and DateTime::naive_local for the latter.

    Utc

    The UTC time zone: a fixed offset of zero.

    Code outside this package cannot write Utc::{}; Utc::new() is the way to obtain the value.

    Weekday

    A day of the week.

    The variant order below has no calendar meaning by itself; use number_from_monday, number_from_sunday, num_days_from_monday, or num_days_from_sunday to get a day-of-week number in a specific counting convention.

    Source Files