dtrexp

package module
v1.0.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 5 Imported by: 0

README

dtrexp-go

dtrexp-go

Go implementation of DTRExp (read: "DTR Expression") — a compact string expression for date-time ranges and recurrence, evaluated by coverage rather than enumeration.

T0900:1800 E1:5          Mon–Fri, 09:00–18:00
E7#-1 M4                 last Sunday of April, every year
20200106/10D             every 10 days from 2020-01-06 (cron can't say this)
M!7                      every month except July

Scope: parsing, validation and coverage evaluation (the spec's core interface). Rendering, description and RRULE export are out of scope; the reference implementation has them.

Install

go get github.com/DTRExp/dtrexp-go

Go 1.26+, stdlib only (time for IANA zones).

Usage

import (
    "time"
    dtrexp "github.com/DTRExp/dtrexp-go"
)

dtr, err := dtrexp.Parse("T0900:1800 E1:5")    // business hours, Mon–Fri
if err != nil { /* a positioned ParseError */ }

ok, err := dtr.Covers(time.Now(), "Europe/Berlin")
// —> true on a weekday, 09:00–18:00 Berlin local time
// The zone is an evaluation parameter, never part of the expression;
// empty string or "UTC" means UTC.

// Preloaded zone; cannot fail:
berlin, _ := time.LoadLocation("Europe/Berlin")
ok = dtr.CoversIn(time.Now(), berlin)

Note that you parse once (at write/config time) and evaluate many; Expression values are immutable after Parse and safe for concurrent use. Covers is a single calendar-field extraction followed by integer comparisons; no occurrence iteration.

Errors and Warnings

Both carry a position; the 0-based character offset into the source:

_, err := dtrexp.Parse("Y*/3")     // anchorless stride — a syntax error
var pe dtrexp.ParseError
errors.As(err, &pe)                // pe.Pos points at the offending character

res := dtrexp.Validate("D30 M2")   // never returns a Go error
res.Valid                          // true — it parses
res.Warnings                       // [{Pos: 0, Message: "unsatisfiable …"}] — no February has 30 days
  • Parse(s) returns the expression or a ParseError (Pos int, Msg string).
  • Validate(s) never fails; typo-shaped input comes back as data. Returns a ValidationResult with Valid bool, Errors (parsing stops at the first syntax error, so at most one) and Warnings.
  • Warnings are the spec's §9.1 unsatisfiability lint: expressions that parse but can never match. dtr.Warnings() and Validate(s).Warnings carry the same content.

Conformance & Quality

  • The test suite is driven by the shared vectors.json from the spec repo (draft 2.8): every coverage, rejection, warning and quiet vector, including the calendar traps (Feb 29 across 2000/2024/2100, W53 existence, DST gap/overlap in Europe/Berlin). See VECTORS.md for how the suite works.
  • 100% statement coverage; mutation-tested with gremlins. Commands and survivor justifications: TESTING.md.
  • Zero dependencies.
  • dtrexp (spec) — the DTRExp specification (grammar, semantics, conformance vectors) this package implements.
  • dtrexp-js — the reference implementation; adds intersect, next, describe, toRRule and canonicalization.
  • dtrexp-py · dtrexp-swift · dtrexp-rs · dtrexp-java — the other ports; same core interface.
  • dtrexp-wasm — the Rust core compiled to WebAssembly for JS hosts.

License

© 2026, Onur Yıldırım. MIT License.

Documentation

Overview

Package dtrexp parses and evaluates DTRExp (Date-Time Range & Recurrence Expression) strings, per DTRExp draft 2.8.

A DTRExp denotes a — possibly infinite — set of time intervals. It is not enumerated into dates; it is evaluated for coverage: "is this instant inside the set?". This package implements parsing/validation (with the spec's §9.1 warnings) and the covers check. Rendering, description and RRULE export are out of scope.

The evaluation model is time-zone agnostic: an expression carries no zone; the zone is a parameter of Covers (default UTC).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Expression

type Expression struct {
	// contains filtered or unexported fields
}

Expression is a parsed DTRExp. It is one or more union branches; an instant is covered iff any branch covers it. Expression values are immutable after Parse and safe for concurrent use.

func Parse

func Parse(s string) (*Expression, error)

Parse parses a DTRExp string. It returns an error for any syntactically or statically invalid expression; the error is always a ParseError carrying the offending character offset. A successfully parsed expression may still carry warnings (see Warnings) for statically unsatisfiable constructs that are legal but never match.

func (*Expression) Covers

func (e *Expression) Covers(t time.Time, tz string) (bool, error)

Covers reports whether the absolute instant t falls inside the set denoted by the expression, evaluated in IANA time zone tz. An empty tz means UTC. It returns an error only if tz is not a loadable IANA zone.

func (*Expression) CoversIn

func (e *Expression) CoversIn(t time.Time, loc *time.Location) bool

CoversIn is Covers with an already-resolved *time.Location (nil means UTC).

func (*Expression) Source

func (e *Expression) Source() string

Source returns the original expression string.

func (*Expression) Warnings

func (e *Expression) Warnings() []Warning

Warnings returns the §9.1 warnings collected during parsing — statically unsatisfiable expressions or branches that are legal but can never match. The slice is empty for a clean expression.

type ParseError

type ParseError struct {
	Pos int
	Msg string
}

ParseError is a positioned syntax error: what went wrong and where. Pos is the 0-based character offset of the offending input in the source string (DTR expressions are ASCII, so byte and character offsets coincide). Every error Parse returns for invalid source is a ParseError.

func (ParseError) Error

func (e ParseError) Error() string

Error implements the error interface, rendering as "dtrexp: <msg> (at <pos>)".

type ValidationResult

type ValidationResult struct {
	Valid    bool
	Errors   []ParseError
	Warnings []Warning
}

ValidationResult is the outcome of Validate: whether the source parses, the positioned syntax errors when it does not, and the §9.1 warnings when it does. An expression can be valid and still warned.

func Validate

func Validate(s string) ValidationResult

Validate checks a DTRExp string without failing: typo-shaped input comes back as data, never as a Go error. Errors is empty when Valid; parsing stops at the first syntax error, so it holds at most one entry. Warnings carries the same content as Warnings on the parsed expression.

type Warning

type Warning struct {
	Pos     int
	Message string
}

Warning is a positioned §9.1 warning: a construct that is legal but can never match. Pos is the 0-based character offset of the offending component in the source string, or -1 where no position is derivable from the parsed expression.

func (Warning) String

func (w Warning) String() string

String returns the warning message (without the position).

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL