| package datetime |
|
|
| import ( |
| "encoding/json" |
| "time" |
|
|
| "github.com/alpacahq/alpacadecimal" |
| ) |
|
|
| |
| type DateTime struct { |
| time.Time |
| } |
|
|
| |
| func NewDateTime(t time.Time) DateTime { |
| return DateTime{t} |
| } |
|
|
| |
| func (t DateTime) AsTime() time.Time { |
| return t.Time |
| } |
|
|
| |
| func (t DateTime) MarshalJSON() ([]byte, error) { |
| return json.Marshal(t.Format(time.RFC3339)) |
| } |
|
|
| |
| |
| func (t *DateTime) UnmarshalJSON(data []byte) error { |
| var s string |
| if err := json.Unmarshal(data, &s); err != nil { |
| return err |
| } |
|
|
| date, err := Parse(s) |
| if err != nil { |
| return err |
| } |
|
|
| *t = date |
|
|
| return nil |
| } |
|
|
| |
| func (dt DateTime) Add(d ISODuration) DateTime { |
| years := d.Years() |
| months := d.Months() |
| weeks := d.Weeks() |
| days := d.Days() |
| hours := d.Hours() |
| minutes := d.Minutes() |
| |
| seconds, _ := alpacadecimal.NewFromString(d.SecondsDecimal().String()) |
|
|
| dt = dt.AddYearsNoOverflow(years). |
| AddMonthsNoOverflow(months). |
| AddWeeks(weeks). |
| AddDays(days). |
| AddHours(hours). |
| AddMinutes(minutes). |
| AddSeconds(seconds) |
|
|
| return dt |
| } |
|
|
| |
| func (d DateTime) AddDateNoOverflow(years int, months int, days int) DateTime { |
| d = d.AddYearsNoOverflow(years). |
| AddMonthsNoOverflow(months). |
| AddDays(days) |
|
|
| return d |
| } |
|
|
| |
| func (d DateTime) AddYearsNoOverflow(years int) DateTime { |
| nanosecond := d.Nanosecond() |
| year, month, day := d.Date() |
| hour, minute, second := d.Clock() |
| |
| lastYear, lastMonth, lastDay := time.Date(year+years, month+1, 0, hour, minute, second, nanosecond, d.Location()).Date() |
| if day > lastDay { |
| day = lastDay |
| } |
| return d.shiftClockTo(time.Date(lastYear, lastMonth, day, hour, minute, second, nanosecond, d.Location())) |
| } |
|
|
| |
| func (d DateTime) AddMonthsNoOverflow(months int) DateTime { |
| nanosecond := d.Nanosecond() |
| year, month, day := d.Date() |
| hour, minute, second := d.Clock() |
| |
| lastYear, lastMonth, lastDay := time.Date(year, month+time.Month(months+1), 0, hour, minute, second, nanosecond, d.Location()).Date() |
| if day > lastDay { |
| day = lastDay |
| } |
| return d.shiftClockTo(time.Date(lastYear, lastMonth, day, hour, minute, second, nanosecond, d.Location())) |
| } |
|
|
| |
| func (d DateTime) AddWeeks(weeks int) DateTime { |
| return d.shiftClockTo(d.Time.AddDate(0, 0, weeks*7)) |
| } |
|
|
| |
| func (d DateTime) AddDays(days int) DateTime { |
| return d.shiftClockTo(d.Time.AddDate(0, 0, days)) |
| } |
|
|
| |
| func (d DateTime) AddHours(hours int) DateTime { |
| return d.shiftClockTo(d.Time.Add(time.Duration(hours) * time.Hour)) |
| } |
|
|
| |
| func (d DateTime) AddMinutes(minutes int) DateTime { |
| return d.shiftClockTo(d.Time.Add(time.Duration(minutes) * time.Minute)) |
| } |
|
|
| |
| func (d DateTime) AddSeconds(seconds alpacadecimal.Decimal) DateTime { |
| nano := seconds.Mul(alpacadecimal.NewFromInt(int64(time.Second))).BigInt().Int64() |
| return d.shiftClockTo(d.Time.Add(time.Duration(nano))) |
| } |
|
|
| |
| func (d DateTime) shiftClockTo(t time.Time) DateTime { |
| wallTimeDiff := t.Sub(d.Time.Round(0)) |
| d.Time = d.Time.Add(wallTimeDiff) |
| return d |
| } |
|
|