Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: deployment window #28

Merged
merged 9 commits into from
Nov 13, 2024
Merged
2 changes: 1 addition & 1 deletion chart-sync/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions common-lib/timeRangeLib/constant.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ const (
ToBeforeFrom ErrorMessage = "Invalid value of hourMinuteFrom or hourMinuteTo for same day ,hourMinuteFrom >hourMinuteTo"
BothLessThanZeroAndFromGreaterThanTo ErrorMessage = "invalid value of DayFrom or DayTo,DayFrom and DayTo is less than zero and dayFrom > dayTo"
DayFromOrToNotValid ErrorMessage = "invalid value of dayFrom or dayTo"
InvalidHourMinuteForWeeklyAndDaily ErrorMessage = "HourMinuteFrom should be less than HourMinuteTo in daily or weekly Frequency"
)
9 changes: 4 additions & 5 deletions common-lib/timeRangeLib/fixedWindowUtil_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ func TestGetWindowForFixedTime(t *testing.T) {
// Define the time zones with GMT offsets
locBangui, _ := time.LoadLocation("Africa/Bangui") // GMT+01:00
locParamaribo, _ := time.LoadLocation("America/Paramaribo") // GMT-03:00
zeroTime := time.Time{}
// Define test cases with different time zones
testCases := []struct {
name string
Expand All @@ -39,8 +38,8 @@ func TestGetWindowForFixedTime(t *testing.T) {
{
name: "Target time in Africa/Bangui (GMT+01:00), after the range (Outside)",
targetTime: time.Date(2024, 10, 14, 19, 30, 0, 0, locBangui), // 7:30 AM GMT+01 (outside)
expectedStart: time.Time{}, // zeroTime
expectedEnd: time.Time{}, // zeroTime
expectedStart: time.Date(2024, 10, 14, 10, 0, 0, 0, locBangui), // zeroTime
expectedEnd: time.Date(2024, 10, 14, 18, 0, 0, 0, locBangui), // zeroTime
},

{
Expand All @@ -58,8 +57,8 @@ func TestGetWindowForFixedTime(t *testing.T) {
{
name: "Target time in America/Paramaribo (GMT-03:00), after the range (Outside)",
targetTime: time.Date(2024, 10, 14, 14, 30, 0, 0, locParamaribo), // 2:30 PM GMT-03 (outside)
expectedStart: zeroTime, // zeroTime
expectedEnd: zeroTime, // zeroTime
expectedStart: time.Date(2024, 10, 14, 6, 0, 0, 0, locParamaribo), // zeroTime
expectedEnd: time.Date(2024, 10, 14, 14, 0, 0, 0, locParamaribo),
},
}

Expand Down
13 changes: 12 additions & 1 deletion common-lib/timeRangeLib/helperUtils.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,20 @@ func constructDateTime(hourMinute string, days int) time.Time {
func isToBeforeFrom(from, to string) bool {
parseHourFrom, _ := time.Parse(hourMinuteFormat, from)
parsedHourTo, _ := time.Parse(hourMinuteFormat, to)
return parsedHourTo.Before(parseHourFrom)
return parsedHourTo.Before(parseHourFrom) || parsedHourTo.Equal(parseHourFrom)
}

func isTimeInBetween(timeCurrent, periodStart, periodEnd time.Time) bool {
return (timeCurrent.After(periodStart) && timeCurrent.Before(periodEnd)) || timeCurrent.Equal(periodStart)
}

// Validate the date from and date to handle same day limits
func isDateFromBeforeTo(timeFrom, timeTo time.Time) bool {
yearFrom, monthFrom, dayFrom := timeFrom.Date()
yearTo, monthTo, dayTo := timeTo.Date()
// Create new dates without the time component for comparison
dateFrom := time.Date(yearFrom, monthFrom, dayFrom, 0, 0, 0, 0, time.UTC)
dateTo := time.Date(yearTo, monthTo, dayTo, 0, 0, 0, 0, time.UTC)
// Return true if dateFrom is strictly less than dateTo
return dateFrom.Before(dateTo)
}
78 changes: 69 additions & 9 deletions common-lib/timeRangeLib/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,19 +22,22 @@ import (
"time"
)

func (tr TimeRange) GetTimeRangeWindow(targetTime time.Time) (nextWindowEdge time.Time, isTimeBetween bool, err error) {
func (tr TimeRange) GetTimeRangeWindow(targetTime time.Time) (nextWindowEdge time.Time, isTimeBetween, isExpired bool, err error) {
err = tr.ValidateTimeRange()
if err != nil {
return nextWindowEdge, false, err
return nextWindowEdge, false, false, err
}
windowStart, windowEnd, err := tr.getWindowForTargetTime(targetTime)
if err != nil {
return nextWindowEdge, isTimeBetween, err
return nextWindowEdge, isTimeBetween, isExpired, err
}
if isTimeInBetween(targetTime, windowStart, windowEnd) {
return windowEnd, true, nil
return windowEnd, true, false, nil
}
return windowStart, false, nil
if targetTime.After(windowEnd) {
return windowEnd, false, true, nil
}
return windowStart, false, false, nil
}
func (tr TimeRange) getWindowForTargetTime(targetTime time.Time) (time.Time, time.Time, error) {

Expand Down Expand Up @@ -73,21 +76,64 @@ func (tr TimeRange) getWindowStartAndEndTime(targetTime time.Time) (time.Time, t
windowStart := schedule.Next(timeMinusDuration)
windowEnd = windowStart.Add(duration)

// Calculate start and end of the previous window
timeMinusPrevDuration := tr.currentTimeMinusPrevWindowDuration(targetTime, 2*prevDuration)
windowPrevStart := schedule.Next(timeMinusPrevDuration)
windowPrevEnd := windowPrevStart.Add(duration)

// Move back through windows until `windowPrevEnd` is less than `targetTime`
for windowPrevEnd.After(targetTime) && targetTime.Before(windowEnd) {
prevDuration += prevDuration
timeMinusPrevDuration = tr.currentTimeMinusPrevWindowDuration(targetTime, prevDuration)
windowPrevStart = schedule.Next(timeMinusPrevDuration)
windowPrevEnd = windowPrevStart.Add(duration)
}

windowStart, windowEnd = tr.applyStartEndBoundary(windowStart, windowEnd)

// edge case where targetTime is within a recurrence boundary
if windowEnd.Equal(windowStart) && targetTime.Before(windowEnd) {
return windowPrevStart, windowPrevEnd, nil
}
return windowStart, windowEnd, nil
}

/*
There are three possible cases for windowStart and windowEnd
relative to the defined time range (TimeFrom to TimeTo):

1. windowStart < TimeFrom
- The window has not yet started.

2. windowStart > TimeTo
- The occurrence has expired because the window starts after the end date.

3. windowEnd > TimeTo
- The occurrence has expired because the window ends after the end date.

In each case, windowStart and windowEnd represent the next occurrence calculated based on the current time.
*/

func (tr TimeRange) applyStartEndBoundary(windowStart time.Time, windowEnd time.Time) (time.Time, time.Time) {
if !tr.TimeFrom.IsZero() && windowStart.Before(tr.TimeFrom) {
windowStart = tr.TimeFrom
}
if !tr.TimeTo.IsZero() && windowStart.After(tr.TimeTo) {
windowStart = tr.TimeTo
}
if !tr.TimeTo.IsZero() && windowEnd.After(tr.TimeTo) {
windowEnd = tr.TimeTo
}
return windowStart, windowEnd
}

func (tr TimeRange) currentTimeMinusWindowDuration(targetTime time.Time, duration time.Duration) time.Time {
if !tr.TimeFrom.IsZero() && targetTime.Before(tr.TimeFrom) {
return tr.TimeFrom.Add(-1 * duration)
}
return targetTime.Add(-1 * duration)
}
func (tr TimeRange) currentTimeMinusPrevWindowDuration(targetTime time.Time, duration time.Duration) time.Time {
return targetTime.Add(-1 * duration)
}

Expand All @@ -97,11 +143,25 @@ func (tr TimeRange) currentTimeMinusWindowDuration(targetTime time.Time, duratio
// while tr.TimeFrom and tr.TimeTo are in GMT. Therefore, to compare them accurately, (in case of Fixed it happens)
// we convert the time range to match the time zone of targetTime.
func (tr TimeRange) getWindowForFixedTime(targetTime time.Time) (time.Time, time.Time) {
var windowStartOrEnd time.Time
timeFromInLocation := tr.TimeFrom.In(targetTime.Location())
timeToInLocation := tr.TimeTo.In(targetTime.Location())
if targetTime.After(timeToInLocation) {
return windowStartOrEnd, windowStartOrEnd
}
return timeFromInLocation, timeToInLocation
}
func (tr TimeRange) SanitizeTimeFromAndTo(loc *time.Location) TimeRange {
if !tr.TimeFrom.IsZero() {
// Update TimeFrom with the parsed hour and minute while keeping date and location
tr.TimeFrom = time.Date(
tr.TimeFrom.Year(), tr.TimeFrom.Month(), tr.TimeFrom.Day(),
0, 0, 0, 1, loc,
)

}
if !tr.TimeTo.IsZero() {
// Update TimeTo with the parsed hour and minute while keeping date and location
tr.TimeTo = time.Date(
tr.TimeTo.Year(), tr.TimeTo.Month(), tr.TimeTo.Day(),
23, 59, 59, 0, loc,
)
}
return tr
}
Loading
Loading