Skip to content

Commit

Permalink
Merge pull request #387 from moov-io/feat-addbankingtime
Browse files Browse the repository at this point in the history
feat: AddBankingTime
  • Loading branch information
adamdecaf authored May 9, 2024
2 parents 46e4527 + ada492e commit 574f555
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 0 deletions.
40 changes: 40 additions & 0 deletions time.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,3 +177,43 @@ func (t Time) IsWeekend() bool {
day := t.Time.Weekday()
return day == time.Saturday || day == time.Sunday
}

// AddBankingTime increments t by the hours, minutes, and seconds provided
// but keeps the final time within 9am to 5pm in t's Location.
func (t Time) AddBankingTime(hours, minutes, seconds int) Time {
duration := time.Duration(hours) * time.Hour
duration += time.Duration(minutes) * time.Minute
duration += time.Duration(seconds) * time.Second

return addBankingDuration(t, duration)
}

func addBankingDuration(start Time, duration time.Duration) Time {
// If we're past the current day's banking hours advance forward one day
if start.Hour() >= 17 && (start.Minute() > 0 || start.Second() > 0) {
start = start.AddBankingDay(1)
}

// Start the day at 9am or later, but not past 5pm
if start.Hour() < 9 || start.Hour() >= 17 {
start.Time = time.Date(start.Year(), start.Month(), start.Day(), 9, start.Minute(), start.Second(), 0, start.Location())
}

// Add banking hours as we can
for duration > 0 {
if start.IsBankingDay() {
// Calculate the time remaining in the banking day
endOfDay := time.Date(start.Year(), start.Month(), start.Day(), 17, 0, 0, 0, start.Location())
remainingToday := endOfDay.Sub(start.Time)
if duration < remainingToday {
start.Time = start.Time.Add(duration)
return start
}
duration -= remainingToday
}
// Move to the next banking day starting at 9 AM
start = start.AddBankingDay(1)
start.Time = time.Date(start.Year(), start.Month(), start.Day(), 9, 0, 0, 0, start.Location())
}
return start
}
68 changes: 68 additions & 0 deletions time_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -505,3 +505,71 @@ func TestTime__YearlyHolidays(t *testing.T) {
require.NotEqual(t, cases[i].holiday, NewTime(cases[i].when).IsBankingDay(), description)
}
}

func TestTime_AddBankingTime(t *testing.T) {
loc, _ := time.LoadLocation("America/New_York")
cases := []struct {
input time.Time
hours, minutes, seconds int
expected time.Time
}{
{
// Normal day -> later that day
input: time.Date(2024, time.April, 30, 10, 30, 0, 0, loc),
hours: 2, minutes: 25, seconds: 18,
expected: time.Date(2024, time.April, 30, 12, 55, 18, 0, loc),
},
{
// Before 9am on banking day, adding less than what gets us to 9am,
// should still be +2hrs after 9am
input: time.Date(2024, time.April, 30, 2, 30, 0, 0, loc),
hours: 2, minutes: 25, seconds: 18,
expected: time.Date(2024, time.April, 30, 11, 55, 18, 0, loc),
},
{
// Overlaps to next day
input: time.Date(2024, time.April, 30, 10, 30, 0, 0, loc),
hours: 7, minutes: 25, seconds: 18,
expected: time.Date(2024, time.May, 1, 9, 55, 18, 0, loc),
},
{
// After 5pm on banking day, advanced to next day
input: time.Date(2024, time.June, 30, 17, 30, 0, 0, loc),
hours: 7, minutes: 25, seconds: 18,
expected: time.Date(2024, time.July, 1, 16, 55, 18, 0, loc),
},
{
// After 5pm on bankng day, advance 2+ banking days
input: time.Date(2024, time.June, 30, 17, 30, 0, 0, loc),
hours: 8, minutes: 25, seconds: 18,
expected: time.Date(2024, time.July, 2, 9, 55, 18, 0, loc),
},
{
// Negative, do nothing
input: time.Date(2024, time.April, 30, 10, 30, 0, 0, loc),
hours: -7, minutes: -25, seconds: -18,
expected: time.Date(2024, time.April, 30, 10, 30, 0, 0, loc),
},
{
// Thursday July 4th is a holiday, so move to Friday
input: time.Date(2024, time.July, 3, 15, 30, 0, 0, loc),
hours: 4, minutes: 12, seconds: 18,
expected: time.Date(2024, time.July, 5, 11, 42, 18, 0, loc),
},
{
// Monday May 27th is a holiday, so Thursday -> Tuesday
input: time.Date(2024, time.May, 23, 14, 30, 0, 0, loc),
hours: 11, minutes: 12, seconds: 18,
expected: time.Date(2024, time.May, 28, 9, 42, 18, 0, loc),
},
}
for idx, tc := range cases {
t.Run(fmt.Sprintf("case_%d", idx), func(t *testing.T) {
desc := fmt.Sprintf("start=%v hours=%v minutes=%v seconds=%v\n",
tc.input.Format(time.RFC3339),
tc.hours, tc.minutes, tc.seconds)
got := NewTime(tc.input).AddBankingTime(tc.hours, tc.minutes, tc.seconds)
require.Equal(t, tc.expected.Format(time.RFC3339), got.Format(time.RFC3339), desc)
})
}
}

0 comments on commit 574f555

Please sign in to comment.