gob/datetime/clock.go

415 lines
13 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.
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 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 lheure à partir dune 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 lheure actuelle. 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)
}
func (c Clock) Now() Clock { return ClockNow(c.p(), c.location.String()) }
// ClockGuess retourne lheure à 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 lheure à 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 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.
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 lheure.
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 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 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 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))
}
// ToTimezone retourne lheure 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 à 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 }
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 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) }