gob/datetime/clock.go

440 lines
14 KiB
Go
Raw 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 (
"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.
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.
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.
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.
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,
// 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.
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.
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.
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.
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.
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.
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.
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.
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.
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)) }
// TZ retourne le fuseau horaire.
func (c Clock) TZ() *time.Location { return c.location }
// 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.
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.
func (c1 Clock) DiffInSeconds(c2 Clock) int { return c1.subS(c2.clock) }
// DiffInMinutes retourne c1 - c2 en minutes.
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) }
// 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) }