isnow.go(docs) tsvsheet manual

Language tour

Every isnow concept has one name. This page is the working vocabulary; the normative definitions live in SPECIFICATION.md.

The membership test

An isnow holds at an instant when every field constraint is satisfied. That test — Holds(at) — is the language’s defining operation; “next occurrence” and “previous occurrence” are derived from it. An occurrence is any instant at which the isnow holds.

go
p, _ := isnow.Parse("M,W,F noon")
p.Holds(time.Now())          // is it now?
p.Next(time.Now())           // the next occurrence

The seven fields

An isnow is seven fields in three groups:

text
Y/m/d   w   H:M:S      [ >|>= spec ]   [ <|<= spec ]
└ date group ┘ │ └ time group ┘
          bare group
FieldGroupSeparator
year, month, daydate group/
weekdaybare group
hour, minute, secondtime group:

Groups are separated by whitespace, ., or _, so an isnow is a single shell-safe token: Y/m/d.w.H:M:SY/m/d_w_H:M:SY/m/d w H:M:S.

The field algebra

One uniform algebra applies to every field:

ConstructNameExample
*wildcard*
12exact valuehour 12
M,W,FsetMon, Wed, Fri
!1exclusionnot the 1st
8-12span (inclusive, wraps on cyclic fields)hours 8–12
-1from-end valuethe last day of the month
-2w1dunit compoundthe last 2 weeks and 1 day
+[15]step from an anchor:0+[15] = every 15 minutes
-[1]step from the endTh-[1] = the last Thursday
Monday+[3]weekday-occurrence stepthe 3rd Monday of the month
M-F-[1]weekday-span BYSETPOSthe last business day of the month

Symbols are case-insensitive, minimal-unique names: weekdays Su M Tu W Th F Sa (plus runs MWF, SS, TT), and the times noon/midday (12:00:00) and midnight (00:00:00). m is always Monday.

Intervals

An interval+[N<unit>] with a duration unit s, mn, h, or d — is a true periodic recurrence (“every N units”) written as a bare group of its own. Unlike a field step, which stays inside one field’s cycle, an interval crosses field boundaries: +[90mn] spans hours, +[25h] spans days, +[10d] spans months.

An interval anchors hierarchically to the civil calendar: the stride picks the smallest civil container that holds it — minute → hour → day → week → month → year — and repeats within each container, re-aligning at its boundary. The anchor moves with its unit rather than drifting from a fixed epoch, so intervals stay aligned to the wall clock and are DST-sane.

IntervalContainerHolds at
+[90mn]day00:00, 01:30, 03:00, … (re-aligns each midnight)
+[2h]day00, 02, … 22
+[3d]weekSunday, Wednesday, Saturday
+[25h]weekSun 00:00, Mon 01:00, … Sat 06:00
+[10d]monththe 1st, 11th, 21st, 31st
+[40d]yearday-of-year 1, 41, 81, …

The week container starts on Sunday (weekday 1). An interval ANDs with the rest of the pattern: M-F +[30mn] >=9 <=17 is every 30 minutes on weekdays inside business hours.

Pattern exclusions

A pattern exclusion! <spec>, the ! set off from its sub-spec by a separator — removes every instant where the sub-spec holds. Chain them for a holiday list:

isnow
M-F ! 12/25 ! 1/1       every weekday except Christmas and New Year

The separator is load-bearing: !12/25 (no space) is a field exclusion (the 25th of any month except December), while ! 12/25 (set off by a separator) is a pattern exclusion (skip December 25 entirely).

Canonical form and the shorthand ladder

The canonical form is the fully-qualified Y/m/d w H:M:S expansion of any isnow. The shorthand ladder lets a short isnow stand for its canonical form by position:

ShorthandCanonical
6*/*/* * 06:00:00
M noon*/*/* Monday 12:00:00
/1 18*/*/01 * 18:00:00
Su :0,30*/*/* Sunday *:00,30:00

Produce it with isnow canon <isnow> or Pattern.Canonical().

Bounds

A since bound (>, >=) and an until bound (<, <=) each carry a sub-spec and define a window:

isnow
12 <9/1                 every day at noon until September 1
::+[9] >=6 <=18         every 9 seconds from 06:00 to 18:00

v0.1.0 note: steps are field-local in every context; a step counting continuously across a bounded window is a planned future extension. Bounds themselves are fully honored.