summaryrefslogtreecommitdiff
path: root/internal/reports/daterange.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/reports/daterange.go')
-rw-r--r--internal/reports/daterange.go162
1 files changed, 152 insertions, 10 deletions
diff --git a/internal/reports/daterange.go b/internal/reports/daterange.go
index 3478615..adeb48b 100644
--- a/internal/reports/daterange.go
+++ b/internal/reports/daterange.go
@@ -2,6 +2,8 @@ package reports
import (
"fmt"
+ "regexp"
+ "strconv"
"strings"
"time"
)
@@ -11,6 +13,33 @@ type DateRange struct {
End time.Time
}
+var monthNames = map[string]time.Month{
+ "january": time.January,
+ "february": time.February,
+ "march": time.March,
+ "april": time.April,
+ "may": time.May,
+ "june": time.June,
+ "july": time.July,
+ "august": time.August,
+ "september": time.September,
+ "october": time.October,
+ "november": time.November,
+ "december": time.December,
+ "jan": time.January,
+ "feb": time.February,
+ "mar": time.March,
+ "apr": time.April,
+ "jun": time.June,
+ "jul": time.July,
+ "aug": time.August,
+ "sep": time.September,
+ "sept": time.September,
+ "oct": time.October,
+ "nov": time.November,
+ "dec": time.December,
+}
+
func ParseDateRange(dateStr string) (DateRange, error) {
dateStr = strings.TrimSpace(dateStr)
now := time.Now().UTC()
@@ -20,8 +49,22 @@ func ParseDateRange(dateStr string) (DateRange, error) {
switch lowerDateStr {
case "last week":
return getLastWeek(now), nil
+ case "this week":
+ return getThisWeek(now), nil
case "last month":
return getLastMonth(now), nil
+ case "this month":
+ return getThisMonth(now), nil
+ }
+
+ // Check for month name patterns (case-insensitive)
+ if dateRange, err := parseMonthName(dateStr, now); err == nil {
+ return dateRange, nil
+ }
+
+ // Check for "month year" format
+ if dateRange, err := parseMonthYear(dateStr); err == nil {
+ return dateRange, nil
}
// Check for custom date range format: "YYYY-MM-DD to YYYY-MM-DD"
@@ -29,7 +72,7 @@ func ParseDateRange(dateStr string) (DateRange, error) {
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)
+ return DateRange{}, fmt.Errorf("unsupported date range: %s (supported: 'this week', 'this month', 'last week', 'last month', month names like 'february', 'month year' like 'july 2023', or 'YYYY-MM-DD to YYYY-MM-DD')", dateStr)
}
func parseCustomDateRange(dateStr string) (DateRange, error) {
@@ -61,7 +104,7 @@ func parseCustomDateRange(dateStr string) (DateRange, error) {
// 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)
@@ -77,14 +120,14 @@ func getLastWeek(now time.Time) DateRange {
if weekday == 0 { // Sunday
weekday = 7
}
-
+
// Start of current week
- currentWeekStart := now.AddDate(0, 0, -(weekday-1)).Truncate(24 * time.Hour)
-
+ 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,
@@ -94,15 +137,114 @@ func getLastWeek(now time.Time) DateRange {
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,
}
-} \ No newline at end of file
+}
+
+func getThisWeek(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
+ weekStart := now.AddDate(0, 0, -(weekday - 1)).Truncate(24 * time.Hour)
+
+ // End of current week (Sunday 23:59:59.999999999)
+ weekEnd := weekStart.AddDate(0, 0, 7).Add(-time.Nanosecond)
+
+ return DateRange{
+ Start: weekStart,
+ End: weekEnd,
+ }
+}
+
+func getThisMonth(now time.Time) DateRange {
+ // Start of current month
+ monthStart := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.UTC)
+
+ // End of current month (last nanosecond)
+ nextMonthStart := monthStart.AddDate(0, 1, 0)
+ monthEnd := nextMonthStart.Add(-time.Nanosecond)
+
+ return DateRange{
+ Start: monthStart,
+ End: monthEnd,
+ }
+}
+
+func parseMonthName(dateStr string, now time.Time) (DateRange, error) {
+ lowerDateStr := strings.ToLower(dateStr)
+ month, exists := monthNames[lowerDateStr]
+ if !exists {
+ return DateRange{}, fmt.Errorf("not a valid month name")
+ }
+
+ // Find the most recent occurrence of this month
+ var targetYear int
+ currentMonth := now.Month()
+
+ if month == currentMonth {
+ // If it's the same month as now, use this year
+ targetYear = now.Year()
+ } else if month < currentMonth {
+ // If the month has already passed this year, use this year
+ targetYear = now.Year()
+ } else {
+ // If the month hasn't come yet this year, use last year
+ targetYear = now.Year() - 1
+ }
+
+ return getMonthRange(targetYear, month), nil
+}
+
+func parseMonthYear(dateStr string) (DateRange, error) {
+ // Match patterns like "july 2023", "feb 2022", etc.
+ re := regexp.MustCompile(`^(\w+)\s+(\d{4})$`)
+ matches := re.FindStringSubmatch(strings.ToLower(dateStr))
+ if len(matches) != 3 {
+ return DateRange{}, fmt.Errorf("invalid month year format")
+ }
+
+ monthStr := matches[1]
+ yearStr := matches[2]
+
+ // Parse year
+ year, err := strconv.Atoi(yearStr)
+ if err != nil {
+ return DateRange{}, fmt.Errorf("invalid year: %s", yearStr)
+ }
+
+ // Parse month
+ month, exists := monthNames[monthStr]
+ if !exists {
+ return DateRange{}, fmt.Errorf("invalid month name: %s", monthStr)
+ }
+
+ return getMonthRange(year, month), nil
+}
+
+func getMonthRange(year int, month time.Month) DateRange {
+ // Start of the specified month
+ monthStart := time.Date(year, month, 1, 0, 0, 0, 0, time.UTC)
+
+ // End of the specified month (last nanosecond)
+ nextMonthStart := monthStart.AddDate(0, 1, 0)
+ monthEnd := nextMonthStart.Add(-time.Nanosecond)
+
+ return DateRange{
+ Start: monthStart,
+ End: monthEnd,
+ }
+}
+