package reports import ( "fmt" "strings" "time" ) type DateRange struct { Start time.Time End time.Time } func ParseDateRange(dateStr string) (DateRange, error) { dateStr = strings.TrimSpace(dateStr) now := time.Now().UTC() // Check for predefined ranges (case-insensitive) lowerDateStr := strings.ToLower(dateStr) switch lowerDateStr { case "last week": return getLastWeek(now), nil case "last month": return getLastMonth(now), nil } // Check for custom date range format: "YYYY-MM-DD to YYYY-MM-DD" if strings.Contains(dateStr, " to ") { return parseCustomDateRange(dateStr) } return DateRange{}, fmt.Errorf("unsupported date range: %s (supported: 'last week', 'last month', or 'YYYY-MM-DD to YYYY-MM-DD')", dateStr) } func parseCustomDateRange(dateStr string) (DateRange, error) { parts := strings.Split(dateStr, " to ") if len(parts) != 2 { return DateRange{}, fmt.Errorf("invalid date range format: expected 'YYYY-MM-DD to YYYY-MM-DD'") } startStr := strings.TrimSpace(parts[0]) endStr := strings.TrimSpace(parts[1]) // Parse start date startDate, err := time.Parse("2006-01-02", startStr) if err != nil { return DateRange{}, fmt.Errorf("invalid start date '%s': expected YYYY-MM-DD format", startStr) } // Parse end date endDate, err := time.Parse("2006-01-02", endStr) if err != nil { return DateRange{}, fmt.Errorf("invalid end date '%s': expected YYYY-MM-DD format", endStr) } // Validate that start date is before or equal to end date if startDate.After(endDate) { return DateRange{}, fmt.Errorf("start date '%s' must be before or equal to end date '%s'", startStr, endStr) } // Convert to UTC and set times appropriately // Start date: beginning of day (00:00:00) startUTC := time.Date(startDate.Year(), startDate.Month(), startDate.Day(), 0, 0, 0, 0, time.UTC) // End date: end of day (23:59:59.999999999) endUTC := time.Date(endDate.Year(), endDate.Month(), endDate.Day(), 23, 59, 59, 999999999, time.UTC) return DateRange{ Start: startUTC, End: endUTC, }, nil } func getLastWeek(now time.Time) DateRange { // Find the start of current week (Monday) weekday := int(now.Weekday()) if weekday == 0 { // Sunday weekday = 7 } // Start of current week currentWeekStart := now.AddDate(0, 0, -(weekday-1)).Truncate(24 * time.Hour) // Last week is the week before current week lastWeekStart := currentWeekStart.AddDate(0, 0, -7) lastWeekEnd := currentWeekStart.Add(-time.Nanosecond) return DateRange{ Start: lastWeekStart, End: lastWeekEnd, } } func getLastMonth(now time.Time) DateRange { // Start of current month currentMonthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC) // Last month start lastMonthStart := currentMonthStart.AddDate(0, -1, 0) // Last month end (last nanosecond of last month) lastMonthEnd := currentMonthStart.Add(-time.Nanosecond) return DateRange{ Start: lastMonthStart, End: lastMonthEnd, } }