package datetime import ( "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 { return dt.f("Y-m-d", 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 d’une date Go t. // Si la précision p est fournie, c’est la précision utilisée, // sinon, c’est 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 l’heure. 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 l’anné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 l’heure. 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 l’anné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 l’anné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 l’anné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, l’heure, etc. func (dt DateTime) SetMonth(m uint, args ...uint) DateTime { return initDT(dt.setM(m, args...), dt.location) } // SetDay modifie le jour et facultativement l’heure, la minute, etc.. func (dt DateTime) SetDay(d uint, args ...uint) DateTime { return initDT(dt.setD(d, args...), dt.location) } // SetHour modifie l’heure 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 l’année, le mois, le jour, l’heure, 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 l’anné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 l’heure, 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 l’anné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 l’heure. 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 d’année au début du jour. func (dt DateTime) BeginOfYear() DateTime { return initDT(dt.bY(), dt.location) } // EndOfYear retourne le temps en fin d’anné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 d’heure. func (dt DateTime) BeginOfHour() DateTime { return initDT(dt.bH(), dt.location) } // EndOfHour retourne le temps en fin d’heure. 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 à l’heure 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) }