moondate
API · Autumn

The reference.

Every public type, function and constant, grouped by package. Generated from pkg.generated.mbti and the source's own documentation comments.

@moondate

import { "moonbitstack/moondate" }

Types

Date

struct
pub(all) struct Date

A day on the proleptic Gregorian calendar.

Proleptic means the Gregorian rules are applied before 1582 as well, which is what every interchange format in reach assumes and what makes arithmetic over the whole range uniform.

  • year : Int32
  • month : Int32
  • day : Int32
Methods
pub fn Date::new(Int32, Int32, Int32) -> Self raise Refused

A date, checked against the calendar.

year Int32month Int32day Int32
pub fn Date::days(Self) -> Int32

Days since 1970-01-01, negative before it.

Howard Hinnant's days_from_civil: shift the year to start in March so the leap day falls at the end, then the month lengths follow a pattern with no table.

pub fn Date::diff(Self, Self) -> Span

One date less another, as a span of whole days.

other Date
pub fn Date::isocalendar(Self) -> (Int32, Int32, Int32)

The ISO 8601 week date: the year the week belongs to, the week number, and the day of the week with Monday as 1.

The year is not always the calendar year. A week belongs to the year that holds its Thursday, so the first of January can fall in the last week of the year before — which is exactly the case a hand-rolled week number gets wrong.

pub fn Date::isoweekday(Self) -> Int32

The day of the week with Monday as 1 and Sunday as 7.

[Date::weekday] counts from Sunday as 0, which is what cron and C's tm_wday use; ISO counts from Monday as 1. Both are here because both are asked for, and picking one silently is how an off-by-one gets into a schedule.

pub fn Date::of_days(Int32) -> Self

The date n days after 1970-01-01, the inverse of [Date::days].

n Int32
pub fn Date::of_isocalendar(Int32, Int32, Int32) -> Self raise Refused

The date named by an ISO week date.

year Int32week Int32weekday Int32
pub fn Date::of_ordinal(Int32) -> Self

The date with that ordinal.

n Int32
pub fn Date::ordinal(Self) -> Int32

Days since 0001-01-01, that day being 1.

The proleptic Gregorian ordinal, which is what makes two dates subtractable without going through an epoch.

pub fn Date::plus_days(Self, Int32) -> Self

The date n days later, or earlier when n is negative.

n Int32
pub fn Date::plus_months(Self, Int32) -> Self

The date n months later, clamped to the end of the month it lands in.

The thirty-first of January plus one month is the twenty-eighth or twenty-ninth of February, because there is no thirty-first. Every calendar library makes this choice and they all make the same one.

n Int32
pub fn Date::replace(Self, year? : Int32, month? : Int32, day? : Int32) -> Self raise Refused

The same date with some parts replaced.

year? Int32month? Int32day? Int32
pub fn Date::weekday(Self) -> Int32

The day of the week, Sunday being 0.

1970-01-01 was a Thursday, which is where the 4 comes from.

pub fn Date::yearday(Self) -> Int32

The day of the year, the first of January being 1.

Trait methods
pub fn Date::compare(Self, Self) -> Int32

Three-way ordering from Compare: less, equal or greater.

pub fn Date::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Date::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Date::op_ge(Self, Self) -> Bool

self >= other, from Compare.

pub fn Date::op_gt(Self, Self) -> Bool

self > other, from Compare.

pub fn Date::op_le(Self, Self) -> Bool

self <= other, from Compare.

pub fn Date::op_lt(Self, Self) -> Bool

self < other, from Compare.

pub fn Date::output(Self, &Logger) -> Unit

Writes the text form to a logger, from Show.

pub fn Date::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

pub fn Date::to_string(Self) -> String

The text form, as a String, from Show.

Moment

enum
pub(all) enum Moment

A point in time, in one of the four shapes a format names.

TOML 1.0.0 has exactly these four and gives them these meanings; RFC 3339 defines only Zoned. The distinction is not decoration: Plain is a wall clock, which is what an alarm or an opening time is, and turning it into an instant needs a zone nobody has supplied.

  • Zoned(date~ : Date, time~ : Time, zone~ : Zone)
  • Plain(date~ : Date, time~ : Time)
  • Day(date~ : Date)
  • Clock(time~ : Time)
Methods
pub fn Moment::asn1_text(Self) -> String raise Refused

A moment as an ASN.1 GeneralizedTime, which is the form DER uses from 2050 on and the one that needs no windowing rule to read back.

pub fn Moment::astimezone(Self, Zone) -> Self?

The same instant read in another zone.

None for the three shapes that are not instants: moving a wall clock to another zone would be inventing the zone it was written in.

zone Zone
pub fn Moment::combine(Date, Time, zone? : Zone) -> Self

A date and a time as one wall-clock moment.

zone makes it an instant instead; leaving it off keeps it a wall clock, which is what an opening time or an alarm is.

date Datetime Timezone? Zone
pub fn Moment::ctime(Self) -> String

The moment in C's ctime form: Sun Nov 6 08:49:37 1994.

The day is space-padded rather than zero-padded, which is the one thing that distinguishes this form from every other.

pub fn Moment::date(Self) -> Date?

The date out of a moment.

None for a bare time, which has no date to give.

pub fn Moment::diff(Self, Self) -> Span?

One moment less another, for the two shapes that can be subtracted.

None when they are not comparable: an instant and a wall clock differ by an amount that depends on a zone nobody supplied, and a bare time and a bare date are not the same kind of thing.

other Moment
pub fn Moment::epoch(Self) -> Int64?

Seconds since 1970-01-01T00:00:00Z, for a moment that names one.

None for the three shapes that do not: a wall clock, a bare date and a bare time are not instants until someone supplies the zone they are read in.

pub fn Moment::http_text(Self) -> String raise Refused

A moment as an HTTP date (RFC 9110 §5.6.7): Sun, 06 Nov 1994 08:49:37 GMT.

This is the one form a Date header may take. The two obsolete forms are read by [http] and never written, which is what §5.6.7 asks for.

pub fn Moment::isocalendar(Self) -> (Int32, Int32, Int32)?

The ISO week date of the moment's date.

pub fn Moment::isoformat(Self, sep? : Char, fraction? : Int32, offset? : Bool) -> String

The moment as ISO 8601 text, which is what [Show] writes.

sep is the character between the date and the time, T by default; any character works, and a space is what a log line wants.

fraction is the number of fractional-second digits, 0 to 9, truncated. Left out, it writes as many as the value needs and none for a whole second, which is Temporal's auto.

offset writes the zone the moment carries, Z for UTC and ±HH:MM for an offset; false leaves the zone off, which is Temporal's offset: "never".

sep~ Char = …fraction? Int32offset~ Bool = …
pub fn Moment::of_epoch(Int64, nano? : Int32, zone? : Zone) -> Self

The moment seconds after 1970-01-01T00:00:00Z, the inverse of [Moment::timestamp].

Reading the clock is not this package's job — it has no I/O — so a caller that wants "now" passes what its own clock said.

seconds Int64nano~ Int32 = …zone~ Zone = …
pub fn Moment::ordinal(Self) -> Int32?

Days since 0001-01-01 of the moment's date.

pub fn Moment::plus(Self, Span) -> Self

The moment span later.

A bare date moves by whole days and a bare time wraps within the day, because that is all each of them can mean.

span Span
pub fn Moment::replace(Self, year? : Int32, month? : Int32, day? : Int32, hour? : Int32, minute? : Int32, second? : Int32, nano? : Int32, zone? : Zone) -> Self raise Refused

The same moment with some parts replaced.

year? Int32month? Int32day? Int32hour? Int32minute? Int32second? Int32nano? Int32zone? Zone
pub fn Moment::time(Self) -> Time

The time out of a moment.

Midnight for a bare date, which is the time it names.

pub fn Moment::timestamp(Self) -> Double?

Seconds since the epoch as a Double, fraction included.

pub fn Moment::timetuple(Self) -> (Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32, Int32)

The nine fields of a broken-down time, in the usual order: year, month, day, hour, minute, second, weekday counted from Monday as 0, day of the year, and whether daylight saving applies — always -1 here, because that needs a zone database this package does not carry.

pub fn Moment::to_iso_string(Self) -> String

The Date.prototype.toISOString shape: always the UTC instant, always three fractional digits, always a trailing Z.

A moment with no zone has no instant of its own, so its wall clock is taken as UTC — the same convention [Moment::strftime] uses for a bare time.

pub fn Moment::to_utc_string(Self) -> String raise Refused

The Date.prototype.toUTCString shape: Tue, 22 Sep 2026 05:30:05 GMT.

This is the HTTP date form [Moment::http_text] already writes, on the UTC instant, which is exactly what ECMAScript's toUTCString produces.

pub fn Moment::utcoffset(Self) -> Span?

How far the moment's clock is from UTC.

pub fn Moment::weekday(Self) -> Int32?

The day of the week of the moment's date, Sunday being 0.

pub fn Moment::zone(Self) -> Zone?

The zone a moment carries, or None when it carries none.

Trait methods
pub fn Moment::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Moment::layout(Self, StringView) -> String
pub fn Moment::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Moment::output(Self, &Logger) -> Unit

Writes the text form to a logger, from Show.

pub fn Moment::pattern(Self, StringView) -> String
pub fn Moment::strftime(Self, StringView) -> String
pub fn Moment::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

pub fn Moment::to_string(Self) -> String

The text form, as a String, from Show.

Span

struct
pub(all) struct Span

A length of time, to the nanosecond, with no calendar attached.

A span is not a number of months: a month is not a fixed length, so adding one is a calendar operation (Date::plus_months) rather than arithmetic.

  • nanos : Int64
Methods
pub fn Span::new(days? : Int64, hours? : Int64, minutes? : Int64, seconds? : Int64, millis? : Int64, micros? : Int64, nanos? : Int64) -> Self

A span made of the usual parts: days, hours, minutes, seconds and fractions.

days~ Int64 = …hours~ Int64 = …minutes~ Int64 = …seconds~ Int64 = …millis~ Int64 = …micros~ Int64 = …nanos~ Int64 = …
pub fn Span::abs(Self) -> Self

The span with its sign dropped.

pub fn Span::add(Self, Self) -> Self

Two spans added.

other Span
pub fn Span::neg(Self) -> Self

The span negated.

pub fn Span::of(Self, Int64) -> Self

A span of n of these.

unit Spann Int64
pub fn Span::parts(Self) -> (Int32, Int32, Int32)

The whole days in a span, and the seconds and nanoseconds left over — the three fields a duration is usually stored in.

pub fn Span::seconds(Self) -> Int64

The span as whole seconds, rounded towards zero.

pub fn Span::sub(Self, Self) -> Self

One span less another.

other Span
pub fn Span::total_seconds(Self) -> Double

The span as seconds, fraction included.

Trait methods
pub fn Span::compare(Self, Self) -> Int32

Three-way ordering from Compare: less, equal or greater.

pub fn Span::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Span::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Span::op_ge(Self, Self) -> Bool

self >= other, from Compare.

pub fn Span::op_gt(Self, Self) -> Bool

self > other, from Compare.

pub fn Span::op_le(Self, Self) -> Bool

self <= other, from Compare.

pub fn Span::op_lt(Self, Self) -> Bool

self < other, from Compare.

pub fn Span::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

Time

struct
pub(all) struct Time

A time on a twenty-four hour clock, to the nanosecond.

A second of 60 is allowed: RFC 3339 §5.6 permits it for a leap second, and a timestamp that records one is a real timestamp that a reader should not throw away.

  • hour : Int32
  • minute : Int32
  • second : Int32
  • nano : Int32
Methods
pub fn Time::new(Int32, Int32, second? : Int32, nano? : Int32) -> Self raise Refused

A time, checked against the clock.

hour Int32minute Int32second~ Int32 = …nano~ Int32 = …
pub fn Time::nanos(Self) -> Int64

Nanoseconds since midnight.

pub fn Time::replace(Self, hour? : Int32, minute? : Int32, second? : Int32, nano? : Int32) -> Self raise Refused

The same time with some parts replaced.

hour? Int32minute? Int32second? Int32nano? Int32
Trait methods
pub fn Time::compare(Self, Self) -> Int32

Three-way ordering from Compare: less, equal or greater.

pub fn Time::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Time::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Time::op_ge(Self, Self) -> Bool

self >= other, from Compare.

pub fn Time::op_gt(Self, Self) -> Bool

self > other, from Compare.

pub fn Time::op_le(Self, Self) -> Bool

self <= other, from Compare.

pub fn Time::op_lt(Self, Self) -> Bool

self < other, from Compare.

pub fn Time::output(Self, &Logger) -> Unit

Writes the text form to a logger, from Show.

pub fn Time::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

pub fn Time::to_string(Self) -> String

The text form, as a String, from Show.

Zone

enum
pub(all) enum Zone

How far the clock is from UTC, in minutes east of it.

Utc and Offset(0) are both midnight-at-Greenwich, but they are not the same thing to write down: RFC 3339 §4.3 gives -00:00 to a timestamp whose offset is unknown, and Z to one that is genuinely UTC.

  • Utc
  • Offset(Int32)
Trait methods
pub fn Zone::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Zone::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Zone::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

Errors

Refused

suberror
pub(all) suberror Refused

Why an expression was refused.

  • Range(field~ : String, got~ : Int32, low~ : Int32, high~ : Int32)
  • Malformed(String)
  • Truncated(String)
Trait methods
pub fn Refused::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Refused::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Refused::output(Self, &Logger) -> Unit

Writes the text form to a logger, from Show.

pub fn Refused::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

pub fn Refused::to_string(Self) -> String

The text form, as a String, from Show.

Functions

pub fn asn1(StringView) -> Moment raise Refused

An ASN.1 UTCTime or GeneralizedTime (ITU-T X.680 §47), as DER writes them.

This is how a certificate spells its validity. DER requires the Z and whole seconds; UTCTime's two-digit year is read as RFC 5280 §4.1.2.5.1 says — 49 and under are 2000s, 50 and over are 1900s, which is not the same rule HTTP uses.

src StringView
pub fn http(StringView) -> Moment raise Refused

An HTTP date read (RFC 9110 §5.6.7).

The preferred IMF-fixdate, and the two obsolete forms a recipient must still accept: RFC 850's Sunday, 06-Nov-94 08:49:37 GMT and asctime's Sun Nov 6 08:49:37 1994. A two-digit year is read as RFC 6265 §5.1.1 says: 69 and under are 2000s, 70 and over are 1900s.

src StringView
pub fn leap(Int32) -> Bool

Whether year has a twenty-ninth of February.

Every fourth year, except every hundredth, except every four-hundredth — the rule that makes the calendar year 365.2425 days long.

year Int32
pub fn length(Int32, Int32) -> Int32

How many days month has in year.

year Int32month Int32
pub fn of_isoformat(StringView) -> Moment raise Refused

A moment read from ISO 8601 text, which is what [parse] does.

src StringView
pub fn parse(StringView) -> Moment raise Refused

An expression, in the five-field form crontab(5) defines or the six-field form that puts seconds in front.

┌───────────── second (0-59, six-field form only)
│ ┌───────────── minute (0-59)
│ │ ┌───────────── hour (0-23)
│ │ │ ┌───────────── day of month (1-31)
│ │ │ │ ┌───────────── month (1-12 or JAN-DEC)
│ │ │ │ │ ┌───────────── day of week (0-7 or SUN-SAT, both 0 and 7 being Sunday)
* * * * * *

Each field takes *, a number, a range a-b, a step */n or a-b/n, and a comma-separated list of those. ? reads as *, which is how a scheduler spells the day field it is not using.

The shorthands @yearly, @annually, @monthly, @weekly, @daily, @midnight and @hourly are the ones crontab(5) lists. @reboot is not here: it names an event rather than a time, and this package answers when something fires, not why.

expr StringView
pub fn parse_layout(StringView, StringView) -> Moment raise Refused
pub fn parse_pattern(StringView, StringView) -> Moment raise Refused
pub fn strptime(StringView, StringView) -> Moment raise Refused

Constants

pub const ANSIC : String = "Mon Jan _2 15:04:05 2006"
pub const DateOnly : String = "2006-01-02"
pub const DateTime : String = "2006-01-02 15:04:05"
pub const Kitchen : String = "3:04PM"
pub const RFC1123 : String = "Mon, 02 Jan 2006 15:04:05 MST"
pub const RFC1123Z : String = "Mon, 02 Jan 2006 15:04:05 -0700"
pub const RFC3339 : String = "2006-01-02T15:04:05Z07:00"
pub const RFC3339Nano : String = "2006-01-02T15:04:05.999999999Z07:00"
pub const RFC822 : String = "02 Jan 06 15:04 MST"
pub const RFC822Z : String = "02 Jan 06 15:04 -0700"
pub const RFC850 : String = "Monday, 02-Jan-06 15:04:05 MST"
pub const RubyDate : String = "Mon Jan 02 15:04:05 -0700 2006"
pub const Stamp : String = "Jan _2 15:04:05"
pub const StampMicro : String = "Jan _2 15:04:05.000000"
pub const StampMilli : String = "Jan _2 15:04:05.000"
pub const StampNano : String = "Jan _2 15:04:05.000000000"
pub const TimeOnly : String = "15:04:05"
pub const UnixDate : String = "Mon Jan _2 15:04:05 MST 2006"
pub let day : Span
pub let end_of_day : Time
pub let hour : Span
pub let max_date : Date
pub let max_year : Int32
pub let midnight : Time

Midnight, and the last representable moment of a day.

pub let min_date : Date

The earliest and latest dates this calendar writes with a four-digit year.

They are 1-01-01 and 9999-12-31, which is as far as a four-digit year writes; the arithmetic here works outside that range, so these are a convention for writing rather than a limit on computing.

pub let min_year : Int32

The years this calendar spans.

pub let minute : Span
pub let nanosecond : Span

Nanoseconds in a second, a minute, an hour and a day.

pub let resolution : Span

The smallest difference two moments can have.

A nanosecond rather than a microsecond: the clock here is finer, which is what a protocol timestamp and a benchmark both want.

pub let second : Span

@cron

import { "moonbitstack/moondate/cron" }

Types

Cron

struct
pub(all) struct Cron

A parsed expression: which values of each field it fires on.

Each field is a bit set, so asking whether a moment matches is six bit tests rather than a search. star_day and star_week are kept because the two fields interact — see [Cron::matches].

  • seconds : Int64
  • minutes : Int64
  • hours : Int32
  • days : Int32
  • months : Int32
  • weekdays : Int32
  • star_day : Bool
  • star_week : Bool
Methods
pub fn Cron::matches(Self, @moondate.Moment) -> Bool

Whether m is a moment this expression fires on.

The day-of-month and day-of-week fields are or-ed when both are restricted, which is Vixie cron's rule and surprises everyone once: 0 0 13 * 5 is the thirteenth *or* any Friday, not Friday the thirteenth. When one of them is * they are and-ed, which is why 0 0 13 * * is only the thirteenth.

m @moondate.Moment
pub fn Cron::next(Self, @moondate.Moment) -> @moondate.Moment?

The first moment strictly after m that this expression fires on.

None when it never does. An expression can name a day that does not exist — 0 0 30 2 * is the thirtieth of February — so the search is bounded at four years, which is past any leap-year cycle a real schedule turns on.

m @moondate.Moment
Trait methods
pub fn Cron::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Cron::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Cron::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

Errors

Refused

suberror
pub(all) suberror Refused

Why an expression was refused.

  • Fields(got~ : Int32)
  • Range(field~ : String, got~ : Int32, low~ : Int32, high~ : Int32)
  • Malformed(String)
Trait methods
pub fn Refused::equal(Self, Self) -> Bool

Structural equality from Eq.

pub fn Refused::not_equal(Self, Self) -> Bool

The negation of equal, from Eq.

pub fn Refused::output(Self, &Logger) -> Unit

Writes the text form to a logger, from Show.

pub fn Refused::to_repr(Self) -> @debug.Repr

The debug representation, from Debug.

pub fn Refused::to_string(Self) -> String

The text form, as a String, from Show.

Functions

pub fn parse(StringView) -> Cron raise Refused

An expression, in the five-field form crontab(5) defines or the six-field form that puts seconds in front.

┌───────────── second (0-59, six-field form only)
│ ┌───────────── minute (0-59)
│ │ ┌───────────── hour (0-23)
│ │ │ ┌───────────── day of month (1-31)
│ │ │ │ ┌───────────── month (1-12 or JAN-DEC)
│ │ │ │ │ ┌───────────── day of week (0-7 or SUN-SAT, both 0 and 7 being Sunday)
* * * * * *

Each field takes *, a number, a range a-b, a step */n or a-b/n, and a comma-separated list of those. ? reads as *, which is how a scheduler spells the day field it is not using.

The shorthands @yearly, @annually, @monthly, @weekly, @daily, @midnight and @hourly are the ones crontab(5) lists. @reboot is not here: it names an event rather than a time, and this package answers when something fires, not why.

expr StringView