dateutil.go

 1// SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
 2//
 3// SPDX-License-Identifier: AGPL-3.0-or-later
 4
 5// Package dateutil provides natural language date parsing for lune commands.
 6package dateutil
 7
 8import (
 9	"fmt"
10	"time"
11
12	"git.secluded.site/go-lunatask"
13	"github.com/KarpelesLab/strtotime"
14)
15
16// Parse parses a natural language date string into a lunatask.Date.
17// Uses PHP strtotime syntax.
18//
19// Supported formats include:
20//   - Relative words: "today", "tomorrow", "yesterday"
21//   - Relative weekdays: "next Monday", "last Friday"
22//   - Relative periods: "next week", "last month", "next year"
23//   - Relative offsets: "+3 days", "-1 week", "3 days" (positive assumed)
24//   - Compound expressions: "next Friday +2 weeks"
25//   - Named dates: "March 5", "January 15 2024"
26//   - ISO format: "2024-01-15"
27//
28// Returns today's date if the input is empty.
29func Parse(input string) (lunatask.Date, error) {
30	if input == "" {
31		return lunatask.Today(), nil
32	}
33
34	t, err := strtotime.StrToTime(input)
35	if err != nil {
36		return lunatask.Date{}, fmt.Errorf("parsing date %q: %w", input, err)
37	}
38
39	return lunatask.NewDate(t), nil
40}
41
42// ParseInTZ parses a natural language date string with timezone awareness.
43// The timezone affects interpretation of relative dates.
44func ParseInTZ(input string, tz *time.Location) (lunatask.Date, error) {
45	if input == "" {
46		return lunatask.Today(), nil
47	}
48
49	t, err := strtotime.StrToTime(input, strtotime.InTZ(tz))
50	if err != nil {
51		return lunatask.Date{}, fmt.Errorf("parsing date %q: %w", input, err)
52	}
53
54	return lunatask.NewDate(t), nil
55}