package engine import ( "fmt" "strings" "time" ) // ParseDate parses date strings with smart interpretation // Supports: ISO dates, relative (tomorrow, today), weekdays (sun, monday) func ParseDate(s string) (time.Time, error) { s = strings.ToLower(strings.TrimSpace(s)) now := timeNow() // Try ISO format first if t, err := time.Parse("2006-01-02", s); err == nil { return t, nil } // Relative dates switch s { case "today": return time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, now.Location()), nil case "tomorrow": tomorrow := now.AddDate(0, 0, 1) return time.Date(tomorrow.Year(), tomorrow.Month(), tomorrow.Day(), 0, 0, 0, 0, tomorrow.Location()), nil case "yesterday": yesterday := now.AddDate(0, 0, -1) return time.Date(yesterday.Year(), yesterday.Month(), yesterday.Day(), 0, 0, 0, 0, yesterday.Location()), nil } // Weekday names weekdays := map[string]time.Weekday{ "sun": time.Sunday, "sunday": time.Sunday, "mon": time.Monday, "monday": time.Monday, "tue": time.Tuesday, "tuesday": time.Tuesday, "wed": time.Wednesday, "wednesday": time.Wednesday, "thu": time.Thursday, "thursday": time.Thursday, "fri": time.Friday, "friday": time.Friday, "sat": time.Saturday, "saturday": time.Saturday, } if targetWeekday, ok := weekdays[s]; ok { return nextWeekday(now, targetWeekday), nil } return time.Time{}, fmt.Errorf("unable to parse date: %s", s) } // nextWeekday returns the next occurrence of the target weekday // Smart logic: if today is Thursday and target is Sunday, returns this Sunday // If today is Sunday and target is Sunday, returns next Sunday func nextWeekday(from time.Time, target time.Weekday) time.Time { // Calculate days until target daysUntil := int(target - from.Weekday()) if daysUntil <= 0 { daysUntil += 7 // Next week } next := from.AddDate(0, 0, daysUntil) return time.Date(next.Year(), next.Month(), next.Day(), 0, 0, 0, 0, next.Location()) }