wp
This commit is contained in:
172
mqe/period_calculator.go
Normal file
172
mqe/period_calculator.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package mqe
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"gordenko.dev/dima/qb/timeutil"
|
||||
)
|
||||
|
||||
type PeriodCalculatorOptions struct {
|
||||
GroupBy GroupBy
|
||||
LastDayOfMonth int
|
||||
FirstHourOfDay int
|
||||
Since time.Time
|
||||
Until time.Time
|
||||
}
|
||||
|
||||
func NewPeriodCalculator(opt PeriodCalculatorOptions) PeriodCalculator {
|
||||
switch opt.GroupBy {
|
||||
case ByHour, ByDay, ByMonth:
|
||||
// pass
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("bug: unknown groupBy %q", opt.GroupBy))
|
||||
}
|
||||
|
||||
s := PeriodCalculator{
|
||||
groupBy: opt.GroupBy,
|
||||
lastDayOfMonth: opt.LastDayOfMonth,
|
||||
firstHourOfDay: opt.FirstHourOfDay,
|
||||
}
|
||||
s.sincePeriod = s.TimeToPeriod(opt.Since)
|
||||
s.untilPeriod = s.TimeToPeriod(opt.Until)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
type PeriodCalculator struct {
|
||||
groupBy GroupBy
|
||||
lastDayOfMonth int
|
||||
firstHourOfDay int
|
||||
sincePeriod time.Time
|
||||
untilPeriod time.Time
|
||||
}
|
||||
|
||||
func (s PeriodCalculator) IsExtendedSincePeriod(period time.Time) bool {
|
||||
return period.Before(s.sincePeriod)
|
||||
}
|
||||
|
||||
func (s PeriodCalculator) IsExtendedUntilPeriod(period time.Time) bool {
|
||||
return period.After(s.untilPeriod)
|
||||
}
|
||||
|
||||
func (s PeriodCalculator) NextPeriod(period time.Time) time.Time {
|
||||
switch s.groupBy {
|
||||
case ByHour:
|
||||
return period.Add(time.Hour)
|
||||
|
||||
case ByDay:
|
||||
return period.AddDate(0, 0, 1)
|
||||
|
||||
case ByMonth:
|
||||
return period.AddDate(0, 1, 0)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("bug: unknown groupBy %q", s.groupBy))
|
||||
}
|
||||
}
|
||||
|
||||
func (s PeriodCalculator) IsPeriodCorrectEnds(period time.Time, lastMeasureTime int64) bool {
|
||||
// по умолчанию
|
||||
tm := timeutil.LastSecondInPeriod(period, string(s.groupBy))
|
||||
|
||||
switch s.groupBy {
|
||||
case ByDay:
|
||||
if s.firstHourOfDay > 0 {
|
||||
// Было 23:59, стало - 01:59
|
||||
tm = tm.Add(time.Duration(s.firstHourOfDay) * time.Hour)
|
||||
}
|
||||
|
||||
case ByMonth:
|
||||
if s.lastDayOfMonth == 0 {
|
||||
if s.firstHourOfDay > 0 {
|
||||
// Было 23:59, стало - 01:59
|
||||
tm = tm.Add(time.Duration(s.firstHourOfDay) * time.Hour)
|
||||
}
|
||||
} else {
|
||||
if s.firstHourOfDay > 0 {
|
||||
// last day 28, first hour 2 превращается в day 29 01:59:59
|
||||
tm = time.Date(
|
||||
tm.Year(),
|
||||
tm.Month(),
|
||||
s.lastDayOfMonth+1,
|
||||
s.firstHourOfDay-1,
|
||||
59,
|
||||
59,
|
||||
0,
|
||||
tm.Location(),
|
||||
)
|
||||
} else {
|
||||
// last day 23:59:59
|
||||
tm = time.Date(
|
||||
tm.Year(),
|
||||
tm.Month(),
|
||||
s.lastDayOfMonth,
|
||||
23,
|
||||
59,
|
||||
59,
|
||||
0,
|
||||
tm.Location(),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timestamp := tm.Add(-179 * time.Second).Unix()
|
||||
|
||||
if lastMeasureTime >= timestamp && lastMeasureTime <= tm.Unix() {
|
||||
return true
|
||||
}
|
||||
//fmt.Printf("Ends: lastMeasureTime=%s, timetsamp=%s\n", time.Unix(lastMeasureTime, 0), time.Unix(timestamp, 0))
|
||||
return false
|
||||
}
|
||||
|
||||
func (s PeriodCalculator) TimeToPeriod(tm time.Time) (period time.Time) {
|
||||
switch s.groupBy {
|
||||
case ByDay:
|
||||
if s.firstHourOfDay > 0 {
|
||||
if tm.Hour() < s.firstHourOfDay {
|
||||
tm = tm.AddDate(0, 0, -1)
|
||||
}
|
||||
}
|
||||
|
||||
case ByMonth:
|
||||
if s.lastDayOfMonth > 0 {
|
||||
if s.lastDayOfMonth > 28 {
|
||||
// На всякий случай добавляем защиту от дурака, ибо модификация даты
|
||||
// в запросе (+1 месяц) для 29, 30 и 31 чисел сделает запрос неверным.
|
||||
panic(fmt.Sprintf("LastDayOfMonth: %d, max allowed value is 28", s.lastDayOfMonth))
|
||||
}
|
||||
|
||||
if s.firstHourOfDay > 0 {
|
||||
if tm.Hour() >= s.firstHourOfDay {
|
||||
if tm.Day() > s.lastDayOfMonth {
|
||||
// add 1 month
|
||||
tm = tm.AddDate(0, 1, 0)
|
||||
}
|
||||
} else {
|
||||
// firstHourOfDay показывает что текущий день еще не наступил,
|
||||
// поэтому day - 1
|
||||
if (tm.Day() - 1) <= s.lastDayOfMonth {
|
||||
tm = tm.AddDate(0, 0, -1)
|
||||
} else {
|
||||
// - 1 day, + 1 month
|
||||
tm = tm.AddDate(0, 0, -1).AddDate(0, 1, 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if tm.Day() > s.lastDayOfMonth {
|
||||
tm = tm.AddDate(0, 1, 0)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if s.firstHourOfDay > 0 {
|
||||
if tm.Hour() < s.firstHourOfDay {
|
||||
tm = tm.AddDate(0, 0, -1)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return timeutil.FirstSecondInPeriod(tm, string(s.groupBy))
|
||||
}
|
||||
Reference in New Issue
Block a user