Skip to content

Commit

Permalink
Add custom type to allow to calculate Elapsed time of the day. (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
Skandalik authored Mar 25, 2021
1 parent 6b40d6a commit d2fe410
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 0 deletions.
3 changes: 3 additions & 0 deletions clock.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ func init() {
Restore()
}

// Day represents full day.
const Day = 24 * time.Hour

// Clock represents a global clock.
var Clock clock.Clock

Expand Down
47 changes: 47 additions & 0 deletions elapsed.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package clock

import (
"math"
"time"
)

// DayElapsed elapsed time during a day
type DayElapsed time.Duration

// NewDayElapsed creates new DayElapsed from passed time.
func NewDayElapsed(current time.Time, shift time.Duration) DayElapsed {
current = current.UTC()
midnight := current.Truncate(Day)
resetTimeForCurrentDay := midnight.Add(shift)

if current.Before(resetTimeForCurrentDay) {
resetTimeForCurrentDay = resetTimeForCurrentDay.Add(-Day) // if we are before reset time, it means reset time was yesterday
}

sub := current.Sub(resetTimeForCurrentDay)
return DayElapsed(sub)
}

// FullHours get full hours of current day
func (e DayElapsed) FullHours() int {
return int(math.Floor(e.hours()))
}

// HourPart elapsed time of current hour (percentage)
func (e DayElapsed) HourPart() float64 {
_, f := math.Modf(e.hours())
return f
}

// Remaining returns remaining time of the day
func (e DayElapsed) Remaining() time.Duration {
remaining := Day - time.Duration(e)
if remaining < 0 {
remaining = 0
}
return remaining
}

func (e DayElapsed) hours() float64 {
return time.Duration(e).Hours()
}
171 changes: 171 additions & 0 deletions elapsed_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package clock_test

import (
"testing"
"time"

"github.com/msales/go-clock"
"github.com/stretchr/testify/assert"
)

func TestDayElapsed_FullHours_and_HourPart(t *testing.T) {
tests := []struct {
name string
dayElapsed clock.DayElapsed
wantFullHour int
wantHourPart float64
wantRemaining time.Duration
}{
{
name: "midnight",
dayElapsed: clock.DayElapsed(time.Duration(0)),
wantFullHour: 0,
wantHourPart: 0.0,
wantRemaining: clock.Day,
},
{
name: "00:30",
dayElapsed: clock.DayElapsed(30 * time.Minute),
wantFullHour: 0,
wantHourPart: 0.5,
wantRemaining: 23*time.Hour + 30*time.Minute,
},
{
name: "01:00",
dayElapsed: clock.DayElapsed(60 * time.Minute),
wantFullHour: 1,
wantHourPart: 0.0,
wantRemaining: 23 * time.Hour,
},
{
name: "01:30",
dayElapsed: clock.DayElapsed(90 * time.Minute),
wantFullHour: 1,
wantHourPart: 0.5,
wantRemaining: 22*time.Hour + 30*time.Minute,
},
{
name: "22:59",
dayElapsed: clock.DayElapsed(1379 * time.Minute),
wantFullHour: 22,
wantHourPart: 0.9833333333,
wantRemaining: 1*time.Hour + 1*time.Minute,
},
{
name: "23:59",
dayElapsed: clock.DayElapsed(1439 * time.Minute),
wantFullHour: 23,
wantHourPart: 0.9833333333,
wantRemaining: 1 * time.Minute,
},
{
name: "16:37",
dayElapsed: clock.DayElapsed(997 * time.Minute),
wantFullHour: 16,
wantHourPart: 0.6166666667,
wantRemaining: 7*time.Hour + 23*time.Minute,
},
{
name: "25:30 overdue",
dayElapsed: clock.DayElapsed(25*time.Hour + 30*time.Minute),
wantFullHour: 25,
wantHourPart: 0.5,
wantRemaining: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
gotFullHours := tt.dayElapsed.FullHours()
gotHourPart := tt.dayElapsed.HourPart()
gotRemaining := tt.dayElapsed.Remaining()
assert.Equal(t, tt.wantFullHour, gotFullHours)
assert.InDelta(t, tt.wantHourPart, gotHourPart, 0.00001)
assert.Equal(t, tt.wantRemaining, gotRemaining)
})
}
}

func TestNewDayElapsed(t *testing.T) {
tests := []struct {
name string
current time.Time
shift time.Duration
wantElapsed clock.DayElapsed
wantRemaining time.Duration
wantFullHours int
wantHourPart float64
}{
{
name: "Reset time on midnight",
current: time.Date(2021, 3, 15, 15, 59, 30, 0, time.UTC),
shift: 0, // UTC midnight
wantElapsed: clock.DayElapsed(15*time.Hour + 59*time.Minute + 30*time.Second),
wantRemaining: 8*time.Hour + 30*time.Second,
wantFullHours: 15,
wantHourPart: 0.9916666667,
},
{
name: "Reset time on midnight at midnight",
current: time.Date(2021, 3, 15, 0, 0, 0, 0, time.UTC),
shift: 0, // UTC midnight
wantElapsed: clock.DayElapsed(0),
wantRemaining: clock.Day,
wantFullHours: 0,
wantHourPart: 0,
},
{
name: "Reset time at 13:20, current time at 13:20",
current: time.Date(2021, 3, 15, 13, 20, 0, 0, time.UTC),
shift: 13*time.Hour + 20*time.Minute,
wantElapsed: clock.DayElapsed(0),
wantRemaining: clock.Day,
wantFullHours: 0,
wantHourPart: 0,
},
{
name: "Reset time at 16:00 UTC, current at 15:59:30",
current: time.Date(2021, 3, 15, 15, 59, 30, 0, time.UTC),
shift: 16 * time.Hour,
wantElapsed: clock.DayElapsed(23*time.Hour + 59*time.Minute + 30*time.Second),
wantRemaining: 30 * time.Second,
wantFullHours: 23,
wantHourPart: 0.9916666667,
},
{
name: "Reset time at 15:00 UTC, current at 15:59:30",
current: time.Date(2021, 3, 15, 15, 59, 30, 0, time.UTC),
shift: 15 * time.Hour,
wantElapsed: clock.DayElapsed(59*time.Minute + 30*time.Second),
wantRemaining: 23*time.Hour + 30*time.Second,
wantFullHours: 0,
wantHourPart: 0.9916666667,
},
{
name: "Reset time at 16:00 UTC, current at 15:59:30 UTC+1",
current: time.Date(2021, 3, 15, 15, 59, 30, 0, time.FixedZone("UTC1", 3600)),
shift: 16 * time.Hour,
wantElapsed: clock.DayElapsed(22*time.Hour + 59*time.Minute + 30*time.Second),
wantRemaining: 1*time.Hour + 30*time.Second,
wantFullHours: 22,
wantHourPart: 0.9916666667,
},
{
name: "Reset time at 23:00 UTC, current at 00:00:00 UTC+1",
current: time.Date(2021, 3, 15, 0, 0, 0, 0, time.FixedZone("UTC1", 3600)),
shift: 23 * time.Hour,
wantElapsed: clock.DayElapsed(0),
wantRemaining: clock.Day,
wantFullHours: 0,
wantHourPart: 0,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
elapsed := clock.NewDayElapsed(tt.current, tt.shift)
assert.Equal(t, tt.wantElapsed, elapsed)
assert.Equal(t, tt.wantRemaining, elapsed.Remaining())
assert.Equal(t, tt.wantFullHours, elapsed.FullHours())
assert.InDelta(t, tt.wantHourPart, elapsed.HourPart(), 0.0001)
})
}
}

0 comments on commit d2fe410

Please sign in to comment.