2017-05-12 20:12:23 -04:00
|
|
|
package util
|
2016-07-22 01:09:09 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
const (
|
|
|
|
// AllDaysMask is a bitmask of all the days of the week.
|
|
|
|
AllDaysMask = 1<<uint(time.Sunday) | 1<<uint(time.Monday) | 1<<uint(time.Tuesday) | 1<<uint(time.Wednesday) | 1<<uint(time.Thursday) | 1<<uint(time.Friday) | 1<<uint(time.Saturday)
|
|
|
|
// WeekDaysMask is a bitmask of all the weekdays of the week.
|
|
|
|
WeekDaysMask = 1<<uint(time.Monday) | 1<<uint(time.Tuesday) | 1<<uint(time.Wednesday) | 1<<uint(time.Thursday) | 1<<uint(time.Friday)
|
|
|
|
//WeekendDaysMask is a bitmask of the weekend days of the week.
|
|
|
|
WeekendDaysMask = 1<<uint(time.Sunday) | 1<<uint(time.Saturday)
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
// DaysOfWeek are all the time.Weekday in an array for utility purposes.
|
|
|
|
DaysOfWeek = []time.Weekday{
|
|
|
|
time.Sunday,
|
|
|
|
time.Monday,
|
|
|
|
time.Tuesday,
|
|
|
|
time.Wednesday,
|
|
|
|
time.Thursday,
|
|
|
|
time.Friday,
|
|
|
|
time.Saturday,
|
|
|
|
}
|
|
|
|
|
|
|
|
// WeekDays are the business time.Weekday in an array.
|
|
|
|
WeekDays = []time.Weekday{
|
|
|
|
time.Monday,
|
|
|
|
time.Tuesday,
|
|
|
|
time.Wednesday,
|
|
|
|
time.Thursday,
|
|
|
|
time.Friday,
|
|
|
|
}
|
|
|
|
|
|
|
|
// WeekendDays are the weekend time.Weekday in an array.
|
|
|
|
WeekendDays = []time.Weekday{
|
|
|
|
time.Sunday,
|
|
|
|
time.Saturday,
|
|
|
|
}
|
|
|
|
|
|
|
|
//Epoch is unix epoc saved for utility purposes.
|
|
|
|
Epoch = time.Unix(0, 0)
|
|
|
|
)
|
|
|
|
|
2018-09-10 16:08:20 -04:00
|
|
|
// Date contains utility functions that operate on dates.
|
|
|
|
var Date date
|
2016-07-31 19:54:09 -04:00
|
|
|
|
|
|
|
type date struct{}
|
2016-07-23 15:58:37 -04:00
|
|
|
|
2018-09-10 16:08:20 -04:00
|
|
|
func (d date) MustEastern() *time.Location {
|
|
|
|
if eastern, err := d.Eastern(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
} else {
|
|
|
|
return eastern
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Eastern returns the eastern timezone.
|
|
|
|
func (d date) Eastern() (*time.Location, error) {
|
|
|
|
// Try POSIX
|
|
|
|
est, err := time.LoadLocation("America/New_York")
|
2018-09-10 16:11:25 -04:00
|
|
|
if err != nil {
|
2018-09-10 16:08:20 -04:00
|
|
|
// Try Windows
|
|
|
|
est, err = time.LoadLocation("EST")
|
2018-09-10 16:11:25 -04:00
|
|
|
if err != nil {
|
2018-09-10 16:08:20 -04:00
|
|
|
return nil, err
|
2016-07-22 01:09:09 -04:00
|
|
|
}
|
|
|
|
}
|
2018-09-10 16:08:20 -04:00
|
|
|
return est, nil
|
2016-07-22 01:09:09 -04:00
|
|
|
}
|
|
|
|
|
2018-09-10 16:08:20 -04:00
|
|
|
func (d date) MustPacific() *time.Location {
|
|
|
|
if pst, err := d.Pacific(); err != nil {
|
|
|
|
panic(err)
|
|
|
|
} else {
|
|
|
|
return pst
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Pacific returns the pacific timezone.
|
|
|
|
func (d date) Pacific() (*time.Location, error) {
|
|
|
|
// Try POSIX
|
|
|
|
pst, err := time.LoadLocation("America/Los_Angeles")
|
2018-09-10 16:11:25 -04:00
|
|
|
if err != nil {
|
2018-09-10 16:08:20 -04:00
|
|
|
// Try Windows
|
|
|
|
pst, err = time.LoadLocation("PST")
|
2018-09-10 16:11:25 -04:00
|
|
|
if err != nil {
|
2018-09-10 16:08:20 -04:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pst, nil
|
2016-07-23 14:50:30 -04:00
|
|
|
}
|
|
|
|
|
2018-09-10 16:08:20 -04:00
|
|
|
// TimeUTC returns a new time.Time for the given clock components in UTC.
|
|
|
|
// It is meant to be used with the `OnDate` function.
|
|
|
|
func (d date) TimeUTC(hour, min, sec, nsec int) time.Time {
|
|
|
|
return time.Date(0, 0, 0, hour, min, sec, nsec, time.UTC)
|
2016-07-23 14:50:30 -04:00
|
|
|
}
|
|
|
|
|
2016-08-01 03:50:32 -04:00
|
|
|
// Time returns a new time.Time for the given clock components.
|
2018-09-10 16:08:20 -04:00
|
|
|
// It is meant to be used with the `OnDate` function.
|
2016-08-01 03:50:32 -04:00
|
|
|
func (d date) Time(hour, min, sec, nsec int, loc *time.Location) time.Time {
|
2016-07-23 18:35:49 -04:00
|
|
|
return time.Date(0, 0, 0, hour, min, sec, nsec, loc)
|
|
|
|
}
|
|
|
|
|
2018-09-10 16:08:20 -04:00
|
|
|
// DateUTC returns a new time.Time for the given date comonents at (noon) in UTC.
|
|
|
|
func (d date) DateUTC(year, month, day int) time.Time {
|
|
|
|
return time.Date(year, time.Month(month), day, 12, 0, 0, 0, time.UTC)
|
|
|
|
}
|
|
|
|
|
|
|
|
// DateUTC returns a new time.Time for the given date comonents at (noon) in a given location.
|
2016-08-01 03:50:32 -04:00
|
|
|
func (d date) Date(year, month, day int, loc *time.Location) time.Time {
|
|
|
|
return time.Date(year, time.Month(month), day, 12, 0, 0, 0, loc)
|
|
|
|
}
|
|
|
|
|
2018-09-10 16:08:20 -04:00
|
|
|
// OnDate returns the clock components of clock (hour,minute,second) on the date components of d.
|
|
|
|
func (d date) OnDate(clock, date time.Time) time.Time {
|
|
|
|
tzAdjusted := date.In(clock.Location())
|
2016-08-01 03:50:32 -04:00
|
|
|
return time.Date(tzAdjusted.Year(), tzAdjusted.Month(), tzAdjusted.Day(), clock.Hour(), clock.Minute(), clock.Second(), clock.Nanosecond(), clock.Location())
|
2016-07-31 19:54:09 -04:00
|
|
|
}
|
|
|
|
|
2018-09-10 16:08:20 -04:00
|
|
|
// NoonOnDate is a shortcut for On(Time(12,0,0), cd) a.k.a. noon on a given date.
|
|
|
|
func (d date) NoonOnDate(cd time.Time) time.Time {
|
2016-07-31 19:54:09 -04:00
|
|
|
return time.Date(cd.Year(), cd.Month(), cd.Day(), 12, 0, 0, 0, cd.Location())
|
2016-07-23 18:35:49 -04:00
|
|
|
}
|
|
|
|
|
2016-07-23 01:43:27 -04:00
|
|
|
// IsWeekDay returns if the day is a monday->friday.
|
2016-07-31 19:54:09 -04:00
|
|
|
func (d date) IsWeekDay(day time.Weekday) bool {
|
|
|
|
return !d.IsWeekendDay(day)
|
2016-07-23 01:43:27 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// IsWeekendDay returns if the day is a monday->friday.
|
2016-07-31 19:54:09 -04:00
|
|
|
func (d date) IsWeekendDay(day time.Weekday) bool {
|
2016-07-23 01:43:27 -04:00
|
|
|
return day == time.Saturday || day == time.Sunday
|
|
|
|
}
|
|
|
|
|
2016-07-31 19:54:09 -04:00
|
|
|
// Before returns if a timestamp is strictly before another date (ignoring hours, minutes etc.)
|
|
|
|
func (d date) Before(before, reference time.Time) bool {
|
2016-08-01 03:50:32 -04:00
|
|
|
tzAdjustedBefore := before.In(reference.Location())
|
|
|
|
if tzAdjustedBefore.Year() < reference.Year() {
|
2016-07-23 01:43:27 -04:00
|
|
|
return true
|
|
|
|
}
|
2016-08-01 03:50:32 -04:00
|
|
|
if tzAdjustedBefore.Month() < reference.Month() {
|
2016-07-23 01:43:27 -04:00
|
|
|
return true
|
|
|
|
}
|
2016-08-01 03:50:32 -04:00
|
|
|
return tzAdjustedBefore.Year() == reference.Year() && tzAdjustedBefore.Month() == reference.Month() && tzAdjustedBefore.Day() < reference.Day()
|
2016-07-23 01:43:27 -04:00
|
|
|
}
|
|
|
|
|
2016-07-31 19:54:09 -04:00
|
|
|
const (
|
2017-02-28 20:55:48 -05:00
|
|
|
_secondsPerHour = 60 * 60
|
|
|
|
_secondsPerDay = 60 * 60 * 24
|
2016-07-31 19:54:09 -04:00
|
|
|
)
|
|
|
|
|
|
|
|
// NextDay returns the timestamp advanced a day.
|
|
|
|
func (d date) NextDay(ts time.Time) time.Time {
|
|
|
|
return ts.AddDate(0, 0, 1)
|
2016-07-22 01:09:09 -04:00
|
|
|
}
|
|
|
|
|
2016-07-31 19:54:09 -04:00
|
|
|
// NextHour returns the next timestamp on the hour.
|
|
|
|
func (d date) NextHour(ts time.Time) time.Time {
|
|
|
|
//advance a full hour ...
|
|
|
|
advanced := ts.Add(time.Hour)
|
|
|
|
minutes := time.Duration(advanced.Minute()) * time.Minute
|
|
|
|
final := advanced.Add(-minutes)
|
|
|
|
return time.Date(final.Year(), final.Month(), final.Day(), final.Hour(), 0, 0, 0, final.Location())
|
2016-07-22 01:09:09 -04:00
|
|
|
}
|
2016-08-01 03:50:32 -04:00
|
|
|
|
|
|
|
// NextDayOfWeek returns the next instance of a given weekday after a given timestamp.
|
|
|
|
func (d date) NextDayOfWeek(after time.Time, dayOfWeek time.Weekday) time.Time {
|
|
|
|
afterWeekday := after.Weekday()
|
|
|
|
if afterWeekday == dayOfWeek {
|
|
|
|
return after.AddDate(0, 0, 7)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 1 vs 5 ~ add 4 days
|
|
|
|
if afterWeekday < dayOfWeek {
|
|
|
|
dayDelta := int(dayOfWeek - afterWeekday)
|
|
|
|
return after.AddDate(0, 0, dayDelta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// 5 vs 1, add 7-(5-1) ~ 3 days
|
|
|
|
dayDelta := 7 - int(afterWeekday-dayOfWeek)
|
|
|
|
return after.AddDate(0, 0, dayDelta)
|
|
|
|
}
|