package timex import ( "fmt" "time" ) type Interval struct { intervalDuration time.Duration periodType PeriodType } type PeriodType string const ( PeriodHourly PeriodType = "hourly" PeriodDaily PeriodType = "daily" PeriodMonthly PeriodType = "monthly" PeriodYearly PeriodType = "yearly" ) func NewInterval(intervalDuration time.Duration, periodType PeriodType) *Interval { return &Interval{ intervalDuration: intervalDuration, periodType: periodType, } } func (i *Interval) GetCurrent() int { return i.GetIntervalForTime(time.Now().UTC()) } func (i *Interval) GetIntervalForTime(t time.Time) int { t = t.UTC() periodStart := i.getPeriodStart(t) elapsed := t.Sub(periodStart) intervalIndex := int(elapsed / i.intervalDuration) // S'assurer que l'index n'est pas négatif if intervalIndex < 0 { intervalIndex = 0 } return intervalIndex } func (i *Interval) getPeriodStart(t time.Time) time.Time { t = t.UTC() switch i.periodType { case PeriodHourly: return time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), 0, 0, 0, time.UTC) case PeriodDaily: return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.UTC) case PeriodMonthly: return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, time.UTC) case PeriodYearly: return time.Date(t.Year(), 1, 1, 0, 0, 0, 0, time.UTC) default: return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, time.UTC) } } func (i *Interval) GetTotalIntervalsInPeriod(referenceTime time.Time) int { referenceTime = referenceTime.UTC() periodStart := i.getPeriodStart(referenceTime) periodEnd := i.getPeriodEnd(referenceTime) totalDuration := periodEnd.Sub(periodStart) return int(totalDuration / i.intervalDuration) } func (i *Interval) getPeriodEnd(t time.Time) time.Time { t = t.UTC() switch i.periodType { case PeriodHourly: return time.Date(t.Year(), t.Month(), t.Day(), t.Hour()+1, 0, 0, 0, time.UTC) case PeriodDaily: return time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, time.UTC) case PeriodMonthly: return time.Date(t.Year(), t.Month()+1, 1, 0, 0, 0, 0, time.UTC) case PeriodYearly: return time.Date(t.Year()+1, 1, 1, 0, 0, 0, 0, time.UTC) default: return time.Date(t.Year(), t.Month(), t.Day()+1, 0, 0, 0, 0, time.UTC) } } func (i *Interval) GetIntervalBounds(index int, referenceTime time.Time) (time.Time, time.Time) { referenceTime = referenceTime.UTC() periodStart := i.getPeriodStart(referenceTime) intervalStart := periodStart.Add(time.Duration(index) * i.intervalDuration) intervalEnd := intervalStart.Add(i.intervalDuration) return intervalStart.UTC(), intervalEnd.UTC() } func (i *Interval) GetIntervalInfo(t time.Time) IntervalInfo { t = t.UTC() index := i.GetIntervalForTime(t) start, end := i.GetIntervalBounds(index, t) return IntervalInfo{ Index: index, Start: start, End: end, Duration: i.intervalDuration, Reference: t, } } type IntervalInfo struct { Index int Start time.Time End time.Time Duration time.Duration Reference time.Time } func (ii IntervalInfo) String() string { return fmt.Sprintf("Interval %d: %s -> %s (Duration: %v)", ii.Index, ii.Start.Format("2006-01-02 15:04:05"), ii.End.Format("2006-01-02 15:04:05"), ii.Duration) }