gob/datetime/datetime.go

543 lines
20 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package datetime
import (
"fmt"
"time"
)
type datetime struct {
date
clock clock
}
func newDT(d date, c clock) datetime {
if d.valid() && c.valid() {
return datetime{d, c}
}
return datetime{dateNil, clockNil}
}
func (dt datetime) h() uint { return dt.clock.h() }
func (dt datetime) i() uint { return dt.clock.i() }
func (dt datetime) s() uint { return dt.clock.s() }
func (dt datetime) v() uint { return dt.clock.v() }
func (dt datetime) p() Precision { return dt.clock.p() }
func (dt datetime) dv() uint { return dt.clock.dv() }
func (dt datetime) ds() uint { return dt.clock.ds() }
func (dt datetime) di() uint { return dt.clock.di() }
func (dt datetime) t(l *time.Location) time.Time {
return fromDT(dt.y(), dt.m(), dt.d(), dt.h(), dt.i(), dt.s(), dt.v(), l)
}
func (dt datetime) dst(l *time.Location) bool { return dt.t(l).IsDST() }
func (dt datetime) ts(l *time.Location) int64 { return dt.t(l).Unix() }
func (dt datetime) tv(l *time.Location) int64 { return dt.t(l).UnixMilli() }
func (dt datetime) valid() bool { return dt.date.valid() && dt.clock.valid() }
func (dt datetime) setY(y int, e ...uint) datetime {
ed, ec := spl(e, 2)
d, c := dt.date.setY(y, ed...), dt.clock
if len(ec) > 0 {
c = c.setH(ec[0], ec[1:]...)
}
return newDT(d, c)
}
func (dt datetime) setM(m uint, e ...uint) datetime {
ed, ec := spl(e, 1)
d, c := dt.date.setM(m, ed...), dt.clock
if len(ec) > 0 {
c = c.setH(ec[0], ec[1:]...)
}
return newDT(d, c)
}
func (dt datetime) setD(d uint, e ...uint) datetime {
t, c := dt.date.setD(d), dt.clock
if len(e) > 0 {
c = c.setH(e[0], e[1:]...)
}
return newDT(t, c)
}
func (dt datetime) setH(h uint, e ...uint) datetime { return newDT(dt.date, dt.clock.setH(h, e...)) }
func (dt datetime) setI(i uint, e ...uint) datetime { return newDT(dt.date, dt.clock.setI(i, e...)) }
func (dt datetime) setS(s uint, e ...uint) datetime { return newDT(dt.date, dt.clock.setS(s, e...)) }
func (dt datetime) setV(v uint) datetime { return newDT(dt.date, dt.clock.setV(v)) }
func (dt datetime) setP(p Precision) datetime { return newDT(dt.date, dt.clock.setP(p)) }
func (dt datetime) add(y, m, d, h, i int, e ...int) datetime {
if !dt.valid() {
return dt
}
p := dt.p()
v := int(dt.dv()) + h*MillisecondPerHour + i*MillisecondPerMinute
if len(e) > 0 {
p, v = min(p, PrecisionSecond), v+e[0]*MillisecondPerSecond
if len(e) > 1 {
p, v = PrecisionMillisecond, v+e[1]
}
}
d += v / MillisecondPerDay
v %= MillisecondPerDay
if v < 0 {
d--
v += MillisecondPerDay
}
return newDT(dt.date.add(y, m, d), newC(uint(v), p))
}
func (dt datetime) addT(y, m, d int) datetime { return newDT(dt.date.add(y, m, d), dt.clock) }
func (dt datetime) addC(h, i int, e ...int) datetime { return dt.add(0, 0, 0, h, i, e...) }
func (dt datetime) addY(y int) datetime { return dt.addT(y, 0, 0) }
func (dt datetime) addM(m int) datetime { return dt.addT(0, m, 0) }
func (dt datetime) addW(w int) datetime { return dt.addD(w * DayPerWeek) }
func (dt datetime) addD(d int) datetime { return dt.addT(0, 0, d) }
func (dt datetime) addH(h int) datetime { return dt.addC(h, 0) }
func (dt datetime) addI(i int) datetime { return dt.addC(0, i) }
func (dt datetime) addS(s int) datetime { return dt.addC(0, 0, s) }
func (dt datetime) addV(n int) datetime { return dt.addC(0, 0, 0, n) }
func (dt datetime) addDD(dd Duration) datetime {
f := map[Unit]func(int) datetime{
Year: dt.addY,
Month: dt.addM,
Week: dt.addW,
Day: dt.addD,
Hour: dt.addH,
Minute: dt.addI,
Second: dt.addS,
Millisecond: dt.addV,
}
e, u := dd.Value(), dd.Unit()
if cb, ok := f[u]; ok {
return cb(e)
}
return dt
}
func (dt datetime) bY() datetime { return dt.setM(January, 1).bD() }
func (dt datetime) eY() datetime { return dt.setM(December, 31).eD() }
func (dt datetime) bM() datetime { return dt.setD(1).bD() }
func (dt datetime) eM() datetime { return dt.setD(monthLen(dt.y(), dt.m())).eD() }
func (dt datetime) bW(l *time.Location) datetime { return newDT(dt.date.bW(l), dt.clock).bD() }
func (dt datetime) eW(l *time.Location) datetime { return newDT(dt.date.eW(l), dt.clock).eD() }
func (dt datetime) bD() datetime { return newDT(dt.date, dt.clock.bD()) }
func (dt datetime) eD() datetime { return newDT(dt.date, dt.clock.eD()) }
func (dt datetime) bH() datetime { return newDT(dt.date, dt.clock.bH()) }
func (dt datetime) eH() datetime { return newDT(dt.date, dt.clock.eH()) }
func (dt datetime) bI() datetime { return newDT(dt.date, dt.clock.bI()) }
func (dt datetime) eI() datetime { return newDT(dt.date, dt.clock.eI()) }
func (dt datetime) bS() datetime { return newDT(dt.date, dt.clock.bS()) }
func (dt datetime) eS() datetime { return newDT(dt.date, dt.clock.eS()) }
func (dt1 datetime) cmp(dt2 datetime) int {
if !dt1.valid() {
if !dt2.valid() {
return 0
}
return -1
}
if !dt2.valid() {
return 1
}
if c := dt1.date.cmp(dt2.date); c != 0 {
return c
}
return dt1.clock.cmp(dt2.clock)
}
func (dt1 datetime) subV(dt2 datetime, l1, l2 *time.Location) int {
return int(dt1.tv(l1) - dt2.tv(l2))
}
func (dt1 datetime) subS(dt2 datetime, l1, l2 *time.Location) int {
return dt1.subV(dt2, l1, l2) / MillisecondPerSecond
}
func (dt1 datetime) subI(dt2 datetime, l1, l2 *time.Location) int {
return dt1.subV(dt2, l1, l2) / MillisecondPerMinute
}
func (dt1 datetime) subH(dt2 datetime, l1, l2 *time.Location) int {
return dt1.subV(dt2, l1, l2) / MillisecondPerHour
}
func (dt1 datetime) subD(dt2 datetime, l1, l2 *time.Location) int {
return dt1.subV(dt2, l1, l2) / MillisecondPerMinute
}
func (dt1 datetime) subW(dt2 datetime, l1, l2 *time.Location) int {
return dt1.subV(dt2, l1, l2) / MillisecondPerWeek
}
func (dt1 datetime) subM(dt2 datetime) int {
d := dt1.date.subM(dt2.date)
if d < 0 {
dd, dv := int(dt1.d())-int(dt2.d()), int(dt1.dv())-int(dt2.dv())
if dd > 0 || (dd == 0 && dv > 0) {
d++
}
}
return d
}
func (dt1 datetime) subY(dt2 datetime) int { return dt1.subM(dt2) / MonthPerYear }
func (dt datetime) f(f string, l *time.Location) string {
if !dt.valid() {
return "-"
}
return formatT(dt.t(l), f)
}
func (dt datetime) str(l *time.Location) string {
ft, fc := "y-m-d", formatP[dt.p()]
return dt.f(fmt.Sprintf("%s %s", ft, fc), l)
}
// DateTime représente une indication de temps (date + heure).
type DateTime struct {
datetime
location *time.Location
}
// DateTimeNil retourne un temps nul.
func DateTimeNil() (dt DateTime) { return }
func initDT0(d date, c clock, l *time.Location) DateTime { return initDT(newDT(d, c), l) }
func initDT(dt datetime, l *time.Location) DateTime {
if !dt.valid() {
return DateTimeNil()
}
return DateTime{dt, l}
}
// NewDateTime retourne un temps dans le fuseau horaire par défaut avec :
// - y, m, d : année, mois, jour
// - h, i : heure, minute,
// - args : seconde, puis milliseconde.
// La précision est calculée automatiquement suivant que la seconde et la milliseconde sont indiquées.
func NewDateTime(y int, m, d, h, i uint, args ...uint) DateTime {
return initDT0(newD(y, m, d), newC0(h, i, args...), DefaultTZ)
}
// NewDateTimeTZ agit comme NewDateTime mais dans le fuseau horaire tz.
func NewDateTimeTZ(tz string, y int, m, d, h, i uint, args ...uint) DateTime {
dt := NewDateTime(y, m, d, h, m, args...)
if dt.valid() {
dt.location = timezone(tz)
}
return dt
}
// NewDateTimeFromTime retourne le temps à partir dune date Go t.
// Si la précision p est fournie, cest la précision utilisée,
// sinon, cest la précision à la milliseconde.
func NewDateTimeFromTime(t time.Time, p ...Precision) DateTime {
var (
pp = PrecisionMillisecond
y, m, d = t.Date()
h, i, s = t.Clock()
v = t.Nanosecond() / NanosecondPerMillisecond
l = t.Location()
)
if len(p) > 0 {
pp = p[0]
}
return initDT0(newD(y, uint(m+1), uint(d)), newC(ms(uint(h), uint(i), uint(s), uint(v)), pp), l)
}
// DateTimeNow retourne le temps à la précision p. Si tz est renseignée,
// la date est placée dans le fuseau horaire indiqué.
func DateTimeNow(p Precision, tz ...string) DateTime {
return NewDateTimeFromTime(now(tz...), p)
}
// Now retourne le temps actuel avec la précision et le fuseau horaire de dt.
func (dt DateTime) Now() DateTime { return DateTimeNow(dt.p(), dt.location.String()) }
// DateTimeGuess retourne le temps à partir de e en essayant de deviner le format.
func DateTimeGuess(p Precision, e string, tz ...string) DateTime {
if t, ok := guess(e, tz...).Get(); ok {
return NewDateTimeFromTime(t, p)
}
return DateTimeNil()
}
// DateTimeParse retourne le temps à partir de e en spécifiant le format f.
func DateTimeParse(p Precision, e, f string, tz ...string) DateTime {
if t, ok := parse(e, f, tz...).Get(); ok {
return NewDateTimeFromTime(t, p)
}
return DateTimeNil()
}
// Precision retourne la précision de lheure.
func (dt DateTime) Precision() Precision { return dt.p() }
// IsNil retourne vrai si le temps est nul.
func (dt DateTime) IsNil() bool { return !dt.valid() }
// Year retourne lannée.
func (dt DateTime) Year() int { return dt.y() }
// Month retourne le mois.
func (dt DateTime) Month() uint { return dt.m() }
// Day retourne le jour.
func (dt DateTime) Day() uint { return dt.d() }
// Hour retourne lheure.
func (dt DateTime) Hour() uint { return dt.h() }
// Minute retourne la minute.
func (dt DateTime) Minute() uint { return dt.i() }
// Second retourne la seconde.
func (dt DateTime) Second() uint { return dt.s() }
// Milli retourne la milliseconde.
func (dt DateTime) Milli() uint { return dt.v() }
// Date retourne la partie date.
func (dt DateTime) Date() (y int, m, d uint) { return dt.y(), dt.m(), dt.d() }
// Clock retourne la partie horaire.
func (dt DateTime) Clock() (h, i, s, v uint) { return dt.h(), dt.i(), dt.s(), dt.m() }
// YearDay retourne le jour dans lannée (de 1 à 366).
func (dt DateTime) YeardDay() uint { return dt.yd() }
// WeekDay retourne le jour dans la semaine (de 0 à 6 en commençant par dimanche).
func (dt DateTime) WeekDay() uint { return dt.wd(dt.location) }
// IsBissextil retourne vrai si la date est dans une année bissextile.
func (dt DateTime) IsBissextile() bool { return dt.b() }
// DaysInYear retourne le nombre de jours dans lannée.
func (dt DateTime) DaysInYear() uint { return dt.yl() }
// DaysInMonth retourne le nombre de jours dans le mois.
func (dt DateTime) DaysInMonth() uint { return dt.ml() }
// DayMinute retourne le nombre de minutes écoulées dans la journée.
func (dt DateTime) DayMinute() uint { return dt.di() }
// DaySecond retourne le nombre de secondes écoulées dans la journée.
func (dt DateTime) DaySecond() uint { return dt.ds() }
// DayMilli retourne le nombre de millisecondes écoulées dans la journée.
func (dt DateTime) DayMilli() uint { return dt.dv() }
// ToDate convertit le temps en ne conservant que la partie date.
func (dt DateTime) ToDate() Date { return newDate(dt.date, dt.location) }
// ToClock convertit le temps en ne conservant que la partie heure.
func (dt DateTime) ToClock() Clock { return newClock(dt.clock, dt.location) }
// ToDateClock sépare la partie date et la partie heure.
func (dt DateTime) ToDateClock() (Date, Clock) { return dt.ToDate(), dt.ToClock() }
// SetYear modifie lannée, et facultativement, le mois, le jour, etc.
func (dt DateTime) SetYear(y int, args ...uint) DateTime {
return initDT(dt.setY(y, args...), dt.location)
}
// SetMonth modifie le mois et facultativement le jour, lheure, etc.
func (dt DateTime) SetMonth(m uint, args ...uint) DateTime {
return initDT(dt.setM(m, args...), dt.location)
}
// SetDay modifie le jour et facultativement lheure, la minute, etc..
func (dt DateTime) SetDay(d uint, args ...uint) DateTime {
return initDT(dt.setD(d, args...), dt.location)
}
// SetHour modifie lheure et facultativement la minute, la seconde, etc.
func (dt DateTime) SetHour(h uint, args ...uint) DateTime {
return initDT(dt.setH(h, args...), dt.location)
}
// SetMinute modifie la minute et facultativement la seconde et la milliseconde.
func (dt DateTime) SetMinute(i uint, args ...uint) DateTime {
return initDT(dt.setI(i, args...), dt.location)
}
// SetSecond modifie la seconde et facultativement la milliseconde.
func (dt DateTime) SetSecond(s uint, args ...uint) DateTime {
return initDT(dt.setS(s, args...), dt.location)
}
// SetMilli modifie la milliseconde.
func (dt DateTime) SetMilli(v uint) DateTime { return initDT(dt.setV(v), dt.location) }
// SetPrecision modifie la précision.
func (dt DateTime) SetPrecision(p Precision) DateTime { return initDT(dt.setP(p), dt.location) }
// Add incrémente lannée, le mois, le jour, lheure, la minute,
// et facultativement la seconde et la milliseconde.
func (dt DateTime) Add(y, m, d, h, i int, args ...int) DateTime {
return initDT(dt.add(y, m, d, h, i, args...), dt.location)
}
// AddDate incrémente lannée, le mois et le jour.
func (dt DateTime) AddDate(y, m, d int) DateTime { return initDT(dt.addT(y, m, d), dt.location) }
// AddClock incrémente lheure, la minute et facultativement la seconde et la milliseconde.
func (dt DateTime) AddClock(h, i int, args ...int) DateTime {
return initDT(dt.addC(h, i, args...), dt.location)
}
// AddYear incrémente lannée.
func (dt DateTime) AddYear(y int) DateTime { return initDT(dt.addY(y), dt.location) }
// AddMonth incrémente le mois.
func (dt DateTime) AddMonth(m int) DateTime { return initDT(dt.addM(m), dt.location) }
// AddWeek incrémente la semaine.
func (dt DateTime) AddWeek(w int) DateTime { return initDT(dt.addW(w), dt.location) }
// AddDay incrémente le jour.
func (dt DateTime) AddDay(d int) DateTime { return initDT(dt.addD(d), dt.location) }
// AddHour incrémente lheure.
func (dt DateTime) AddHour(h int) DateTime { return initDT(dt.addH(h), dt.location) }
// AddMinute incrémente la minute.
func (dt DateTime) AddMinute(i int) DateTime { return initDT(dt.addI(i), dt.location) }
// AddSecond incrémente la seconde.
func (dt DateTime) AddSecond(s int) DateTime { return initDT(dt.addS(s), dt.location) }
// AddMilli incrémente la milliseconde.
func (dt DateTime) AddMilli(v int) DateTime { return initDT(dt.addV(v), dt.location) }
// AddDuration incrémente une durée.
func (dt DateTime) AddDuration(dd Duration) DateTime { return initDT(dt.addDD(dd), dt.location) }
// BeginOfYear retourne le temps en début dannée au début du jour.
func (dt DateTime) BeginOfYear() DateTime { return initDT(dt.bY(), dt.location) }
// EndOfYear retourne le temps en fin dannée à la fin du jour.
func (dt DateTime) EndOfYear() DateTime { return initDT(dt.eY(), dt.location) }
// BeginOfMonth retourne le temps en début de mois au début du jour.
func (dt DateTime) BeginOfMonth() DateTime { return initDT(dt.bM(), dt.location) }
// EndOfMonth retourne le temps en fin de mois à la fin du jour.
func (dt DateTime) EndOfMonth() DateTime { return initDT(dt.eM(), dt.location) }
// BeginOfWeek retourne le temps en début de semaine au début du jour.
func (dt DateTime) BeginOfWeek() DateTime { return initDT(dt.bW(dt.location), dt.location) }
// EndOfWeek retourne le temps en fin de semaine à la fin du jour.
func (dt DateTime) EndOfWeek() DateTime { return initDT(dt.eW(dt.location), dt.location) }
// BeginOfDay retourne le temps en début de jour.
func (dt DateTime) BeginOfDay() DateTime { return initDT(dt.bD(), dt.location) }
// EndOfDay retourne le temps en fin de jour.
func (dt DateTime) EndOfDay() DateTime { return initDT(dt.eD(), dt.location) }
// BeginOfHour retourne le temps en début dheure.
func (dt DateTime) BeginOfHour() DateTime { return initDT(dt.bH(), dt.location) }
// EndOfHour retourne le temps en fin dheure.
func (dt DateTime) EndOfHour() DateTime { return initDT(dt.eH(), dt.location) }
// BeginOfMinute retourne le temps en début de minute.
func (dt DateTime) BeginOfMinute() DateTime { return initDT(dt.bI(), dt.location) }
// EndOfMinute retourne le temps en fin de minute.
func (dt DateTime) EndOfMinute() DateTime { return initDT(dt.eI(), dt.location) }
// BeginOfSecond retourne le temps en début de seconde.
func (dt DateTime) BeginOfSecond() DateTime { return initDT(dt.bS(), dt.location) }
// EndOfSecond retourne le temps en fin de seconde.
func (dt DateTime) EndOfSecond() DateTime { return initDT(dt.eS(), dt.location) }
// ToTime retourne le temps dans le fuseau horaire indiqué.
func (dt DateTime) ToTime() time.Time { return dt.t(dt.location) }
// In retourne le temps dans le fuseau horaire indiqué.
func (dt DateTime) In(l *time.Location) DateTime {
if dt.IsNil() {
return DateTimeNil()
}
return NewDateTimeFromTime(dt.ToTime().In(l), dt.p())
}
// InTZ agit comme In mais en fournissant le fuseau horaire sous forme
// de chaîne de caractères.
func (dt DateTime) InTZ(tz string) DateTime { return dt.In(timezone(tz)) }
// TZ retourne le fuseau horaire.
func (dt DateTime) TZ() *time.Location { return dt.location }
// IsDST retourne vrai si le fuseau horaire est à lheure dété.
func (dt DateTime) IsDST() bool { return dt.dst(dt.location) }
// Timestamp retourne le timestamp en secondes.
func (dt DateTime) TimeStamp() int64 { return dt.ts(dt.location) }
// TimestampMilli retourne le timestamp en millisecondes.
func (dt DateTime) TimeStampMilli() int64 { return dt.tv(dt.location) }
// Compare compare 2 temps après normalisation du fuseau horaire et de la précision.
func (dt1 DateTime) Compare(dt2 DateTime) int { return dt1.cmp(dt2.datetime) }
func (dt1 DateTime) Eq(dt2 DateTime) bool { return dt1.Compare(dt2) == 0 }
func (dt1 DateTime) Ne(dt2 DateTime) bool { return dt1.Compare(dt2) != 0 }
func (dt1 DateTime) Gt(dt2 DateTime) bool { return dt1.Compare(dt2) > 0 }
func (dt1 DateTime) Ge(dt2 DateTime) bool { return dt1.Compare(dt2) >= 0 }
func (dt1 DateTime) Lt(dt2 DateTime) bool { return dt1.Compare(dt2) < 0 }
func (dt1 DateTime) Le(dt2 DateTime) bool { return dt1.Compare(dt2) <= 0 }
// IsNow retourne vrai si le temps est le temps actuel.
func (dt DateTime) IsNow() bool { return dt.Eq(dt.Now()) }
// IsPast retourne vrai si le temps est situé dans le passé.
func (dt DateTime) IsPast() bool { return dt.Lt(dt.Now()) }
// IsPast retourne vrai si le temps est situé dans le futur.
func (dt DateTime) IsFuture() bool { return dt.Gt(dt.Now()) }
// DiffInMills retourne dt1 - dt2 en millisecondes.
func (dt1 DateTime) DiffInMillis(dt2 DateTime) int {
return dt1.subV(dt2.datetime, dt1.location, dt2.location)
}
// DiffInSeconds retourne dt1 - dt2 en secondes.
func (dt1 DateTime) DiffInSeconds(dt2 DateTime) int {
return dt1.subS(dt2.datetime, dt1.location, dt2.location)
}
// DiffInMinutes retourne dt1 - dt2 en minutes.
func (dt1 DateTime) DiffInMinutes(dt2 DateTime) int {
return dt1.subI(dt2.datetime, dt1.location, dt2.location)
}
// DiffInHours retourne dt1 - dt2 en heures.
func (dt1 DateTime) DiffInHours(dt2 DateTime) int {
return dt1.subH(dt2.datetime, dt1.location, dt2.location)
}
// DiffInDays retourne dt1 - dt2 en jours.
func (dt1 DateTime) DiffInDays(dt2 DateTime) int {
return dt1.subD(dt2.datetime, dt1.location, dt2.location)
}
// DiffInWeeks retourne dt1 - dt2 en semaines.
func (dt1 DateTime) DiffInWeeks(dt2 DateTime) int {
return dt1.subW(dt2.datetime, dt1.location, dt2.location)
}
// DiffInMonths retourne dt1 - dt2 en mois.
func (dt1 DateTime) DiffInMonths(dt2 DateTime) int { return dt1.subM(dt2.datetime) }
// DiffInYears retourn dt1 - dt2 en années.
func (dt1 DateTime) DiffInYears(dt2 DateTime) int { return dt1.subY(dt2.datetime) }
// Format retourne une représentation du temps au format spécifié.
func (dt DateTime) Format(f string) string { return dt.f(f, dt.location) }
// String retourne une représentation du temps au format 'Y-m-d H:iT',
// 'Y-m-d H:i:sT' ou 'Y-m-d H:i:s.vT' suivant la précision.
func (dt DateTime) String() string { return dt.str(dt.location) }