gob/datetime/clock.go

440 lines
14 KiB
Go
Raw Normal View History

2023-11-03 19:33:26 +00:00
package datetime
import (
"time"
)
type clock uint
// Precision représente la précision dune horloge.
// Par exemple :
// - 15:06 est une horloge précise à la minute,
// - 15:06:02 est précise à la seconde,
// - 15:06:02.257 est précise à la milliseconde.
//
// La précision est utilisée dans Clock pour les comparaisons :
// les comparaisons entre deux horloges se font à la précision
// le lhorloge la moins précise.
2023-11-03 19:33:26 +00:00
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<<bitsPrecision) | clock(p&maskPrecision)
}
func (c clock) p() Precision { return Precision(c & maskPrecision) }
func (c clock) valid() bool { return c.p() > 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 à lheure h et la minute i dans le fuseau horaire par défaut.
// La précision est calculée automatiquement suivant que la seconde et la milliseconde sont également
// présentes dans args.
2023-11-03 19:33:26 +00:00
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.
// tz peut être mis sous la forme "Europe/Paris", "CET", "Local", etc.
2023-11-03 19:33:26 +00:00
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 lheure à partir dune date Go t.
// Si la précision p nest pas définie, cest une précision à la ms.
2023-11-03 19:33:26 +00:00
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 lheure actuelle avec une précision p. Si tz est renseignée,
2023-11-03 19:33:26 +00:00
// lheure est placée dans le fuseau horaire indiqué.
func ClockNow(p Precision, tz ...string) Clock {
return NewClockFromTime(now(tz...), p)
}
// Now retourne lheure actuelle avec la même précision et le même fuseau horaire que c.
2023-11-03 19:33:26 +00:00
func (c Clock) Now() Clock { return ClockNow(c.p(), c.location.String()) }
// ClockGuess retourne lheure à partir de e et à la précision p en essayant de deviner le format.
2023-11-03 19:33:26 +00:00
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 lheure à partir de e et à la précision p en spécifiant le format f.
2023-11-03 19:33:26 +00:00
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 lhorloge.
func (c Clock) Precision() Precision { return c.p() }
// IsNil retourne vrai si lhorloge 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 lheure.
func (c Clock) Minute() uint { return c.i() }
// Hour retourne lheure du jour.
func (c Clock) Hour() uint { return c.h() }
// Clock retourne lheure, 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 de la seconde.
2023-11-03 19:33:26 +00:00
func (c Clock) SetMilli(v uint) Clock { return newClock(c.setV(v), c.location) }
// SetSecond modifie la seconde de la minute, et la milliseconde, si v est renseignée.
2023-11-03 19:33:26 +00:00
func (c Clock) SetSecond(s uint, v ...uint) Clock { return newClock(c.setS(s, v...), c.location) }
// SetMinute modifie la minute de lheure, ainsi que la seconde et la millisecondes si elles sont renseignées.
2023-11-03 19:33:26 +00:00
func (c Clock) SetMinute(i uint, args ...uint) Clock { return newClock(c.setI(i, args...), c.location) }
// SetHour modifie lheure et, facultativement, la minute, la seconde et la milliseconde.
2023-11-03 19:33:26 +00:00
func (c Clock) SetHour(h uint, args ...uint) Clock { return newClock(c.setH(h, args...), c.location) }
// SetPrecision retourne lhorloge avec la précision p.
2023-11-03 19:33:26 +00:00
func (c Clock) SetPrecision(p Precision) Clock { return newClock(c.setP(p), c.location) }
// Add ajoute un nombre dheures 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 millisecondes.
2023-11-03 19:33:26 +00:00
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 lheure en cours.
func (c Clock) BeginOfHour() Clock { return newClock(c.bH(), c.location) }
// EndOfHour retourne la fin de lheure 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 lheure en date de type time.Time.
func (c Clock) ToTime() time.Time { return c.t(c.location) }
// In retourne lheure dans le fuseau horaire indiqué.
func (c Clock) In(l *time.Location) Clock {
if c.IsNil() {
return c
}
return NewClockFromTime(c.ToTime().In(l))
}
// InTZ agit comme In mais en fournissant le fuseau horaire sous forme
// de chaîne de caractères.
func (c Clock) inTZ(tz string) Clock { return c.In(timezone(tz)) }
2023-11-03 19:33:26 +00:00
// TZ retourne le fuseau horaire.
func (c Clock) TZ() *time.Location { return c.location }
2023-11-03 19:33:26 +00:00
// IsDST retourne vrai si le fuseau horaire est à lheure 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 seffectue 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 }
// IsNow retourne vrai si lhorloge est à lheure actuelle.
func (c Clock) IsNow() bool { return c.Eq(c.Now()) }
// IsPast retourne vrai si lhorloge est située dans le passé.
func (c Clock) IsPast() bool { return c.Lt(c.Now()) }
// IsFuture retourne vrai si lhorloge est située dans le futur.
2023-11-03 19:33:26 +00:00
func (c Clock) IsFuture() bool { return c.Gt(c.Now()) }
// DiffInMillis retourne c1 - c2 en millisecondes.
func (c1 Clock) DiffInMillis(c2 Clock) int { return c1.subV(c2.clock) }
// DiffInSeconds retourne c1 - c2 en secondes.
2023-11-03 19:33:26 +00:00
func (c1 Clock) DiffInSeconds(c2 Clock) int { return c1.subS(c2.clock) }
// DiffInMinutes retourne c1 - c2 en minutes.
2023-11-03 19:33:26 +00:00
func (c1 Clock) DiffInMinutes(c2 Clock) int { return c1.subI(c2.clock) }
// DiffInHours retourne c1 - c2 en heures.
func (c1 Clock) DiffInHours(c2 Clock) int { return c1.subH(c2.clock) }
2023-11-03 19:33:26 +00:00
// Format retourne une représentation de lheure 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) }