package datetime import ( "time" ) type clock uint // Precision représente la précision d’une horloge. type Precision uint func newC0(h, i uint, e ...uint) clock { h, i, s, v, p := formatC(h, i, e...) return newC(ms(h, i, s, v), p) } func newC(n uint, p Precision) clock { switch p { case PrecisionMillisecond: case PrecisionSecond: n -= n % MillisecondPerSecond case PrecisionMinute: n -= n % MillisecondPerMinute default: return clockNil } if n > maxClock { return clockNil } return clock(n< NoPrecision && c.dv() <= maxClock } func (c clock) dv() uint { return uint(c >> bitsPrecision) } func (c clock) ds() uint { return c.dv() / MillisecondPerSecond } func (c clock) di() uint { return c.dv() / MillisecondPerMinute } func (c clock) v() uint { return c.dv() % MillisecondPerSecond } func (c clock) s() uint { return c.ds() % SecondPerMinute } func (c clock) i() uint { return c.di() % MinutePerHour } func (c clock) h() uint { return c.dv() / MillisecondPerHour } func (c clock) t(l *time.Location) (t time.Time) { if !c.valid() { return } return fromT(c.h(), c.i(), c.s(), c.v(), l) } func (c clock) dst(l *time.Location) bool { return c.t(l).IsDST() } func (c clock) ts(l *time.Location) int64 { return c.t(l).Unix() } func (c clock) tv(l *time.Location) int64 { return c.t(l).UnixMilli() } func (c clock) _setV(e, v uint, p Precision) (v2 uint, p2 Precision) { if e >= MillisecondPerSecond || p == NoPrecision { return } return v + e - c.v(), PrecisionMillisecond } func (c clock) _setS(e, v uint, p Precision) (v2 uint, p2 Precision) { if e >= SecondPerMinute || p == NoPrecision { return } return v + e*MillisecondPerSecond - c.s()*MillisecondPerSecond, min(p, PrecisionSecond) } func (c clock) _setI(e, v uint, p Precision) (v2 uint, p2 Precision) { if e >= MinutePerHour || p == NoPrecision { return } return v + e*MillisecondPerMinute - c.i()*MillisecondPerMinute, min(p, PrecisionMinute) } func (c clock) _setH(e, v uint, p Precision) (v2 uint, p2 Precision) { if e >= HourPerDay || p == NoPrecision { return } return v + e*MillisecondPerHour - c.h()*MillisecondPerHour, min(p, PrecisionMinute) } func (c clock) setV(v uint) clock { v, p := c._setV(v, c.dv(), c.p()) return newC(v, p) } func (c clock) setS(s uint, e ...uint) clock { v, p := c._setS(s, c.dv(), c.p()) if len(e) > 0 { v, p = c._setV(e[0], v, p) } return newC(v, p) } func (c clock) setI(i uint, e ...uint) clock { v, p := c._setI(i, c.dv(), c.p()) if len(e) > 0 { i, p = c._setS(e[0], v, p) if len(e) > 1 { i, p = c._setV(e[1], v, p) } } return newC(v, p) } func (c clock) setH(h uint, e ...uint) clock { v, p := c._setH(h, c.dv(), c.p()) if len(e) > 0 { v, p = c._setI(e[0], v, p) if len(e) > 1 { v, p = c._setS(e[1], v, p) if len(e) > 2 { v, p = c._setV(e[2], v, p) } } } return newC(v, p) } func (c clock) setP(p Precision) clock { return newC(c.dv(), p) } func (c clock) add(h, i int, e ...int) clock { if !c.valid() { return c } r, v, p := h*MillisecondPerHour+i*MillisecondPerMinute, c.dv(), c.p() if len(e) > 0 { r, p = r+e[0]*MillisecondPerSecond, min(p, PrecisionSecond) if len(e) > 1 { r, p = r+e[1], PrecisionMillisecond } } switch { case r >= 0: v += uint(r) case int(v)+r >= 0: v -= uint(abs(r)) default: return clockNil } return newC(v, p) } func (c clock) addH(h int) clock { return c.add(h, 0) } func (c clock) addI(i int) clock { return c.add(0, i) } func (c clock) addS(s int) clock { return c.add(0, 0, s) } func (c clock) addV(n int) clock { return c.add(0, 0, 0, n) } func (c clock) addDD(d Duration) clock { e, u := d.Duration() switch u { case Millisecond: return c.add(0, 0, 0, e) case Second: return c.add(0, 0, e) case Minute: return c.add(0, e) case Hour: return c.add(e, 0) default: return c } } func (c clock) bD() clock { return newC(minClock, c.p()) } func (c clock) eD() clock { return newC(maxClock, c.p()) } func (c clock) bH() clock { return c.setI(0, beginPrecisionS[c.p()]...) } func (c clock) eH() clock { return c.setI(59, endPrecisionS[c.p()]...) } func (c clock) bI() clock { return c.setS(0, beginPrecisionM[c.p()]...) } func (c clock) eI() clock { return c.setS(59, endPrecisionM[c.p()]...) } func (c clock) bS() clock { return c.setV(0) } func (c clock) eS() clock { return c.setV(999) } func (c1 clock) cmp(c2 clock) int { if !c1.valid() { if !c2.valid() { return 0 } return -1 } if !c2.valid() { return 1 } p := max(c1.p(), c2.p()) c1, c2 = c1.setP(p), c2.setP(p) return cmp(c1.dv(), c2.dv()) } func (c1 clock) subV(c2 clock) int { return int(c1.dv()) - int(c2.dv()) } func (c1 clock) subS(c2 clock) int { return c1.subV(c2) / MillisecondPerSecond } func (c1 clock) subI(c2 clock) int { return c1.subV(c2) / MillisecondPerMinute } func (c1 Clock) subH(c2 clock) int { return c1.subV(c2) / MillisecondPerHour } func (c clock) f(f string, l *time.Location) string { if !c.valid() { return "-" } return formatT(c.t(l), f) } func (c clock) str(l *time.Location) string { return c.f(formatP[c.p()], l) } // Clock représente une indication de temps dans la journée. type Clock struct { clock location *time.Location } // ClockNil retourne une horloge nulle. func ClockNil() (c Clock) { return } func newClock(c clock, l *time.Location) Clock { if c.valid() { return Clock{ clock: c, location: l, } } return ClockNil() } func setClock(v uint, p Precision, l *time.Location) Clock { return newClock(newC(v, p), l) } // NewClock retourne une horloge dans le fuseau horaire par défaut. // La précision est calculée automatiquement suivant que la seconde et la milliseconde sont indiquées. func NewClock(h uint, i uint, args ...uint) Clock { return newClock(newC0(h, i, args...), DefaultTZ) } // NewClockTZ agit comme NewClock mais dans le fuseau horaire tz. func NewClockTZ(tz string, h uint, i uint, args ...uint) Clock { c := NewClock(h, i, args...) if c.valid() { c.location = timezone(tz) } return c } // NewClockFromTime retourne l’heure à partir d’une date Go. func NewClockFromTime(t time.Time, p ...Precision) Clock { var ( pp = PrecisionMillisecond h, i, s = t.Clock() v = t.Nanosecond() / int(time.Millisecond) l = t.Location() ) if len(p) > 0 { pp = p[0] } return setClock(ms(uint(h), uint(i), uint(s), uint(v)), pp, l) } // ClockNow retourne l’heure actuelle. Si tz est renseignée, // l’heure est placée dans le fuseau horaire indiqué. func ClockNow(p Precision, tz ...string) Clock { return NewClockFromTime(now(tz...), p) } func (c Clock) Now() Clock { return ClockNow(c.p(), c.location.String()) } // ClockGuess retourne l’heure à partir de e en essayant de deviner le format. func ClockGuess(p Precision, e string, tz ...string) Clock { if t, ok := guess(e, tz...).Get(); ok { return NewClockFromTime(t, p) } return ClockNil() } // ClockParse retourne l’heure à partir de e en spécifiant le format f. func ClockParse(p Precision, e, f string, tz ...string) Clock { if t, ok := parse(e, f).Get(); ok { return NewClockFromTime(t, p) } return ClockNil() } // Precision retourne la précision de l’horloge. func (c Clock) Precision() Precision { return c.p() } // IsNil retourne vrai si l’horloge est nulle. func (c Clock) IsNil() bool { return !c.valid() } // DayMilli retourne le nombre de millisecondes écoulées dans le jour. func (c Clock) DayMilli() uint { return c.dv() } // DaySecond retourne le nombre de secondes écoulées dans le jour. func (c Clock) DaySecond() uint { return c.ds() } // DayMinute retourne le nombre de minutes écoulées dans le jour. func (c Clock) DayMinute() uint { return c.di() } // Milli retourne la milliseconde dans la seconde. func (c Clock) Milli() uint { return c.v() } // Second retourne la seconde de la minute. func (c Clock) Second() uint { return c.s() } // Minute retourne la minute de l’heure. func (c Clock) Minute() uint { return c.i() } // Hour retourne l’heure du jour. func (c Clock) Hour() uint { return c.h() } // Clock retourne l’heure, la minute, la seconde et la milliseconde. func (c Clock) Clock() (h, i, s, v uint) { return c.h(), c.i(), c.s(), c.v() } // SetMilli modifie la milliseconde. func (c Clock) SetMilli(v uint) Clock { return newClock(c.setV(v), c.location) } // SetSecond modifie la seconde. func (c Clock) SetSecond(s uint, v ...uint) Clock { return newClock(c.setS(s, v...), c.location) } // SetMinute modifie la minute. func (c Clock) SetMinute(i uint, args ...uint) Clock { return newClock(c.setI(i, args...), c.location) } // SetHour modifie l’heure. func (c Clock) SetHour(h uint, args ...uint) Clock { return newClock(c.setH(h, args...), c.location) } // SetPrecision modifie la précision. func (c Clock) SetPrecision(p Precision) Clock { return newClock(c.setP(p), c.location) } // Add ajoute un nombre d’heures et de minutes, et, facultativement, // de secondes et de millisecondes. func (c Clock) Add(h, i int, args ...int) Clock { return newClock(c.add(h, i, args...), c.location) } // AddHour ajoute une durée en heures. func (c Clock) AddHour(h int) Clock { return newClock(c.addH(h), c.location) } // AddMinute ajoute une durée en minutes. func (c Clock) AddMinute(i int) Clock { return newClock(c.addI(i), c.location) } // AddSecond ajoute une durée en secondes. func (c Clock) AddSecond(s int) Clock { return newClock(c.addS(s), c.location) } // AddMilli ajoute une durée en ms. func (c Clock) AddMilli(v int) Clock { return newClock(c.addV(v), c.location) } // AddDuration ajoute une durée. func (c Clock) AddDuration(dd Duration) Clock { return newClock(c.addDD(dd), c.location) } // BeginOfDay retourne le début de la journée, en gardant la précision. func (c Clock) BeginOfDay() Clock { return newClock(c.bD(), c.location) } // EndOfDay retourne la fin de la journée, en gardant la précision. func (c Clock) EndOfDay() Clock { return newClock(c.eD(), c.location) } // BeginOfHour retourne le début de l’heure en cours. func (c Clock) BeginOfHour() Clock { return newClock(c.bH(), c.location) } // EndOfHour retourne la fin de l’heure en cours. func (c Clock) EndOfHour() Clock { return newClock(c.eH(), c.location) } // BeginOfMinute retourne le début de la minute en cours. func (c Clock) BeginOfMinute() Clock { return newClock(c.bI(), c.location) } // EndOfMinute retourne la fin de la minute en cours. func (c Clock) EndOfMinute() Clock { return newClock(c.eI(), c.location) } // BeginOfSecond retourne le début de la seconde en cours. func (c Clock) BeginOfSecond() Clock { return newClock(c.bS(), c.location) } // EndOfSecond retourne la fin de la seconde en cours. func (c Clock) EndOfSecond() Clock { return newClock(c.eS(), c.location) } // ToTime convertit l’heure en date de type time.Time. func (c Clock) ToTime() time.Time { return c.t(c.location) } // In retourne l’heure dans le fuseau horaire indiqué. func (c Clock) In(l *time.Location) Clock { if c.IsNil() { return c } return NewClockFromTime(c.ToTime().In(l)) } // ToTimezone retourne l’heure dans le fuseau horaire indiqué. func (c Clock) ToTimezone(tz string) Clock { return c.In(timezone(tz)) } // Location retourne le fuseau horaire. func (c Clock) Location() *time.Location { return c.location } // IsDST retourne vrai si le fuseau horaire est à l’heure d’été. func (c Clock) IsDST() bool { return c.dst(c.location) } // Timestamp retourne le timestamp en secondes. func (c Clock) Timestamp() int64 { return c.ts(c.location) } // TimestampMilli retourne le timestamp en secondes. func (c Clock) TimestampMilli() int64 { return c.tv(c.location) } // Compare retourne : // - 1 si c1 est dans le futur de c2 // - -1 si c1 est dans le passé de c2 // - 0 si c1 = c2. // La comparaison s’effectue après normalisation (ie. même fuseau horaire et même précision). func (c1 Clock) Compare(c2 Clock) int { return c1.cmp(c2.In(c1.location).clock) } func (c1 Clock) Eq(c2 Clock) bool { return c1.Compare(c2) == 0 } func (c1 Clock) Ne(c2 Clock) bool { return c1.Compare(c2) != 0 } func (c1 Clock) Gt(c2 Clock) bool { return c1.Compare(c2) > 0 } func (c1 Clock) Ge(c2 Clock) bool { return c1.Compare(c2) >= 0 } func (c1 Clock) Lt(c2 Clock) bool { return c1.Compare(c2) < 0 } func (c1 Clock) Le(c2 Clock) bool { return c1.Compare(c2) <= 0 } func (c Clock) IsNow() bool { return c.Eq(c.Now()) } func (c Clock) IsPast() bool { return c.Lt(c.Now()) } func (c Clock) IsFuture() bool { return c.Gt(c.Now()) } func (c1 Clock) DiffInMillis(c2 Clock) int { return c1.subV(c2.clock) } func (c1 Clock) DiffInSeconds(c2 Clock) int { return c1.subS(c2.clock) } func (c1 Clock) DiffInMinutes(c2 Clock) int { return c1.subI(c2.clock) } func (c1 Clock) DiffInHours(c2 Clock) int { return c1.subH(c2.clock) } // Format retourne une représentation de l’heure au format spécifié. func (c Clock) Format(format string) string { return c.f(format, c.location) } // String retourne une représentation au format H:iT, H:i:sT ou H:i:s.vT suivant la précision. func (c Clock) String() string { return c.str(c.location) }