| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | package legacydata | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"strconv" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | 	"github.com/vectordotdev/go-datemath" | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type DataTimeRange struct { | 
					
						
							|  |  |  | 	From string | 
					
						
							|  |  |  | 	To   string | 
					
						
							|  |  |  | 	Now  time.Time | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func NewDataTimeRange(from, to string) DataTimeRange { | 
					
						
							|  |  |  | 	return DataTimeRange{ | 
					
						
							|  |  |  | 		From: from, | 
					
						
							|  |  |  | 		To:   to, | 
					
						
							|  |  |  | 		Now:  time.Now(), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) GetFromAsMsEpoch() int64 { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	return tr.MustGetFrom().UnixNano() / int64(time.Millisecond) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) GetFromAsSecondsEpoch() int64 { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	return tr.GetFromAsMsEpoch() / 1000 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) GetFromAsTimeUTC() time.Time { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	return tr.MustGetFrom().UTC() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) GetToAsMsEpoch() int64 { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	return tr.MustGetTo().UnixNano() / int64(time.Millisecond) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) GetToAsSecondsEpoch() int64 { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	return tr.GetToAsMsEpoch() / 1000 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) GetToAsTimeUTC() time.Time { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	return tr.MustGetTo().UTC() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) MustGetFrom() time.Time { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	res, err := tr.ParseFrom() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return time.Unix(0, 0) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) MustGetTo() time.Time { | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	res, err := tr.ParseTo() | 
					
						
							|  |  |  | 	if err != nil { | 
					
						
							|  |  |  | 		return time.Unix(0, 0) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) ParseFrom(options ...TimeRangeOption) (time.Time, error) { | 
					
						
							|  |  |  | 	options = append(options, WithNow(tr.Now)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pt := newParsableTime(tr.From, options...) | 
					
						
							|  |  |  | 	return pt.Parse() | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func (tr DataTimeRange) ParseTo(options ...TimeRangeOption) (time.Time, error) { | 
					
						
							|  |  |  | 	options = append(options, WithRoundUp(), WithNow(tr.Now)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pt := newParsableTime(tr.To, options...) | 
					
						
							|  |  |  | 	return pt.Parse() | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func WithWeekstart(weekday time.Weekday) TimeRangeOption { | 
					
						
							|  |  |  | 	return func(timeRange parsableTime) parsableTime { | 
					
						
							|  |  |  | 		timeRange.weekstart = &weekday | 
					
						
							|  |  |  | 		return timeRange | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func WithLocation(loc *time.Location) TimeRangeOption { | 
					
						
							|  |  |  | 	return func(timeRange parsableTime) parsableTime { | 
					
						
							|  |  |  | 		timeRange.location = loc | 
					
						
							|  |  |  | 		return timeRange | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func WithFiscalStartMonth(month time.Month) TimeRangeOption { | 
					
						
							|  |  |  | 	return func(timeRange parsableTime) parsableTime { | 
					
						
							|  |  |  | 		timeRange.fiscalStartMonth = &month | 
					
						
							|  |  |  | 		return timeRange | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func WithNow(t time.Time) TimeRangeOption { | 
					
						
							|  |  |  | 	return func(timeRange parsableTime) parsableTime { | 
					
						
							|  |  |  | 		timeRange.now = t | 
					
						
							|  |  |  | 		return timeRange | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func WithRoundUp() TimeRangeOption { | 
					
						
							|  |  |  | 	return func(timeRange parsableTime) parsableTime { | 
					
						
							|  |  |  | 		timeRange.roundUp = true | 
					
						
							|  |  |  | 		return timeRange | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type parsableTime struct { | 
					
						
							|  |  |  | 	time             string | 
					
						
							|  |  |  | 	now              time.Time | 
					
						
							|  |  |  | 	location         *time.Location | 
					
						
							|  |  |  | 	weekstart        *time.Weekday | 
					
						
							|  |  |  | 	fiscalStartMonth *time.Month | 
					
						
							|  |  |  | 	roundUp          bool | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type TimeRangeOption func(timeRange parsableTime) parsableTime | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | func newParsableTime(t string, options ...TimeRangeOption) parsableTime { | 
					
						
							|  |  |  | 	p := parsableTime{ | 
					
						
							|  |  |  | 		time: t, | 
					
						
							|  |  |  | 		now:  time.Now(), | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | 	for _, opt := range options { | 
					
						
							|  |  |  | 		p = opt(p) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return p | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t parsableTime) Parse() (time.Time, error) { | 
					
						
							|  |  |  | 	// Milliseconds since Unix epoch. | 
					
						
							|  |  |  | 	if val, err := strconv.ParseInt(t.time, 10, 64); err == nil { | 
					
						
							|  |  |  | 		return time.UnixMilli(val), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Duration relative to current time. | 
					
						
							|  |  |  | 	if diff, err := time.ParseDuration("-" + t.time); err == nil { | 
					
						
							|  |  |  | 		return t.now.Add(diff), nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Advanced time string, mimics the frontend's datemath library. | 
					
						
							|  |  |  | 	return datemath.ParseAndEvaluate(t.time, t.datemathOptions()...) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (t parsableTime) datemathOptions() []func(*datemath.Options) { | 
					
						
							|  |  |  | 	options := []func(*datemath.Options){ | 
					
						
							|  |  |  | 		datemath.WithNow(t.now), | 
					
						
							|  |  |  | 		datemath.WithRoundUp(t.roundUp), | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if t.location != nil { | 
					
						
							|  |  |  | 		options = append(options, datemath.WithLocation(t.location)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if t.weekstart != nil { | 
					
						
							| 
									
										
										
										
											2022-03-26 19:57:29 +01:00
										 |  |  | 		options = append(options, datemath.WithStartOfWeek(*t.weekstart)) | 
					
						
							| 
									
										
										
										
											2022-01-04 13:56:34 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if t.fiscalStartMonth != nil { | 
					
						
							|  |  |  | 		loc := time.UTC | 
					
						
							|  |  |  | 		if t.location != nil { | 
					
						
							|  |  |  | 			loc = t.location | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		options = append(options, datemath.WithStartOfFiscalYear( | 
					
						
							|  |  |  | 			// Year doesn't matter, and Grafana only supports setting the | 
					
						
							|  |  |  | 			// month that the fiscal year starts in. | 
					
						
							|  |  |  | 			time.Date(0, *t.fiscalStartMonth, 1, 0, 0, 0, 0, loc), | 
					
						
							|  |  |  | 		)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return options | 
					
						
							| 
									
										
										
										
											2021-11-10 11:52:16 +01:00
										 |  |  | } |