package main
import (
"fmt"
"time"
)
// GetDatesBetween generates all dates between startDateStr and endDateStr inclusive.
// Accepts dates in "YYYY-MM-DD" format and returns a slice of date strings.
func GetDatesBetween(startDateStr, endDateStr string) ([]string, error) {
// Go uses a specific reference time for layouts: Mon Jan 2 15:04:05 MST 2006
const layout = "2006-01-02"
// 1. Parse input strings into time.Time objects
startDate, err := time.Parse(layout, startDateStr)
if err != nil {
return nil, fmt.Errorf("invalid start date format (use YYYY-MM-DD): %w", err)
}
endDate, err := time.Parse(layout, endDateStr)
if err != nil {
return nil, fmt.Errorf("invalid end date format (use YYYY-MM-DD): %w", err)
}
// Normalize both dates to midnight UTC to strip any time-of-day components
startDate = time.Date(startDate.Year(), startDate.Month(), startDate.Day(), 0, 0, 0, 0, time.UTC)
endDate = time.Date(endDate.Year(), endDate.Month(), endDate.Day(), 0, 0, 0, 0, time.UTC)
// 2. Validate that the date range is logically sound
if startDate.After(endDate) {
return nil, fmt.Errorf("start date cannot be after the end date")
}
var dates []string
current := startDate
// 3. Iterate day-by-day safely
for !current.After(endDate) {
dates = append(dates, current.Format(layout))
// AddDate(years, months, days) handles leap years, month-end rollovers,
// and daylight saving shifts seamlessly.
current = current.AddDate(0, 0, 1)
}
return dates, nil
}
func main() {
// Example usage spanning a month boundary and leap year
start := "2026-02-26"
end := "2026-03-02"
dates, err := GetDatesBetween(start, end)
if err != nil {
fmt.Println("Error:", err)
return
}
fmt.Printf("Dates between %s and %s:\n", start, end)
for _, d := range dates {
fmt.Println(d)
}
}
/*
run:
Dates between 2026-02-26 and 2026-03-02:
2026-02-26
2026-02-27
2026-02-28
2026-03-01
2026-03-02
*/