openmeter / pkg /datetime /datetime.go
Leon4gr45's picture
Upload folder using huggingface_hub (part 9)
fea99b3 verified
Raw
History Blame Contribute Delete
3.95 kB
package datetime
import (
"encoding/json"
"time"
"github.com/alpacahq/alpacadecimal"
)
// DateTime extends the time.Time type to support the RFC 9557 format.
type DateTime struct {
time.Time
}
// NewDateTime creates a new DateTime from a time.Time.
func NewDateTime(t time.Time) DateTime {
return DateTime{t}
}
// AsTime returns the underlying time.Time.
func (t DateTime) AsTime() time.Time {
return t.Time
}
// MarshalJSON marshals the DateTime to a JSON string in RFC3339 format.
func (t DateTime) MarshalJSON() ([]byte, error) {
return json.Marshal(t.Format(time.RFC3339))
}
// UnmarshalJSON unmarshals the DateTime from a JSON string.
// It supports RFC3339, ISO8601, and RFC9557 formats.
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
}
// Add adds a duration to a DateTime.
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()
// We can safely ignore this error
seconds, _ := alpacadecimal.NewFromString(d.SecondsDecimal().String())
dt = dt.AddYearsNoOverflow(years).
AddMonthsNoOverflow(months).
AddWeeks(weeks).
AddDays(days).
AddHours(hours).
AddMinutes(minutes).
AddSeconds(seconds)
return dt
}
// AddDateNoOverflow adds some years, months, and days without overflowing month.
func (d DateTime) AddDateNoOverflow(years int, months int, days int) DateTime {
d = d.AddYearsNoOverflow(years).
AddMonthsNoOverflow(months).
AddDays(days)
return d
}
// AddYearsNoOverflow adds some years without overflowing month.
func (d DateTime) AddYearsNoOverflow(years int) DateTime {
nanosecond := d.Nanosecond()
year, month, day := d.Date()
hour, minute, second := d.Clock()
// get the last day of this month after some years
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()))
}
// AddMonthsNoOverflow adds some months without overflowing month.
func (d DateTime) AddMonthsNoOverflow(months int) DateTime {
nanosecond := d.Nanosecond()
year, month, day := d.Date()
hour, minute, second := d.Clock()
// get the last day of this month after some months
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()))
}
// AddWeeks adds some weeks to the DateTime.
func (d DateTime) AddWeeks(weeks int) DateTime {
return d.shiftClockTo(d.Time.AddDate(0, 0, weeks*7))
}
// AddDays adds some days to the DateTime.
func (d DateTime) AddDays(days int) DateTime {
return d.shiftClockTo(d.Time.AddDate(0, 0, days))
}
// AddHours adds some hours to the DateTime.
func (d DateTime) AddHours(hours int) DateTime {
return d.shiftClockTo(d.Time.Add(time.Duration(hours) * time.Hour))
}
// AddMinutes adds some minutes to the DateTime.
func (d DateTime) AddMinutes(minutes int) DateTime {
return d.shiftClockTo(d.Time.Add(time.Duration(minutes) * time.Minute))
}
// AddSeconds adds some seconds to the DateTime.
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)))
}
// To mimic time.Add(d time.Duration) behavior, we want to use clock shift instead of constructing time instances.
func (d DateTime) shiftClockTo(t time.Time) DateTime {
wallTimeDiff := t.Sub(d.Time.Round(0))
d.Time = d.Time.Add(wallTimeDiff)
return d
}