fix: expose complete dataset period catalog

This commit is contained in:
2026-08-20 22:28:07 +03:30
parent d6de48fd15
commit 6523e90a03
8 changed files with 140 additions and 72 deletions

View File

@@ -119,76 +119,121 @@ func nextJalaliMonth(jy, jm int) (int, int) {
return jy, jm
}
func latestCompletePeriods(datasetStart, datasetMax time.Time, location *time.Location) []Period {
func completePeriods(datasetStart, datasetMax time.Time, location *time.Location) []Period {
if datasetMax.Before(datasetStart) {
return nil
}
localStart := datasetStart.In(location)
localMax := datasetMax.In(location)
datasetStartDay := time.Date(localStart.Year(), localStart.Month(), localStart.Day(), 0, 0, 0, 0, location)
dayStart := time.Date(localMax.Year(), localMax.Month(), localMax.Day(), 0, 0, 0, 0, location)
datasetEnd := dayStart.AddDate(0, 0, 1)
datasetEnd := time.Date(localMax.Year(), localMax.Month(), localMax.Day(), 0, 0, 0, 0, location).AddDate(0, 0, 1)
periods := make([]Period, 0)
for dayStart := datasetEnd.AddDate(0, 0, -1); !dayStart.Before(datasetStartDay); dayStart = dayStart.AddDate(0, 0, -1) {
jy, jm, jd := gregorianToJalali(dayStart.Year(), int(dayStart.Month()), dayStart.Day())
periods = append(periods, newPeriod(
"d-"+dayStart.Format(time.DateOnly),
"DAY",
dayStart,
dayStart.AddDate(0, 0, 1),
fmt.Sprintf("روز %s %s %s", persianNumber(jd), jalaliMonthNames[jm-1], persianNumber(jy)),
false,
))
}
weekEnd := datasetEnd
for weekEnd.Weekday() != time.Saturday {
weekEnd = weekEnd.AddDate(0, 0, -1)
}
weekStart := weekEnd.AddDate(0, 0, -7)
for weekStart := weekEnd.AddDate(0, 0, -7); !weekStart.Before(datasetStartDay); weekStart = weekStart.AddDate(0, 0, -7) {
weekEnd = weekStart.AddDate(0, 0, 7)
weekStartJY, weekStartJM, weekStartJD := gregorianToJalali(weekStart.Year(), int(weekStart.Month()), weekStart.Day())
weekLastDay := weekEnd.AddDate(0, 0, -1)
weekEndJY, weekEndJM, weekEndJD := gregorianToJalali(weekLastDay.Year(), int(weekLastDay.Month()), weekLastDay.Day())
periods = append(periods, newPeriod(
"w-"+weekStart.Format(time.DateOnly),
"WEEK",
weekStart,
weekEnd,
fmt.Sprintf(
"هفته %s %s %s تا %s %s %s",
persianNumber(weekStartJD), jalaliMonthNames[weekStartJM-1], persianNumber(weekStartJY),
persianNumber(weekEndJD), jalaliMonthNames[weekEndJM-1], persianNumber(weekEndJY),
),
false,
))
}
jy, jm, _ := gregorianToJalali(localMax.Year(), int(localMax.Month()), localMax.Day())
monthStart := jalaliDate(jy, jm, 1, location)
nextYear, nextMonth := nextJalaliMonth(jy, jm)
latestDay := datasetEnd.AddDate(0, 0, -1)
latestJY, latestJM, _ := gregorianToJalali(latestDay.Year(), int(latestDay.Month()), latestDay.Day())
monthYear, month := latestJY, latestJM
monthStart := jalaliDate(monthYear, month, 1, location)
nextYear, nextMonth := nextJalaliMonth(monthYear, month)
monthEnd := jalaliDate(nextYear, nextMonth, 1, location)
if monthEnd.After(datasetEnd) {
jy, jm = previousJalaliMonth(jy, jm)
monthStart = jalaliDate(jy, jm, 1, location)
nextYear, nextMonth = nextJalaliMonth(jy, jm)
monthYear, month = previousJalaliMonth(monthYear, month)
}
for isDefault := true; ; isDefault = false {
monthStart = jalaliDate(monthYear, month, 1, location)
nextYear, nextMonth = nextJalaliMonth(monthYear, month)
monthEnd = jalaliDate(nextYear, nextMonth, 1, location)
if monthStart.Before(datasetStartDay) {
break
}
periods = append(periods, newPeriod(
fmt.Sprintf("jm-%04d-%02d", monthYear, month),
"JALALI_MONTH",
monthStart,
monthEnd,
fmt.Sprintf("%s %s", jalaliMonthNames[month-1], persianNumber(monthYear)),
isDefault,
))
monthYear, month = previousJalaliMonth(monthYear, month)
}
seasonStartMonth := ((jm-1)/3)*3 + 1
seasonYear := jy
seasonStart := jalaliDate(seasonYear, seasonStartMonth, 1, location)
seasonEndYear, seasonEndMonth := seasonYear, seasonStartMonth+3
if seasonEndMonth > 12 {
seasonEndYear++
seasonEndMonth -= 12
}
seasonEnd := jalaliDate(seasonEndYear, seasonEndMonth, 1, location)
seasonYear := latestJY
seasonStartMonth := ((latestJM - 1) / 3 * 3) + 1
seasonStart, seasonEnd := seasonBoundaries(seasonYear, seasonStartMonth, location)
if seasonEnd.After(datasetEnd) {
seasonStartMonth -= 3
if seasonStartMonth < 1 {
seasonYear--
seasonStartMonth += 12
seasonYear, seasonStartMonth = previousPersianSeason(seasonYear, seasonStartMonth)
}
for {
seasonStart, seasonEnd = seasonBoundaries(seasonYear, seasonStartMonth, location)
if seasonStart.Before(datasetStartDay) {
break
}
seasonStart = jalaliDate(seasonYear, seasonStartMonth, 1, location)
seasonEndYear, seasonEndMonth = seasonYear, seasonStartMonth+3
if seasonEndMonth > 12 {
seasonEndYear++
seasonEndMonth -= 12
}
seasonEnd = jalaliDate(seasonEndYear, seasonEndMonth, 1, location)
periods = append(periods, newPeriod(
fmt.Sprintf("ps-%04d-%02d", seasonYear, seasonStartMonth),
"PERSIAN_SEASON",
seasonStart,
seasonEnd,
fmt.Sprintf("%s %s", persianSeasonNames[(seasonStartMonth-1)/3], persianNumber(seasonYear)),
false,
))
seasonYear, seasonStartMonth = previousPersianSeason(seasonYear, seasonStartMonth)
}
dayJY, dayJM, dayJD := gregorianToJalali(dayStart.Year(), int(dayStart.Month()), dayStart.Day())
weekEndJY, weekEndJM, weekEndJD := gregorianToJalali(weekEnd.AddDate(0, 0, -1).Year(), int(weekEnd.AddDate(0, 0, -1).Month()), weekEnd.AddDate(0, 0, -1).Day())
weekStartJY, weekStartJM, weekStartJD := gregorianToJalali(weekStart.Year(), int(weekStart.Month()), weekStart.Day())
periods := []Period{
newPeriod("d-"+dayStart.Format(time.DateOnly), "DAY", dayStart, datasetEnd,
fmt.Sprintf("روز %s %s %s", persianNumber(dayJD), jalaliMonthNames[dayJM-1], persianNumber(dayJY)), false),
newPeriod("w-"+weekStart.Format(time.DateOnly), "WEEK", weekStart, weekEnd,
fmt.Sprintf("هفته %s %s تا %s %s", persianNumber(weekStartJD), jalaliMonthNames[weekStartJM-1], persianNumber(weekEndJD), jalaliMonthNames[weekEndJM-1]), false),
newPeriod(fmt.Sprintf("jm-%04d-%02d", jy, jm), "JALALI_MONTH", monthStart, monthEnd,
fmt.Sprintf("%s %s", jalaliMonthNames[jm-1], persianNumber(jy)), true),
newPeriod(fmt.Sprintf("ps-%04d-%02d", seasonYear, seasonStartMonth), "PERSIAN_SEASON", seasonStart, seasonEnd,
fmt.Sprintf("%s %s", persianSeasonNames[(seasonStartMonth-1)/3], persianNumber(seasonYear)), false),
}
for index := range periods {
periods[index].IsComplete = !periods[index].LocalStartAt.Before(datasetStartDay)
}
_ = weekEndJY
_ = weekStartJY
return periods
}
func seasonBoundaries(year, startMonth int, location *time.Location) (time.Time, time.Time) {
endYear, endMonth := year, startMonth+3
if endMonth > 12 {
endYear++
endMonth -= 12
}
return jalaliDate(year, startMonth, 1, location), jalaliDate(endYear, endMonth, 1, location)
}
func previousPersianSeason(year, startMonth int) (int, int) {
startMonth -= 3
if startMonth < 1 {
return year - 1, startMonth + 12
}
return year, startMonth
}
func newPeriod(id, kind string, localStart, localEnd time.Time, label string, isDefault bool) Period {
return Period{
PeriodID: id, PeriodType: kind, StartAt: localStart.UTC(), EndAt: localEnd.UTC(),