Add household week and local-time utilities
Independent review Codex gpt-6-sol high: APPROVED (0 findings)
CI / ci (pull_request) Successful in 1m27s
CI / ci (push) Successful in 1m24s

internal/household provides Today, WeekStart, WeekDays, WeekLabel,
PeriodKey and LocalTime, all in the household IANA zone and never the
process zone. Weeks are ISO Monday to Sunday; calendar arithmetic runs
on UTC midnights so DST never shifts dates.

LocalTime reads a skipped or repeated wall time with the UTC offset in
effect before the transition: a spring-forward gap moves forward by its
length, and a fall-back repeat is its first occurrence.

store gains LocalDateOf and LocalDate.Date so household builds dates
without reparsing, and LocalDate.Value rejects years outside 0000-9999.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 09:51:08 -04:00
co-authored by Claude Opus 5.5
parent 6d5c14f778
commit 1cc8bf99cd
4 changed files with 482 additions and 1 deletions
+16 -1
View File
@@ -86,6 +86,17 @@ func ParseLocalDate(s string) (LocalDate, error) {
return LocalDate{t.Year(), t.Month(), t.Day()}, nil
}
// LocalDateOf returns the calendar date of t in t's own location.
func LocalDateOf(t time.Time) LocalDate {
y, m, d := t.Date()
return LocalDate{y, m, d}
}
// Date returns the year, month and day of d.
func (d LocalDate) Date() (year int, month time.Month, day int) {
return d.year, d.month, d.day
}
// String returns the YYYY-MM-DD form.
func (d LocalDate) String() string {
return fmt.Sprintf("%04d-%02d-%02d", d.year, int(d.month), d.day)
@@ -96,11 +107,15 @@ func (d LocalDate) IsZero() bool {
return d == LocalDate{}
}
// Value implements driver.Valuer. The zero LocalDate is an error.
// Value implements driver.Valuer. The zero LocalDate is an error, as is a
// year outside 0000–9999, which the four-digit stored form cannot represent.
func (d LocalDate) Value() (driver.Value, error) {
if d.IsZero() {
return nil, errors.New("store: zero LocalDate")
}
if d.year < 0 || d.year > 9999 {
return nil, fmt.Errorf("store: LocalDate year %d outside 0000-9999", d.year)
}
return d.String(), nil
}