Module datetime réécrit
This commit is contained in:
parent
0700fced7b
commit
41e37d8398
|
@ -0,0 +1,414 @@
|
||||||
|
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<<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 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) }
|
|
@ -1,78 +0,0 @@
|
||||||
package datetime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/tools/go/analysis/passes/bools"
|
|
||||||
)
|
|
||||||
|
|
||||||
// IsZero retourne vrai si la date représente le 01/01/0001 à 00:00 UTC.
|
|
||||||
func IsZero(t time.Time) bool {
|
|
||||||
return t.IsZero()
|
|
||||||
}
|
|
||||||
|
|
||||||
// Compare retourne :
|
|
||||||
// - 1 si t1 est dans le futur de t2,
|
|
||||||
// - 0 si t1 et t2 sont égaux,
|
|
||||||
// - -1 sinon.
|
|
||||||
func Compare(t1, t2 time.Time) int {
|
|
||||||
u1, u2 := t1.Unix(), t2.Unix()
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case u1 == u2:
|
|
||||||
return 0
|
|
||||||
case u1 > u2:
|
|
||||||
return 1
|
|
||||||
default:
|
|
||||||
return -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Eq retourne vrai si t1 = t2.
|
|
||||||
func Eq(t1, t2 time.Time) bool { return Compare(t1, t2) == 0 }
|
|
||||||
|
|
||||||
// Ne retourne vrai si t1 ≠ t2.
|
|
||||||
func Ne(t1, t2 time.Time) bool { return Compare(t1, t2) != 0 }
|
|
||||||
|
|
||||||
// Gt retourne vrai si t1 > t2.
|
|
||||||
func Gt(t1, t2 time.Time) bool { return Compare(t1, t2) > 0 }
|
|
||||||
|
|
||||||
// Ge retourne vrai si t1 ≥ t2.
|
|
||||||
func Ge(t1, t2 time.Time) bool { return Compare(t1, t2) >= 0 }
|
|
||||||
|
|
||||||
// Lt retourne vrai si t1 < t2.
|
|
||||||
func Lt(t1, t2 time.Time) bool { return Compare(t1, t2) < 0 }
|
|
||||||
|
|
||||||
// Le retourne vrai si t1 ≤ t2.
|
|
||||||
func Le(t1, t2 time.Time) bool { return Compare(t1, t2) <= 0 }
|
|
||||||
|
|
||||||
// Min retourne la date la plus située dans le passé.
|
|
||||||
func Min(t time.Time, times ...time.Time) time.Time {
|
|
||||||
for _, tt := range times {
|
|
||||||
if Lt(tt, t) {
|
|
||||||
t = tt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// Max retourne la date la plus située dans le futur.
|
|
||||||
func Max(t time.Time, times ...time.Time) time.Time {
|
|
||||||
for _, tt := range times {
|
|
||||||
if Gt(tt, t) {
|
|
||||||
t = tt
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsNow retourne vrai si la date est actuelle.
|
|
||||||
func IsNow(t time.Time) bool { return Eq(t, time.Now()) }
|
|
||||||
|
|
||||||
// IsPast retourne vrai si la date est située dans le passé.
|
|
||||||
func IsPast(t time.Time) bool { return Lt(t, time.Now()) }
|
|
||||||
|
|
||||||
// IsFuture retourne vrai si la date est située dans le future.
|
|
||||||
func IsFuture(t time.Time) bool { return Gt(t, time.Now()) }
|
|
|
@ -4,9 +4,229 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Conversions d’unités.
|
||||||
|
NanosecondPerMicrosecond = 1000
|
||||||
|
MicrosecondPerMillisecond = 1000
|
||||||
|
MillisecondPerSecond = 1000
|
||||||
|
SecondPerMinute = 60
|
||||||
|
MinutePerHour = 60
|
||||||
|
HourPerDay = 24
|
||||||
|
DayPerWeek = 7
|
||||||
|
MonthPerYear = 12
|
||||||
|
BeatPerDay = 1000
|
||||||
|
|
||||||
|
HourPerWeek = HourPerDay * DayPerWeek
|
||||||
|
MinutePerDay = MinutePerHour * HourPerDay
|
||||||
|
MinutePerWeek = MinutePerHour * HourPerWeek
|
||||||
|
SecondPerHour = SecondPerMinute * MinutePerHour
|
||||||
|
SecondPerDay = SecondPerMinute * MinutePerDay
|
||||||
|
SecondPerWeek = SecondPerMinute * MinutePerWeek
|
||||||
|
MillisecondPerMinute = MillisecondPerSecond * SecondPerMinute
|
||||||
|
MillisecondPerHour = MillisecondPerSecond * SecondPerHour
|
||||||
|
MillisecondPerDay = MillisecondPerSecond * SecondPerDay
|
||||||
|
MillisecondPerWeek = MillisecondPerSecond * SecondPerWeek
|
||||||
|
MicrosecondPerSecond = MicrosecondPerMillisecond * MillisecondPerSecond
|
||||||
|
NanosecondPerMillisecond = NanosecondPerMicrosecond * MicrosecondPerMillisecond
|
||||||
|
NanosecondPerSecond = NanosecondPerMicrosecond * MicrosecondPerSecond
|
||||||
|
|
||||||
|
// Unités supportées
|
||||||
|
NoUnit Unit = iota
|
||||||
|
Millisecond
|
||||||
|
Second
|
||||||
|
Minute
|
||||||
|
Hour
|
||||||
|
Day
|
||||||
|
Week
|
||||||
|
Month
|
||||||
|
Year
|
||||||
|
|
||||||
|
// Durée nulle
|
||||||
|
DurationNil = Duration(0)
|
||||||
|
|
||||||
|
bitsUnit = Duration(4)
|
||||||
|
bitsValue = 64 - bitsUnit
|
||||||
|
|
||||||
|
maskUnit = 1<<bitsUnit - 1
|
||||||
|
maskValue = ^maskUnit
|
||||||
|
|
||||||
|
// Précisions supportées
|
||||||
|
NoPrecision Precision = iota
|
||||||
|
PrecisionMillisecond
|
||||||
|
PrecisionSecond
|
||||||
|
PrecisionMinute
|
||||||
|
|
||||||
|
bitsPrecision = uint32(2)
|
||||||
|
maskPrecision = 1<<bitsPrecision - 1
|
||||||
|
maskMillisecond = ^maskPrecision
|
||||||
|
|
||||||
|
minClock = uint(0)
|
||||||
|
maxClock = uint(MillisecondPerDay - 1)
|
||||||
|
|
||||||
|
clockNil = clock(0)
|
||||||
|
|
||||||
|
bitsDay = 5
|
||||||
|
bitsMonth = 4
|
||||||
|
|
||||||
|
shiftDay = date(0)
|
||||||
|
shiftMonth = date(bitsDay)
|
||||||
|
shiftYear = date(bitsDay + bitsMonth)
|
||||||
|
|
||||||
|
maskDay = 1<<bitsDay - 1
|
||||||
|
maskMonth = (1<<bitsMonth - 1) << shiftMonth
|
||||||
|
maskYear = ^(maskDay | maskMonth)
|
||||||
|
|
||||||
|
dateNil = date(0)
|
||||||
|
|
||||||
|
// Mois
|
||||||
|
January = uint(1) + iota
|
||||||
|
February
|
||||||
|
March
|
||||||
|
April
|
||||||
|
May
|
||||||
|
June
|
||||||
|
July
|
||||||
|
August
|
||||||
|
September
|
||||||
|
October
|
||||||
|
November
|
||||||
|
December
|
||||||
|
|
||||||
|
// Jours de la semaine
|
||||||
|
Sunday = uint(iota)
|
||||||
|
Monday
|
||||||
|
Tuesday
|
||||||
|
Wednesday
|
||||||
|
Thursday
|
||||||
|
Friday
|
||||||
|
Saturday
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// Fuseau horaire par défaut
|
// représentation de l’unité sous forme de caractère
|
||||||
DefaultTZ = time.Local
|
unitToByte = map[Unit]byte{
|
||||||
|
NoUnit: 0,
|
||||||
|
Millisecond: 'N',
|
||||||
|
Second: 'S',
|
||||||
|
Minute: 'M',
|
||||||
|
Hour: 'H',
|
||||||
|
Day: 'd',
|
||||||
|
Week: 'w',
|
||||||
|
Month: 'm',
|
||||||
|
Year: 'y',
|
||||||
|
}
|
||||||
|
|
||||||
|
maskDate = map[string]date{
|
||||||
|
"d": maskDay,
|
||||||
|
"m": maskMonth,
|
||||||
|
"y": maskYear,
|
||||||
|
}
|
||||||
|
shiftDate = map[string]date{
|
||||||
|
"d": shiftDay,
|
||||||
|
"m": shiftMonth,
|
||||||
|
"y": shiftYear,
|
||||||
|
}
|
||||||
|
|
||||||
|
beginPrecisionM = map[Precision][]uint{
|
||||||
|
PrecisionMillisecond: []uint{0},
|
||||||
|
}
|
||||||
|
endPrecisionM = map[Precision][]uint{
|
||||||
|
PrecisionMillisecond: []uint{999},
|
||||||
|
}
|
||||||
|
beginPrecisionS = map[Precision][]uint{
|
||||||
|
PrecisionSecond: []uint{0},
|
||||||
|
PrecisionMillisecond: []uint{0, 0},
|
||||||
|
}
|
||||||
|
endPrecisionS = map[Precision][]uint{
|
||||||
|
PrecisionSecond: []uint{999},
|
||||||
|
PrecisionMillisecond: []uint{59, 999},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Layouts de base pour le parsage des dates
|
||||||
|
layouts = []string{
|
||||||
|
"Mon, Jan 2, 2006 3:04 PM",
|
||||||
|
"2006-01-02 15:04:05", "2006-01-02 15:04:05.999", "20060102150405", "20060102150405.999",
|
||||||
|
"2006-01-02", "2006-01-02.999", "20060102", "20060102.999",
|
||||||
|
// ISO8601
|
||||||
|
"2006-01-02T15:04:05-07:00", "2006-01-02T15:04:05.999-07:00",
|
||||||
|
// RFC822
|
||||||
|
"02 Jan 06 15:04 MST", "02 Jan 06 15:04 -0700",
|
||||||
|
// RFC850
|
||||||
|
"Monday, 02-Jan-06 15:04:05 MST",
|
||||||
|
// RFC1123
|
||||||
|
"Mon, 02 Jan 2006 15:04:05 MST", "Mon, 02 Jan 2006 15:04:05 -0700",
|
||||||
|
// RFC3339
|
||||||
|
"2006-01-02T15:04:05Z07:00", "2006-01-02T15:04:05.999999999Z07:00",
|
||||||
|
// RFC1036
|
||||||
|
"Mon, 02 Jan 06 15:04:05 -0700",
|
||||||
|
// RFC7231
|
||||||
|
"Mon, 02 Jan 2006 15:04:05 MST",
|
||||||
|
"3:04PM",
|
||||||
|
// Cookies
|
||||||
|
"Monday, 02-Jan-2006 15:04:05 MST",
|
||||||
|
// ANSIC
|
||||||
|
"Mon Jan _2 15:04:05 2006",
|
||||||
|
// UNIX
|
||||||
|
"Mon Jan _2 15:04:05 MST 2006",
|
||||||
|
// Ruby
|
||||||
|
"Mon Jan 02 15:04:05 -0700 2006",
|
||||||
|
|
||||||
|
"2006",
|
||||||
|
"2006-1", "2006-1-2", "2006-1-2 15", "2006-1-2 15:4", "2006-1-2 15:4:5", "2006-1-2 15:4:5.999",
|
||||||
|
"2006.1", "2006.1.2", "2006.1.2 15", "2006.1.2 15:4", "2006.1.2 15:4:5", "2006.1.2 15:4:5.999",
|
||||||
|
"2006/1", "2006/1/2", "2006/1/2 15", "2006/1/2 15:4", "2006/1/2 15:4:5", "2006/1/2 15:4:5.999",
|
||||||
|
"2006-01", "2006-01-02", "2006-01-02 15", "2006-01-02 15:04", "2006-01-02 15:04:05", "2006-01-02 15:04:05.999",
|
||||||
|
"2006.01", "2006.01.02", "2006.01.02 15", "2006.01.02 15:04", "2006.01.02 15:04:05", "2006.01.02 15:04:05.999",
|
||||||
|
"2006/01", "2006/01/02", "2006/01/02 15", "2006/01/02 15:04", "2006/01/02 15:04:05", "2006/01/02 15:04:05.999",
|
||||||
|
"2006-01-02 15:04:05PM MST", "2006-01-02 15:04:05.999PM MST", "2006-1-2 15:4:5PM MST", "2006-1-2 15:4:5.999PM MST",
|
||||||
|
"2006-01-02 15:04:05 PM MST", "2006-01-02 15:04:05.999 PM MST", "2006-1-2 15:4:5 PM MST", "2006-1-2 15:4:5.999 PM MST",
|
||||||
|
"2/1/2006", "2/1/2006 15", "2/1/2006 15:4", "2/1/2006 15:4:5", "2/1/2006 15:4:5.999",
|
||||||
|
"02/01/2006", "02/01/2006 15", "02/01/2006 15:04", "02/01/2006 15:04:05", "02/01/2006 15:04:05.999",
|
||||||
|
"2006-1-2 15:4:5 -0700 MST", "2006-1-2 15:4:5.999 -0700 MST",
|
||||||
|
"2006-1-2T15:4:5Z07", "2006-1-2T15:4:5.999Z07",
|
||||||
|
"2006-1-2T15:4:5Z07:00", "2006-1-2T15:4:5.999Z07:00",
|
||||||
|
"2006-1-2T15:4:5-07:00", "2006-1-2T15:4:5.999-07:00",
|
||||||
|
"20060102150405-07:00", "20060102150405.999-07:00",
|
||||||
|
"20060102150405Z07", "20060102150405.999Z07",
|
||||||
|
"20060102150405Z07:00", "20060102150405.999Z07:00",
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversion parsage → layout
|
||||||
|
parsers = map[rune]string{
|
||||||
|
// Jours
|
||||||
|
'j': "2", // Jour du mois sans les 0 initiaux (1-31)
|
||||||
|
'd': "02", // Jour du mois, sur deux chiffres (avec un 0 initial) (01-31)
|
||||||
|
'D': "Mon", // Jour de la semaine, en 3 lettres (Mon-Sun)
|
||||||
|
'l': "Monday", // Jour de la semaine, textuel, version longue (Monday-Sunday)
|
||||||
|
|
||||||
|
// Mois
|
||||||
|
'n': "1", // Mois sans les 0 initiaux (1-12)
|
||||||
|
'm': "01", // Mois au format numérique, avec 0 initiaux (01-12)
|
||||||
|
'M': "Jan", // Mois, en trois lettres (Jan-Dec)
|
||||||
|
'F': "January", // Mois, textuel, version longue (January-December)
|
||||||
|
|
||||||
|
// Année
|
||||||
|
'y': "06", // Année sur 2 chiffres (Exemples : 99 ou 03)
|
||||||
|
'Y': "2006", // Année sur au moins 4 chiffres, avec - pour les années av. J.-C. (Exemples : -0055, 0787, 1999, 2003, 10191)
|
||||||
|
|
||||||
|
// Heure
|
||||||
|
'a': "pm", // Ante meridiem et Post meridiem en minuscules (am ou pm)
|
||||||
|
'A': "PM", // Ante meridiem et Post meridiem en majuscules (AM ou PM)
|
||||||
|
'g': "3", // Heure, au format 12h, sans les 0 initiaux (1-12)
|
||||||
|
'h': "03", // Heure, au format 12h, avec les 0 initiaux (01-12)
|
||||||
|
'H': "15", // Heure, au format 24h, avec les 0 initiaux (00-23)
|
||||||
|
'i': "04", // Minutes avec les 0 initiaux (00-59)
|
||||||
|
's': "05", // Secondes avec les 0 initiaux (00-59)
|
||||||
|
|
||||||
|
// Fuseau horaire
|
||||||
|
'T': "MST", // Abréviation du fuseau horaire, si connu ; sinon décalage depuis GMT (Exemples : EST, MDT, +05)
|
||||||
|
'O': "-0700", // Différence d’heures avec l’heure de Greenwich (GMT), sans deux-points entre les heures et les minutes (Exemple : +0200)
|
||||||
|
'P': "-07:00", // Différence d’heures avec l’heure de Greenwich (GMT), avec deux-points entre les heures et les minutes (Exemple : +02:00)
|
||||||
|
|
||||||
|
// Date et heure complète
|
||||||
|
'c': "2006-01-02T15:04:05-07:00", // Date au format ISO 8601 (2004-02-12T15:19:21+00:00)
|
||||||
|
'r': "Thu, 21 Dec 2000 16:01:07 +0200", // Date au format RFC 5322 (Thu, 21 Dec 2000 16:01:070200)
|
||||||
|
}
|
||||||
|
|
||||||
// Jours de la semaine (format court)
|
// Jours de la semaine (format court)
|
||||||
shortDays = []string{
|
shortDays = []string{
|
||||||
|
@ -115,143 +335,22 @@ var (
|
||||||
'U': format_U, // Secondes depuis l’époque Unix (1er Janvier 1970, 0h00 00s GMT)
|
'U': format_U, // Secondes depuis l’époque Unix (1er Janvier 1970, 0h00 00s GMT)
|
||||||
}
|
}
|
||||||
|
|
||||||
parsers = map[rune]string{
|
amPmLow = map[bool]string{
|
||||||
// Jours
|
true: "am",
|
||||||
'j': "2", // Jour du mois sans les 0 initiaux (1-31)
|
false: "pm",
|
||||||
'd': "02", // Jour du mois, sur deux chiffres (avec un 0 initial) (01-31)
|
|
||||||
'D': "Mon", // Jour de la semaine, en 3 lettres (Mon-Sun)
|
|
||||||
'l': "Monday", // Jour de la semaine, textuel, version longue (Monday-Sunday)
|
|
||||||
|
|
||||||
// Mois
|
|
||||||
'n': "1", // Mois sans les 0 initiaux (1-12)
|
|
||||||
'm': "01", // Mois au format numérique, avec 0 initiaux (01-12)
|
|
||||||
'M': "Jan", // Mois, en trois lettres (Jan-Dec)
|
|
||||||
'F': "January", // Mois, textuel, version longue (January-December)
|
|
||||||
|
|
||||||
// Année
|
|
||||||
'y': "06", // Année sur 2 chiffres (Exemples : 99 ou 03)
|
|
||||||
'Y': "2006", // Année sur au moins 4 chiffres, avec - pour les années av. J.-C. (Exemples : -0055, 0787, 1999, 2003, 10191)
|
|
||||||
|
|
||||||
// Heure
|
|
||||||
'a': "pm", // Ante meridiem et Post meridiem en minuscules (am ou pm)
|
|
||||||
'A': "PM", // Ante meridiem et Post meridiem en majuscules (AM ou PM)
|
|
||||||
'g': "3", // Heure, au format 12h, sans les 0 initiaux (1-12)
|
|
||||||
'h': "03", // Heure, au format 12h, avec les 0 initiaux (01-12)
|
|
||||||
'H': "15", // Heure, au format 24h, avec les 0 initiaux (00-23)
|
|
||||||
'i': "04", // Minutes avec les 0 initiaux (00-59)
|
|
||||||
's': "05", // Secondes avec les 0 initiaux (00-59)
|
|
||||||
|
|
||||||
// Fuseau horaire
|
|
||||||
'T': "MST", // Abréviation du fuseau horaire, si connu ; sinon décalage depuis GMT (Exemples : EST, MDT, +05)
|
|
||||||
'O': "-0700", // Différence d’heures avec l’heure de Greenwich (GMT), sans deux-points entre les heures et les minutes (Exemple : +0200)
|
|
||||||
'P': "-07:00", // Différence d’heures avec l’heure de Greenwich (GMT), avec deux-points entre les heures et les minutes (Exemple : +02:00)
|
|
||||||
|
|
||||||
// Date et heure complète
|
|
||||||
'c': "2006-01-02T15:04:05-07:00", // Date au format ISO 8601 (2004-02-12T15:19:21+00:00)
|
|
||||||
'r': "Thu, 21 Dec 2000 16:01:07 +0200", // Date au format RFC 5322 (Thu, 21 Dec 2000 16:01:070200)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
layouts = []string{
|
amPmUp = map[bool]string{
|
||||||
DayDateTimeLayout,
|
true: "AM",
|
||||||
DateTimeLayout, DateTimeNanoLayout, ShortDateTimeLayout, ShortDateTimeNanoLayout,
|
false: "PM",
|
||||||
DateLayout, DateNanoLayout, ShortDateLayout, ShortDateNanoLayout,
|
|
||||||
ISO8601Layout, ISO8601NanoLayout,
|
|
||||||
RFC822Layout, RFC822ZLayout, RFC850Layout, RFC1123Layout, RFC1123ZLayout, RFC3339Layout, RFC3339NanoLayout, RFC1036Layout, RFC7231Layout,
|
|
||||||
KitchenLayout,
|
|
||||||
CookieLayout,
|
|
||||||
ANSICLayout,
|
|
||||||
UnixDateLayout,
|
|
||||||
RubyDateLayout,
|
|
||||||
"2006",
|
|
||||||
"2006-1", "2006-1-2", "2006-1-2 15", "2006-1-2 15:4", "2006-1-2 15:4:5", "2006-1-2 15:4:5.999999999",
|
|
||||||
"2006.1", "2006.1.2", "2006.1.2 15", "2006.1.2 15:4", "2006.1.2 15:4:5", "2006.1.2 15:4:5.999999999",
|
|
||||||
"2006/1", "2006/1/2", "2006/1/2 15", "2006/1/2 15:4", "2006/1/2 15:4:5", "2006/1/2 15:4:5.999999999",
|
|
||||||
"2006-01-02 15:04:05PM MST", "2006-01-02 15:04:05.999999999PM MST", "2006-1-2 15:4:5PM MST", "2006-1-2 15:4:5.999999999PM MST",
|
|
||||||
"2006-01-02 15:04:05 PM MST", "2006-01-02 15:04:05.999999999 PM MST", "2006-1-2 15:4:5 PM MST", "2006-1-2 15:4:5.999999999 PM MST",
|
|
||||||
"1/2/2006", "1/2/2006 15", "1/2/2006 15:4", "1/2/2006 15:4:5", "1/2/2006 15:4:5.999999999",
|
|
||||||
"2006-1-2 15:4:5 -0700 MST", "2006-1-2 15:4:5.999999999 -0700 MST",
|
|
||||||
"2006-1-2T15:4:5Z07", "2006-1-2T15:4:5.999999999Z07",
|
|
||||||
"2006-1-2T15:4:5Z07:00", "2006-1-2T15:4:5.999999999Z07:00",
|
|
||||||
"2006-1-2T15:4:5-07:00", "2006-1-2T15:4:5.999999999-07:00",
|
|
||||||
"20060102150405-07:00", "20060102150405.999999999-07:00",
|
|
||||||
"20060102150405Z07", "20060102150405.999999999Z07",
|
|
||||||
"20060102150405Z07:00", "20060102150405.999999999Z07:00",
|
|
||||||
}
|
}
|
||||||
)
|
|
||||||
|
formatP = map[Precision]string{
|
||||||
const (
|
PrecisionMinute: "H:iT",
|
||||||
// Unités de durée
|
PrecisionSecond: "H:i:sT",
|
||||||
Nanosecond = time.Nanosecond
|
PrecisionMillisecond: "H:i:s.vT",
|
||||||
Microsecond = time.Microsecond
|
}
|
||||||
Millisecond = time.Millisecond
|
|
||||||
Second = time.Second
|
// Fuseau horaire par défaut
|
||||||
Minute = time.Minute
|
DefaultTZ = time.Local
|
||||||
Hour = time.Hour
|
|
||||||
Day = time.Hour * 24
|
|
||||||
Week = Day * 7
|
|
||||||
|
|
||||||
MonthsPerYear = 12
|
|
||||||
DaysPerWeek = 7
|
|
||||||
HoursPerDay = 24
|
|
||||||
HoursPerWeek = HoursPerDay * DaysPerWeek
|
|
||||||
MinutesPerHour = 60
|
|
||||||
MinutesPerDay = MinutesPerHour * HoursPerDay
|
|
||||||
MinutesPerWeek = MinutesPerHour * HoursPerWeek
|
|
||||||
SecondsPerMinute = 60
|
|
||||||
SecondsPerHour = SecondsPerMinute * MinutesPerHour
|
|
||||||
SecondsPerDay = SecondsPerMinute * MinutesPerDay
|
|
||||||
SecondsPerWeek = SecondsPerMinute * MinutesPerWeek
|
|
||||||
|
|
||||||
// Erreurs
|
|
||||||
errInvalidTZ = "Invalid timezone %q"
|
|
||||||
errInvalidValue = "Cannot parse string %q as datetime, please make sure the value is valid"
|
|
||||||
|
|
||||||
// Quelques layouts
|
|
||||||
ANSICLayout = time.ANSIC
|
|
||||||
UnixDateLayout = time.UnixDate
|
|
||||||
RubyDateLayout = time.RubyDate
|
|
||||||
RFC822Layout = time.RFC822
|
|
||||||
RFC822ZLayout = time.RFC822Z
|
|
||||||
RFC850Layout = time.RFC850
|
|
||||||
RFC1123Layout = time.RFC1123
|
|
||||||
RFC1123ZLayout = time.RFC1123Z
|
|
||||||
RssLayout = time.RFC1123Z
|
|
||||||
KitchenLayout = time.Kitchen
|
|
||||||
RFC2822Layout = time.RFC1123Z
|
|
||||||
CookieLayout = "Monday, 02-Jan-2006 15:04:05 MST"
|
|
||||||
RFC3339Layout = "2006-01-02T15:04:05Z07:00"
|
|
||||||
RFC3339MilliLayout = "2006-01-02T15:04:05.999Z07:00"
|
|
||||||
RFC3339MicroLayout = "2006-01-02T15:04:05.999999Z07:00"
|
|
||||||
RFC3339NanoLayout = "2006-01-02T15:04:05.999999999Z07:00"
|
|
||||||
ISO8601Layout = "2006-01-02T15:04:05-07:00"
|
|
||||||
ISO8601MilliLayout = "2006-01-02T15:04:05.999-07:00"
|
|
||||||
ISO8601MicroLayout = "2006-01-02T15:04:05.999999-07:00"
|
|
||||||
ISO8601NanoLayout = "2006-01-02T15:04:05.999999999-07:00"
|
|
||||||
RFC1036Layout = "Mon, 02 Jan 06 15:04:05 -0700"
|
|
||||||
RFC7231Layout = "Mon, 02 Jan 2006 15:04:05 MST"
|
|
||||||
DayDateTimeLayout = "Mon, Jan 2, 2006 3:04 PM"
|
|
||||||
DateTimeLayout = "2006-01-02 15:04:05"
|
|
||||||
DateTimeMilliLayout = "2006-01-02 15:04:05.999"
|
|
||||||
DateTimeMicroLayout = "2006-01-02 15:04:05.999999"
|
|
||||||
DateTimeNanoLayout = "2006-01-02 15:04:05.999999999"
|
|
||||||
ShortDateTimeLayout = "20060102150405"
|
|
||||||
ShortDateTimeMilliLayout = "20060102150405.999"
|
|
||||||
ShortDateTimeMicroLayout = "20060102150405.999999"
|
|
||||||
ShortDateTimeNanoLayout = "20060102150405.999999999"
|
|
||||||
DateLayout = "2006-01-02"
|
|
||||||
DateMilliLayout = "2006-01-02.999"
|
|
||||||
DateMicroLayout = "2006-01-02.999999"
|
|
||||||
DateNanoLayout = "2006-01-02.999999999"
|
|
||||||
ShortDateLayout = "20060102"
|
|
||||||
ShortDateMilliLayout = "20060102.999"
|
|
||||||
ShortDateMicroLayout = "20060102.999999"
|
|
||||||
ShortDateNanoLayout = "20060102.999999999"
|
|
||||||
TimeLayout = "15:04:05"
|
|
||||||
TimeMilliLayout = "15:04:05.999"
|
|
||||||
TimeMicroLayout = "15:04:05.999999"
|
|
||||||
TimeNanoLayout = "15:04:05.999999999"
|
|
||||||
ShortTimeLayout = "150405"
|
|
||||||
ShortTimeMilliLayout = "150405.999"
|
|
||||||
ShortTimeMicroLayout = "150405.999999"
|
|
||||||
ShortTimeNanoLayout = "150405.999999999"
|
|
||||||
)
|
)
|
||||||
|
|
|
@ -1,101 +0,0 @@
|
||||||
package datetime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
. "gitea.zaclys.com/bvaudour/gob/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Zero retourne la date correspondant au 01/01/0001 00:00:00 UTC.
|
|
||||||
// Si tz est fourni, la date est dans le fuseau horaire demandé,
|
|
||||||
// sinon, dans le fuseau horaire par défaut.
|
|
||||||
func Zero(tz ...string) Result[time.Time] {
|
|
||||||
var t time.Time
|
|
||||||
|
|
||||||
return toTZ(t, tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now retourne la date actuelle.
|
|
||||||
func Now(tz ...string) Result[time.Time] {
|
|
||||||
t := time.Now()
|
|
||||||
|
|
||||||
return toTZ(t, tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tomorrow retourne la date dans 24h.
|
|
||||||
func Tomorrow(tz ...string) Result[time.Time] {
|
|
||||||
now := Now(tz...)
|
|
||||||
if t, ok := now.Ok(); ok {
|
|
||||||
return Ok(AddDays(t, 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
return now
|
|
||||||
}
|
|
||||||
|
|
||||||
// Yesterday retourne la date il y a 24h.
|
|
||||||
func Yesterday(tz ...string) Result[time.Time] {
|
|
||||||
now := Now(tz...)
|
|
||||||
if t, ok := now.Ok(); ok {
|
|
||||||
return Ok(AddDays(t, -1))
|
|
||||||
}
|
|
||||||
|
|
||||||
return now
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromTimestamp convertit un timestamp (exprimé en secondes) en date.
|
|
||||||
func FromTimestamp(timestamp int64, tz ...string) Result[time.Time] {
|
|
||||||
t := time.Unix(timestamp, 0)
|
|
||||||
|
|
||||||
return toTZ(t, tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromTimestampMilli convertit un timestamp (exprimé en ms) en date.
|
|
||||||
func FromTimestampMilli(timestamp int64, tz ...string) Result[time.Time] {
|
|
||||||
t := time.Unix(timestamp/1e3, (timestamp%1e3)*1e6)
|
|
||||||
|
|
||||||
return toTZ(t, tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromTimestampMicro convertit un timestamp (exprimé en μs) en date.
|
|
||||||
func FromTimestampMicro(timestamp int64, tz ...string) Result[time.Time] {
|
|
||||||
t := time.Unix(timestamp/1e6, (timestamp%1e6)*1e3)
|
|
||||||
|
|
||||||
return toTZ(t, tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromTimestampNano convertit un timestamp (exprimé en ns) en date.
|
|
||||||
func FromTimestampNano(timestamp int64, tz ...string) Result[time.Time] {
|
|
||||||
t := time.Unix(timestamp/1e9, timestamp%1e9)
|
|
||||||
|
|
||||||
return toTZ(t, tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromDateTime retourne la date à partir des données numériques complètes.
|
|
||||||
func FromDateTime(year, month, day, hour, minute, second int, tz ...string) Result[time.Time] {
|
|
||||||
location, ok := getTZ(tz...).Get()
|
|
||||||
if !ok {
|
|
||||||
return Err[time.Time](fmt.Errorf(errInvalidTZ, tz))
|
|
||||||
}
|
|
||||||
|
|
||||||
t := time.Date(year, time.Month(month-1), day, hour, minute, second, 0, location)
|
|
||||||
|
|
||||||
return Ok(t)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromDate retourne le début du jour à partir des données de dates.
|
|
||||||
func FromDate(year, month, day int, tz ...string) Result[time.Time] {
|
|
||||||
return FromDateTime(year, month, day, 0, 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// FromTime retourne la date d’aujourd’hui à l’heure indiquée.
|
|
||||||
func FromTime(hour, minute, second int, tz ...string) Result[time.Time] {
|
|
||||||
now := Now(tz...)
|
|
||||||
if !now.IsOk() {
|
|
||||||
return now
|
|
||||||
}
|
|
||||||
|
|
||||||
n, _ := now.Ok()
|
|
||||||
year, month, day := n.Date()
|
|
||||||
return FromDateTime(year, int(month+1), day, hour, minute, second, tz...)
|
|
||||||
}
|
|
|
@ -0,0 +1,374 @@
|
||||||
|
package datetime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type date int
|
||||||
|
|
||||||
|
func newD(y int, m, j uint) date {
|
||||||
|
if !validD(y, m, j) {
|
||||||
|
return dateNil
|
||||||
|
}
|
||||||
|
return setD(y, "y") | setD(m, "m") | setD(j, "d")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t date) y() int { return getD[int](t, "y") }
|
||||||
|
func (t date) m() uint { return getD[uint](t, "m") }
|
||||||
|
func (t date) d() uint { return getD[uint](t, "d") }
|
||||||
|
func (t date) t(l *time.Location) time.Time { return fromD(t.y(), t.m(), t.d(), l) }
|
||||||
|
func (t date) dst(l *time.Location) bool { return t.t(l).IsDST() }
|
||||||
|
func (t date) ts(l *time.Location) int64 { return t.t(l).Unix() }
|
||||||
|
func (t date) tv(l *time.Location) int64 { return t.t(l).UnixMilli() }
|
||||||
|
func (t date) b() bool { return bissextil(t.y()) }
|
||||||
|
func (t date) yl() uint { return yearLen(t.y()) }
|
||||||
|
func (t date) ml() uint { return monthLen(t.y(), t.m()) }
|
||||||
|
|
||||||
|
func (t date) valid() bool { return validD(t.y(), t.m(), t.d()) }
|
||||||
|
|
||||||
|
func (t date) yd() uint {
|
||||||
|
if t.valid() {
|
||||||
|
y, m, d := t.y(), t.m(), t.d()
|
||||||
|
for mm := January; mm < m; mm++ {
|
||||||
|
d += monthLen(y, mm)
|
||||||
|
}
|
||||||
|
|
||||||
|
return d
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
func (t date) wd(l *time.Location) uint { return uint(t.t(l).Weekday()) }
|
||||||
|
|
||||||
|
func (t date) setY(y int, e ...uint) date {
|
||||||
|
if !t.valid() {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
m, d := t.m(), t.d()
|
||||||
|
if len(e) > 0 {
|
||||||
|
m = e[0]
|
||||||
|
if len(e) > 1 {
|
||||||
|
d = e[1]
|
||||||
|
} else if ml := monthLen(y, m); d > ml {
|
||||||
|
d = ml
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newD(y, m, d)
|
||||||
|
}
|
||||||
|
func (t date) setM(m uint, e ...uint) date {
|
||||||
|
if !t.valid() {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
y, d := t.y(), t.d()
|
||||||
|
if len(e) > 0 {
|
||||||
|
d = e[0]
|
||||||
|
} else if ml := monthLen(y, m); d > ml {
|
||||||
|
d = ml
|
||||||
|
}
|
||||||
|
return newD(y, m, d)
|
||||||
|
}
|
||||||
|
func (t date) setD(d uint) date {
|
||||||
|
if !t.valid() {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
t = replD(t, d, "d")
|
||||||
|
if !t.valid() {
|
||||||
|
return dateNil
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t date) add(y, m, d int) date {
|
||||||
|
if !t.valid() {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
y, m, d = t.y()+y, int(t.m())+m, int(t.d())+d
|
||||||
|
if m > int(December) {
|
||||||
|
mm := m - 1
|
||||||
|
y, m = y+mm/MonthPerYear, (mm%MonthPerYear)+1
|
||||||
|
} else if m < int(January) {
|
||||||
|
mm := m - 12
|
||||||
|
y, m = y+mm/MonthPerYear, (mm%MonthPerYear)+12
|
||||||
|
}
|
||||||
|
for !validD(y, uint(m), uint(d)) {
|
||||||
|
ml := int(monthLen(y, uint(m)))
|
||||||
|
if d > ml {
|
||||||
|
d -= ml
|
||||||
|
m++
|
||||||
|
if m > int(December) {
|
||||||
|
m -= MonthPerYear
|
||||||
|
y++
|
||||||
|
}
|
||||||
|
} else if d < 1 {
|
||||||
|
m--
|
||||||
|
if m < int(January) {
|
||||||
|
m += MonthPerYear
|
||||||
|
y--
|
||||||
|
}
|
||||||
|
d += int(monthLen(y, uint(m)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return newD(y, uint(m), uint(d))
|
||||||
|
}
|
||||||
|
func (t date) addY(y int) date { return t.add(y, 0, 0) }
|
||||||
|
func (t date) addM(m int) date { return t.add(0, m, 0) }
|
||||||
|
func (t date) addW(w int) date { return t.addD(w * DayPerWeek) }
|
||||||
|
func (t date) addD(d int) date { return t.add(0, 0, d) }
|
||||||
|
func (t date) addDD(dd Duration) date {
|
||||||
|
ad := func(ud int) func(int) date {
|
||||||
|
return func(e int) date { return t.addD(e / ud) }
|
||||||
|
}
|
||||||
|
f := map[Unit]func(int) date{
|
||||||
|
Year: t.addY,
|
||||||
|
Month: t.addM,
|
||||||
|
Week: t.addW,
|
||||||
|
Day: t.addD,
|
||||||
|
Hour: ad(HourPerDay),
|
||||||
|
Minute: ad(MinutePerDay),
|
||||||
|
Second: ad(SecondPerDay),
|
||||||
|
Millisecond: ad(MillisecondPerDay),
|
||||||
|
}
|
||||||
|
e, u := dd.Value(), dd.Unit()
|
||||||
|
if cb, ok := f[u]; ok {
|
||||||
|
return cb(e)
|
||||||
|
}
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t date) bY() date { return t.setM(January, 1) }
|
||||||
|
func (t date) eY() date { return t.setM(December, 31) }
|
||||||
|
func (t date) bM() date { return t.setD(1) }
|
||||||
|
func (t date) eM() date { return t.setD(monthLen(t.y(), t.m())) }
|
||||||
|
func (t date) bW(l *time.Location) date { return t.addD(diffBow(t.wd(l))) }
|
||||||
|
func (t date) eW(l *time.Location) date { return t.addD(diffEow(t.wd(l))) }
|
||||||
|
|
||||||
|
func (t1 date) cmp(t2 date) int {
|
||||||
|
if !t1.valid() {
|
||||||
|
if !t2.valid() {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
if !t2.valid() {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
if c := cmp(t1.y(), t2.y()); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
if c := cmp(t1.m(), t2.m()); c != 0 {
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
return cmp(t1.d(), t2.d())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t1 date) diff(t2 date) (dy, dm, dd int) {
|
||||||
|
return t1.y() - t2.y(), int(t1.m()) - int(t2.m()), int(t1.d()) - int(t2.d())
|
||||||
|
}
|
||||||
|
func (t1 date) subD(t2 date, l1, l2 *time.Location) int {
|
||||||
|
return int(t1.ts(l1)-t2.ts(l2)) / SecondPerDay
|
||||||
|
}
|
||||||
|
func (t1 date) subW(t2 date, l1, l2 *time.Location) int { return t1.subD(t2, l1, l2) / DayPerWeek }
|
||||||
|
func (t1 date) subM(t2 date) int {
|
||||||
|
dy, dm, dd := t1.diff(t2)
|
||||||
|
if dd < 0 {
|
||||||
|
dm--
|
||||||
|
}
|
||||||
|
return dy*MonthPerYear + dm
|
||||||
|
}
|
||||||
|
func (t1 date) subY(t2 date) int { return t1.subM(t2) / MonthPerYear }
|
||||||
|
|
||||||
|
func (t date) f(f string, l *time.Location) string {
|
||||||
|
if !t.valid() {
|
||||||
|
return "-"
|
||||||
|
}
|
||||||
|
return formatT(t.t(l), f)
|
||||||
|
}
|
||||||
|
func (t date) str(l *time.Location) string { return t.f("Y-m-d", l) }
|
||||||
|
|
||||||
|
// Date représente une date sans l’heure de la journée.
|
||||||
|
type Date struct {
|
||||||
|
date
|
||||||
|
location *time.Location
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateNil retourne une date nulle.
|
||||||
|
func DateNil() (t Date) { return }
|
||||||
|
|
||||||
|
func newDate(t date, l *time.Location) Date {
|
||||||
|
if t.valid() {
|
||||||
|
return Date{
|
||||||
|
date: t,
|
||||||
|
location: l,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return DateNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDate retourne la date dans le fuseau horaire demandé.
|
||||||
|
func NewDate(y int, m, d uint, tz ...string) Date {
|
||||||
|
return newDate(newD(y, m, d), timezone(tz...))
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewDateFromTime retourne la date à partir d’une date Go.
|
||||||
|
func NewDateFromTime(t time.Time) Date {
|
||||||
|
y, m, d := t.Date()
|
||||||
|
l := t.Location()
|
||||||
|
|
||||||
|
return newDate(newD(y, uint(m+1), uint(d)), l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateNow retourne la date actuelle. Si tz est renseignée,
|
||||||
|
// la date est placée dans le fuseau horaire indiqué.
|
||||||
|
func DateNow(tz ...string) Date { return NewDateFromTime(now(tz...)) }
|
||||||
|
|
||||||
|
func (t Date) Now() Date { return DateNow(t.location.String()) }
|
||||||
|
|
||||||
|
// DateGuess retourne la date à partir de e en essayant de deviner le format.
|
||||||
|
func DateGuess(e string, tz ...string) Date {
|
||||||
|
if t, ok := guess(e, tz...).Get(); ok {
|
||||||
|
return NewDateFromTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return DateNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// DateParse retourne la date à partir de v en spécifiant le format f.
|
||||||
|
func DateParse(e, f string, tz ...string) Date {
|
||||||
|
if t, ok := parse(e, f).Get(); ok {
|
||||||
|
return NewDateFromTime(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
return DateNil()
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNil retourne vrai si la date est nulle.
|
||||||
|
func (t Date) IsNil() bool { return !t.valid() }
|
||||||
|
|
||||||
|
// Year retourne l’année.
|
||||||
|
func (t Date) Year() int { return t.y() }
|
||||||
|
|
||||||
|
// Month retourne le mois (de 1 à 12).
|
||||||
|
func (t Date) Month() uint { return t.m() }
|
||||||
|
|
||||||
|
// Day retourne le jour du mois (de 1 à 31).
|
||||||
|
func (t Date) Day() uint { return t.d() }
|
||||||
|
|
||||||
|
// Date retourne l’année, le mois et le jour du mois.
|
||||||
|
func (t Date) Date() (y int, m, d uint) { return t.y(), t.m(), t.d() }
|
||||||
|
|
||||||
|
// YearDay retourne le jour dans l’année (de 1 à 366).
|
||||||
|
func (t Date) YearDay() uint { return t.yd() }
|
||||||
|
|
||||||
|
// WeekDay retourne le jour de la semaine (de 0 à 6 en commençant par dimanche).
|
||||||
|
func (t Date) WeekDay() uint { return t.wd(t.location) }
|
||||||
|
|
||||||
|
// IsBissextil retourn vrai si la date est dans une année bissextile.
|
||||||
|
func (t Date) IsBissextil() bool { return t.b() }
|
||||||
|
|
||||||
|
// DaysInYear retourne le nombre de jours dans l’année.
|
||||||
|
func (t Date) DaysInYear() uint { return t.yl() }
|
||||||
|
|
||||||
|
// DaysInMonth retourne le nombre de jours dans le mois.
|
||||||
|
func (t Date) DaysInMonth() uint { return t.ml() }
|
||||||
|
|
||||||
|
// SetYear crée une nouvelle date en changeant l’année (et facultativement le mois et le jour).
|
||||||
|
func (t Date) SetYear(y int, md ...uint) Date { return newDate(t.setY(y, md...), t.location) }
|
||||||
|
|
||||||
|
// SetMonth crée une nouvelle date en changeant le mois (et facultativement le jour).
|
||||||
|
func (t Date) SetMonth(m uint, d ...uint) Date { return newDate(t.setM(m, d...), t.location) }
|
||||||
|
|
||||||
|
// SetDay crée une nouvelle date en changeant le jour.
|
||||||
|
func (t Date) SetDay(d uint) Date { return newDate(t.setD(d), t.location) }
|
||||||
|
|
||||||
|
// Add incrémente l’année, le mois et le jour.
|
||||||
|
func (t Date) Add(y, m, d int) Date { return newDate(t.add(y, m, d), t.location) }
|
||||||
|
|
||||||
|
// AddYear incrémente l’année.
|
||||||
|
func (t Date) AddYear(y int) Date { return newDate(t.addY(y), t.location) }
|
||||||
|
|
||||||
|
// AddMonth incrémente le mois.
|
||||||
|
func (t Date) AddMonth(m int) Date { return newDate(t.addM(m), t.location) }
|
||||||
|
|
||||||
|
// AddWeek incrémente la date de week semaines.
|
||||||
|
func (t Date) AddWeek(w int) Date { return newDate(t.addW(w), t.location) }
|
||||||
|
|
||||||
|
// AddDay incrémente le jour.
|
||||||
|
func (t Date) AddDay(d int) Date { return newDate(t.addD(d), t.location) }
|
||||||
|
|
||||||
|
// AddDuration décale la date d’une durée donnée.
|
||||||
|
func (t Date) AddDuration(dd Duration) Date { return newDate(t.addDD(dd), t.location) }
|
||||||
|
|
||||||
|
// BeginOfYear retourne la date du premier jour de l’année.
|
||||||
|
func (t Date) BeginOfYear() Date { return newDate(t.bY(), t.location) }
|
||||||
|
|
||||||
|
// EndOfYear retourne la date du dernier jour de l’année.
|
||||||
|
func (t Date) EndOfYear() Date { return newDate(t.eY(), t.location) }
|
||||||
|
|
||||||
|
// BeginOfMonth retourne la date du premier jour du mois.
|
||||||
|
func (t Date) BeginOfMonth() Date { return newDate(t.bM(), t.location) }
|
||||||
|
|
||||||
|
// EndOfMonth retourne la date du dernier jour du mois.
|
||||||
|
func (t Date) EndOfMonth() Date { return newDate(t.eM(), t.location) }
|
||||||
|
|
||||||
|
// BeginOfWeek retourne la date du premier jour de la semaine (ie. lundi).
|
||||||
|
func (t Date) BeginOfWeek() Date { return newDate(t.bW(t.location), t.location) }
|
||||||
|
|
||||||
|
// EndOfWeek retourne la date du dernier jour de la semaine.
|
||||||
|
func (t Date) EndOfWeek() Date { return newDate(t.eW(t.location), t.location) }
|
||||||
|
|
||||||
|
// ToTime convertit la date en date de type time.Time.
|
||||||
|
func (t Date) ToTime() time.Time { return t.t(t.location) }
|
||||||
|
|
||||||
|
// In retourne la date dans le fuseau horaire indiqué.
|
||||||
|
func (t Date) In(l *time.Location) Date {
|
||||||
|
if !t.valid() {
|
||||||
|
return t
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewDateFromTime(t.t(t.location).In(l))
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTimezone retourne la date dans le fuseau horaire indiqué.
|
||||||
|
func (t Date) ToTimezone(tz string) Date { return t.In(timezone(tz)) }
|
||||||
|
|
||||||
|
// Location retourne le fuseau horaire.
|
||||||
|
func (t Date) Location() *time.Location { return t.location }
|
||||||
|
|
||||||
|
// IsDST retourne vrai si le fuseau horaire est à l’heure d’été.
|
||||||
|
func (t Date) IsDST() bool { return t.dst(t.location) }
|
||||||
|
|
||||||
|
// Timestamp retourne le timestamp en secondes.
|
||||||
|
func (t Date) Timestamp() int64 { return t.ts(t.location) }
|
||||||
|
|
||||||
|
// TimestampMilli retourne le timestamp en secondes.
|
||||||
|
func (t Date) TimestampMilli() int64 { return t.tv(t.location) }
|
||||||
|
|
||||||
|
// Compare compare 2 dates.
|
||||||
|
func (t1 Date) Compare(t2 Date) int { return t1.cmp(t2.In(t1.location).date) }
|
||||||
|
|
||||||
|
func (t1 Date) Eq(t2 Date) bool { return t1.Compare(t2) == 0 }
|
||||||
|
func (t1 Date) Ne(t2 Date) bool { return t1.Compare(t2) != 0 }
|
||||||
|
func (t1 Date) Gt(t2 Date) bool { return t1.Compare(t2) > 0 }
|
||||||
|
func (t1 Date) Ge(t2 Date) bool { return t1.Compare(t2) >= 0 }
|
||||||
|
func (t1 Date) Lt(t2 Date) bool { return t1.Compare(t2) < 0 }
|
||||||
|
func (t1 Date) Le(t2 Date) bool { return t1.Compare(t2) <= 0 }
|
||||||
|
|
||||||
|
func (t Date) IsNow() bool { return t.Eq(t.Now()) }
|
||||||
|
func (t Date) IsPast() bool { return t.Lt(t.Now()) }
|
||||||
|
func (t Date) IsFuture() bool { return t.Gt(t.Now()) }
|
||||||
|
|
||||||
|
func (t1 Date) diff(t2 Date) (dy, dm, dd int) {
|
||||||
|
return t1.y() - t2.y(), int(t1.m()) - int(t2.m()), int(t1.d()) - int(t2.d())
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t1 Date) DiffInDays(t2 Date) int { return t1.subD(t2.date, t1.location, t2.location) }
|
||||||
|
func (t1 Date) DiffInWeeks(t2 Date) int { return t1.subW(t2.date, t1.location, t2.location) }
|
||||||
|
func (t1 Date) DiffInMonths(t2 Date) int { return t1.subM(t2.date) }
|
||||||
|
func (t1 Date) DiffInYears(t2 Date) int { return t1.subY(t2.date) }
|
||||||
|
|
||||||
|
// Format retourne une représentation de la date au format spécifié.
|
||||||
|
func (t Date) Format(format string) string { return t.f(format, t.location) }
|
||||||
|
|
||||||
|
// String retourne la date au format Y-m-d.
|
||||||
|
func (t Date) String() string { return t.str(t.location) }
|
|
@ -0,0 +1,522 @@
|
||||||
|
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]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dc := v / MillisecondPerDay
|
||||||
|
d, v = d+dc, v-dc*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.
|
||||||
|
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.
|
||||||
|
// 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.
|
||||||
|
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 la date actuelle. 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)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dt DateTime) Now() DateTime { return DateTimeNow(dt.p(), dt.location.String()) }
|
||||||
|
|
||||||
|
// DateTimeGuess retourne la date à 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 la date à 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 la date est nulle.
|
||||||
|
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 .
|
||||||
|
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.
|
||||||
|
func (dt DateTime) SetYear(y int, args ...uint) DateTime {
|
||||||
|
return initDT(dt.setY(y, args...), dt.location)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMonth modifie le mois.
|
||||||
|
func (dt DateTime) SetMonth(m uint, args ...uint) DateTime {
|
||||||
|
return initDT(dt.setM(m, args...), dt.location)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDay modifie le jour.
|
||||||
|
func (dt DateTime) SetDay(d uint, args ...uint) DateTime {
|
||||||
|
return initDT(dt.setD(d, args...), dt.location)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetHour modifie l’heure.
|
||||||
|
func (dt DateTime) SetHour(h uint, args ...uint) DateTime {
|
||||||
|
return initDT(dt.setH(h, args...), dt.location)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMinute modifie la minute.
|
||||||
|
func (dt DateTime) SetMinute(i uint, args ...uint) DateTime {
|
||||||
|
return initDT(dt.setI(i, args...), dt.location)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetSecond modifie la seconde.
|
||||||
|
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 la date en début d’année.
|
||||||
|
func (dt DateTime) BeginOfYear() DateTime { return initDT(dt.bY(), dt.location) }
|
||||||
|
|
||||||
|
// EndOfYear retourne la date en fin d’année.
|
||||||
|
func (dt DateTime) EndOfYear() DateTime { return initDT(dt.eY(), dt.location) }
|
||||||
|
|
||||||
|
// BeginOfMonth retourne la date en début de mois.
|
||||||
|
func (dt DateTime) BeginOfMonth() DateTime { return initDT(dt.bM(), dt.location) }
|
||||||
|
|
||||||
|
// EndOfMonth retourne la date en fin de mois.
|
||||||
|
func (dt DateTime) EndOfMonth() DateTime { return initDT(dt.eM(), dt.location) }
|
||||||
|
|
||||||
|
// BeginOfWeek retourne la date en début de semaine.
|
||||||
|
func (dt DateTime) BeginOfWeek() DateTime { return initDT(dt.bW(dt.location), dt.location) }
|
||||||
|
|
||||||
|
// EndOfWeek retourne la date en fin de semaine.
|
||||||
|
func (dt DateTime) EndOfWeek() DateTime { return initDT(dt.eW(dt.location), dt.location) }
|
||||||
|
|
||||||
|
// BeginOfDay retourne la date en début de jour.
|
||||||
|
func (dt DateTime) BeginOfDay() DateTime { return initDT(dt.bD(), dt.location) }
|
||||||
|
|
||||||
|
// EndOfDay retourne la date en fin de jour.
|
||||||
|
func (dt DateTime) EndOfDay() DateTime { return initDT(dt.eD(), dt.location) }
|
||||||
|
|
||||||
|
// BeginOfHour retourne la date en début d’heure.
|
||||||
|
func (dt DateTime) BeginOfHour() DateTime { return initDT(dt.bH(), dt.location) }
|
||||||
|
|
||||||
|
// EndOfHour retourne la date en fin d’heure.
|
||||||
|
func (dt DateTime) EndOfHour() DateTime { return initDT(dt.eH(), dt.location) }
|
||||||
|
|
||||||
|
// BeginOfMinute retourne la date en début de minute.
|
||||||
|
func (dt DateTime) BeginOfMinute() DateTime { return initDT(dt.bI(), dt.location) }
|
||||||
|
|
||||||
|
// EndOfMinute retourne la date en fin de minute.
|
||||||
|
func (dt DateTime) EndOfMinute() DateTime { return initDT(dt.eI(), dt.location) }
|
||||||
|
|
||||||
|
// BeginOfSecond retourne la date en début de seconde.
|
||||||
|
func (dt DateTime) BeginOfSecond() DateTime { return initDT(dt.bS(), dt.location) }
|
||||||
|
|
||||||
|
// EndOfSecond retourne la date en fin de seconde.
|
||||||
|
func (dt DateTime) EndOfSecond() DateTime { return initDT(dt.eS(), dt.location) }
|
||||||
|
|
||||||
|
// ToTime retourne la date dans le fuseau horaire indiqué.
|
||||||
|
func (dt DateTime) ToTime() time.Time { return dt.t(dt.location) }
|
||||||
|
|
||||||
|
// In retourne la date 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())
|
||||||
|
}
|
||||||
|
|
||||||
|
// ToTimezone retourne la date dans le fuseau horaire indiqué.
|
||||||
|
func (dt DateTime) ToTimezone(tz string) DateTime { return dt.In(timezone(tz)) }
|
||||||
|
|
||||||
|
// Location retourne le fuseau horaire.
|
||||||
|
func (dt DateTime) Location() *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 dates.
|
||||||
|
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 }
|
||||||
|
|
||||||
|
func (dt DateTime) IsNow() bool { return dt.Eq(dt.Now()) }
|
||||||
|
func (dt DateTime) IsPast() bool { return dt.Lt(dt.Now()) }
|
||||||
|
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 de la date au format spécifié.
|
||||||
|
func (dt DateTime) Format(f string) string { return dt.f(f, dt.location) }
|
||||||
|
|
||||||
|
// String retourne une représentation de la date 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) }
|
|
@ -1,72 +1,55 @@
|
||||||
package datetime
|
package datetime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"fmt"
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DiffInYears retourne (t1 - t2) exprimé en années.
|
// Unit est une unité de durée.
|
||||||
func DiffInYears(t1, t2 time.Time) int64 {
|
type Unit uint
|
||||||
y1, m1, d1 := t1.Date()
|
|
||||||
y2, m2, d2 := t2.Date()
|
|
||||||
|
|
||||||
dy, dm, dd := y1-y2, m1-m2, d1-d2
|
// Duration est une durée entre deux repères de temps.
|
||||||
if dm < 0 || (dm == 0 && dd < 0) {
|
type Duration int
|
||||||
dy--
|
|
||||||
}
|
// NewDuration retourne une durée à partir d’une valeur et d’une unité.
|
||||||
if dy < 0 && (dd != 0 || dm != 0) {
|
func NewDuration(value int, unit Unit) Duration {
|
||||||
dy++
|
if unit == NoUnit {
|
||||||
|
return DurationNil
|
||||||
}
|
}
|
||||||
|
|
||||||
return int64(dy)
|
return (Duration(value) << bitsUnit) | Duration(unit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiffInMonths retourne (t1 - t2) exprimé en mois.
|
// Value retourne la valeur de la durée, sans l’unité.
|
||||||
func DiffInMonths(t1, t2 time.Time) int64 {
|
func (d Duration) Value() int { return int(d >> bitsUnit) }
|
||||||
y1, m1, d1 := t1.Date()
|
|
||||||
y2, m2, d2 := t2.Date()
|
|
||||||
|
|
||||||
dy, dm, dd := y1-y2, m1-m2, d1-d2
|
// Unit retourne l’unité de durée.
|
||||||
if dd < 0 {
|
func (d Duration) Unit() Unit { return Unit(d & maskUnit) }
|
||||||
dm--
|
|
||||||
}
|
// Duration retourne la valeur et l’unité de la durée.
|
||||||
if dy == 0 && dm == 0 {
|
func (d Duration) Duration() (int, Unit) { return d.Value(), d.Unit() }
|
||||||
return int64(dm)
|
|
||||||
}
|
// IsNil retourne vrai si la durée ne représente pas une durée valide.
|
||||||
if dy == 0 && dm != 0 && dd != 0 {
|
func (d Duration) IsNil() bool { return d.Unit() == NoUnit }
|
||||||
dh := abs(DiffInHours(t1, t2))
|
|
||||||
if int(dh) < DaysInMonth(t1)*HoursPerDay {
|
// IsClock retourne vrai si la durée est dans une unité de temps sur 24h.
|
||||||
return int64(0)
|
func (d Duration) IsClock() bool { u := d.Unit(); return u > NoUnit && u < Day }
|
||||||
}
|
|
||||||
return int64(dm)
|
// IsDate retourne vrai si la durée est dans une unité de date.
|
||||||
|
func (d Duration) IsDate() bool { return d.Unit() > Hour }
|
||||||
|
|
||||||
|
// Abs retourne la durée en valeur absolue.
|
||||||
|
func (d Duration) Abs() Duration { return NewDuration(abs(d.Value()), d.Unit()) }
|
||||||
|
|
||||||
|
// Neg retourne l’inverse négatif de la durée.
|
||||||
|
func (d Duration) Neg() Duration { return NewDuration(-d.Value(), d.Unit()) }
|
||||||
|
|
||||||
|
// String retourne la représentation textuelle de la durée.
|
||||||
|
func (d Duration) String() string {
|
||||||
|
if d.IsNil() {
|
||||||
|
return "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
return int64(dy*MonthsPerYear + int(dm))
|
v, u := d.Value(), d.Unit()
|
||||||
}
|
|
||||||
|
return fmt.Sprintf("%d%c", v, unitToByte[u])
|
||||||
// DiffInWeeks retourne (t1 - t2) exprimé en semaines.
|
|
||||||
func DiffInWeeks(t1, t2 time.Time) int64 {
|
|
||||||
return int64(math.Floor(float64(DiffInSeconds(t1, t2)) / float64(SecondsPerWeek)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiffInDays retourne (t1 - t2) exprimé en jours.
|
|
||||||
func DiffInDays(t1, t2 time.Time) int64 {
|
|
||||||
return int64(math.Floor(float64(DiffInSeconds(t1, t2)) / float64(SecondsPerDay)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiffInHours retourne (t1 - t2) exprimé en heures.
|
|
||||||
func DiffInHours(t1, t2 time.Time) int64 {
|
|
||||||
|
|
||||||
return DiffInSeconds(t1, t2) / SecondsPerHour
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiffInMinutes retourne (t1 - t2) exprimé en minutes.
|
|
||||||
func DiffInMinutes(t1, t2 time.Time) int64 {
|
|
||||||
|
|
||||||
return DiffInSeconds(t1, t2) / SecondsPerMinute
|
|
||||||
}
|
|
||||||
|
|
||||||
// DiffInSeconds retourne (t1 - t2) exprimé en secondes.
|
|
||||||
func DiffInSeconds(t1, t2 time.Time) int64 {
|
|
||||||
return t1.Unix() - t2.Unix()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,46 +6,13 @@ import (
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
func abs[N ~int | ~int64](e N) N {
|
func gmtDiff(t time.Time) (hour, minute int) {
|
||||||
if e < 0 {
|
g := toTZ(t, "GMT")
|
||||||
return -e
|
d0, h0, m0 := t.Day(), t.Hour(), t.Minute()
|
||||||
}
|
d1, h1, m1 := g.Day(), g.Hour(), g.Minute()
|
||||||
return e
|
|
||||||
}
|
|
||||||
|
|
||||||
func isYearBissextil(year int) bool { return year%4 == 0 && !(year%100 == 0 && year%400 != 0) }
|
m := (d0-d1)*MinutePerDay + (h0-h1)*MinutePerHour + (m0 - m1)
|
||||||
|
return m / MinutePerHour, m % MillisecondPerHour
|
||||||
func daysInMonth(year int, month time.Month) int {
|
|
||||||
switch month {
|
|
||||||
case time.February:
|
|
||||||
if isYearBissextil(year) {
|
|
||||||
return 29
|
|
||||||
}
|
|
||||||
return 28
|
|
||||||
case time.April, time.June, time.September, time.November:
|
|
||||||
return 30
|
|
||||||
default:
|
|
||||||
return 31
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func internetHour(t time.Time) int {
|
|
||||||
t, _ = ToTimezone(t, "CET").Ok()
|
|
||||||
h, m, s := t.Clock()
|
|
||||||
n := t.Nanosecond()
|
|
||||||
d := time.Duration(n)*Nanosecond + time.Duration(s)*Second + time.Duration(m)*Minute + time.Duration(h)*Hour
|
|
||||||
i := d * 1000 / Day
|
|
||||||
return int(i)
|
|
||||||
}
|
|
||||||
|
|
||||||
func gmtDiff(t time.Time) time.Duration {
|
|
||||||
d0 := t.Day()
|
|
||||||
h0, m0, _ := t.Clock()
|
|
||||||
g, _ := ToTimezone(t, "GMT").Ok()
|
|
||||||
d1 := g.Day()
|
|
||||||
h1, m1, _ := t.Clock()
|
|
||||||
|
|
||||||
return time.Duration(d0-d1)*Day + time.Duration(h0-h1)*Hour + time.Duration(m0-m1)*Minute
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Jour
|
// Jour
|
||||||
|
@ -68,32 +35,27 @@ func format_n(t time.Time) string { return fmt.Sprintf("%d", t.Month()+1) }
|
||||||
func format_m(t time.Time) string { return fmt.Sprintf("%02d", t.Month()+1) }
|
func format_m(t time.Time) string { return fmt.Sprintf("%02d", t.Month()+1) }
|
||||||
func format_M(t time.Time) string { return shortMonths[t.Month()] }
|
func format_M(t time.Time) string { return shortMonths[t.Month()] }
|
||||||
func format_F(t time.Time) string { return longMonths[t.Month()] }
|
func format_F(t time.Time) string { return longMonths[t.Month()] }
|
||||||
func format_t(t time.Time) string { return fmt.Sprintf("%d", daysInMonth(t.Year(), t.Month())) }
|
func format_t(t time.Time) string { return fmt.Sprintf("%d", monthLen(t.Year(), uint(t.Month())+1)) }
|
||||||
|
|
||||||
// Année
|
// Année
|
||||||
func format_y(t time.Time) string { return fmt.Sprintf("%02d", t.Year()%100) }
|
func format_y(t time.Time) string { return fmt.Sprintf("%02d", t.Year()%100) }
|
||||||
func format_Y(t time.Time) string { return fmt.Sprintf("%d", t.Year()) }
|
func format_Y(t time.Time) string { return fmt.Sprintf("%d", t.Year()) }
|
||||||
func format_L(t time.Time) string {
|
func format_L(t time.Time) string {
|
||||||
if isYearBissextil(t.Year()) {
|
if bissextil(t.Year()) {
|
||||||
return "1"
|
return "1"
|
||||||
}
|
}
|
||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
|
|
||||||
// Heure
|
// Heure
|
||||||
func format_a(t time.Time) string {
|
func format_a(t time.Time) string { return amPmLow[t.Hour() < 12] }
|
||||||
if t.Hour() < 12 {
|
func format_A(t time.Time) string { return amPmUp[t.Hour() < 12] }
|
||||||
return "am"
|
func format_B(t time.Time) string {
|
||||||
}
|
h, m, s := t.Clock()
|
||||||
return "pm"
|
n := t.Nanosecond() / NanosecondPerMillisecond
|
||||||
|
|
||||||
|
return fmt.Sprintf("%03d", sit(uint(h), uint(m), uint(s), uint(n)))
|
||||||
}
|
}
|
||||||
func format_A(t time.Time) string {
|
|
||||||
if t.Hour() < 12 {
|
|
||||||
return "AM"
|
|
||||||
}
|
|
||||||
return "PM"
|
|
||||||
}
|
|
||||||
func format_B(t time.Time) string { return fmt.Sprintf("%03d", internetHour(t)) }
|
|
||||||
func format_g(t time.Time) string {
|
func format_g(t time.Time) string {
|
||||||
h := t.Hour() % 12
|
h := t.Hour() % 12
|
||||||
if h == 0 {
|
if h == 0 {
|
||||||
|
@ -112,8 +74,12 @@ func format_h(t time.Time) string {
|
||||||
func format_H(t time.Time) string { return fmt.Sprintf("%02d", t.Hour()) }
|
func format_H(t time.Time) string { return fmt.Sprintf("%02d", t.Hour()) }
|
||||||
func format_i(t time.Time) string { return fmt.Sprintf("%02d", t.Minute()) }
|
func format_i(t time.Time) string { return fmt.Sprintf("%02d", t.Minute()) }
|
||||||
func format_s(t time.Time) string { return fmt.Sprintf("%02d", t.Second()) }
|
func format_s(t time.Time) string { return fmt.Sprintf("%02d", t.Second()) }
|
||||||
func format_v(t time.Time) string { return fmt.Sprintf("%03d", t.Nanosecond()/1000000) }
|
func format_v(t time.Time) string {
|
||||||
func format_u(t time.Time) string { return fmt.Sprintf("%06d", t.Nanosecond()/1000) }
|
return fmt.Sprintf("%03d", t.Nanosecond()/NanosecondPerMillisecond)
|
||||||
|
}
|
||||||
|
func format_u(t time.Time) string {
|
||||||
|
return fmt.Sprintf("%06d", t.Nanosecond()/NanosecondPerMicrosecond)
|
||||||
|
}
|
||||||
|
|
||||||
// Fuseau horaire
|
// Fuseau horaire
|
||||||
func format_T(t time.Time) string {
|
func format_T(t time.Time) string {
|
||||||
|
@ -121,12 +87,12 @@ func format_T(t time.Time) string {
|
||||||
if !strings.Contains(name, "/") {
|
if !strings.Contains(name, "/") {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
diff := gmtDiff(t)
|
h, m := gmtDiff(t)
|
||||||
h, m := diff/Hour, (diff%Hour)/Minute
|
|
||||||
s := "+"
|
s := "+"
|
||||||
if h < 0 {
|
if h < 0 {
|
||||||
s = "-"
|
s = "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
if m == 0 {
|
if m == 0 {
|
||||||
return fmt.Sprintf("%s%02d", s, abs(h))
|
return fmt.Sprintf("%s%02d", s, abs(h))
|
||||||
}
|
}
|
||||||
|
@ -140,33 +106,37 @@ func format_I(t time.Time) string {
|
||||||
return "0"
|
return "0"
|
||||||
}
|
}
|
||||||
func format_O(t time.Time) string {
|
func format_O(t time.Time) string {
|
||||||
diff := gmtDiff(t)
|
h, m := gmtDiff(t)
|
||||||
h, m := diff/Hour, (diff%Hour)/Minute
|
|
||||||
s := "+"
|
s := "+"
|
||||||
if h < 0 {
|
if h < 0 {
|
||||||
s = "-"
|
s = "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s%02d%02d", s, abs(h), abs(m))
|
return fmt.Sprintf("%s%02d%02d", s, abs(h), abs(m))
|
||||||
}
|
}
|
||||||
func format_P(t time.Time) string {
|
func format_P(t time.Time) string {
|
||||||
diff := gmtDiff(t)
|
h, m := gmtDiff(t)
|
||||||
h, m := diff/Hour, (diff%Hour)/Minute
|
|
||||||
s := "+"
|
s := "+"
|
||||||
if h < 0 {
|
if h < 0 {
|
||||||
s = "-"
|
s = "-"
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Sprintf("%s%02d:%02d", s, abs(h), abs(m))
|
return fmt.Sprintf("%s%02d:%02d", s, abs(h), abs(m))
|
||||||
}
|
}
|
||||||
func format_p(t time.Time) string {
|
func format_p(t time.Time) string {
|
||||||
diff := gmtDiff(t)
|
h, m := gmtDiff(t)
|
||||||
|
diff := h*MinutePerHour + m
|
||||||
if diff == 0 {
|
if diff == 0 {
|
||||||
return "Z"
|
return "Z"
|
||||||
}
|
}
|
||||||
|
|
||||||
return format_P(t)
|
return format_P(t)
|
||||||
}
|
}
|
||||||
func format_Z(t time.Time) string {
|
func format_Z(t time.Time) string {
|
||||||
diff := gmtDiff(t)
|
h, m := gmtDiff(t)
|
||||||
return fmt.Sprintf("%d", diff/Second)
|
diff := h*SecondPerHour + m*SecondPerMinute
|
||||||
|
|
||||||
|
return fmt.Sprintf("%d", diff)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Date et heure complète
|
// Date et heure complète
|
||||||
|
@ -180,11 +150,7 @@ func format_r(t time.Time) string {
|
||||||
}
|
}
|
||||||
func format_U(t time.Time) string { return fmt.Sprintf("%d", t.Unix()) }
|
func format_U(t time.Time) string { return fmt.Sprintf("%d", t.Unix()) }
|
||||||
|
|
||||||
// Format retourne la représentation de la date dans le format indiqué.
|
func formatT(t time.Time, format string) string {
|
||||||
// Pour connaître toutes les options possibles pour le format, veullez consulter
|
|
||||||
// https://www.php.net/manual/fr/datetime.format.php
|
|
||||||
// (ou le fichier const.go).
|
|
||||||
func Format(t time.Time, format string) string {
|
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
|
|
||||||
runes := []rune(format)
|
runes := []rune(format)
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
package datetime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
)
|
|
||||||
|
|
||||||
// DaysInMonth retourne le nombre de jours dans le mois.
|
|
||||||
func DaysInMonth(t time.Time) int { return daysInMonth(t.Year(), t.Month()) }
|
|
||||||
|
|
||||||
// DaysInYear retourne le nombe de jours dans l’année.
|
|
||||||
func DaysInYear(t time.Time) int {
|
|
||||||
if IsBissextil(t) {
|
|
||||||
return 366
|
|
||||||
}
|
|
||||||
return 365
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsBissextil retourne vrai si la date est située dans une année bissextile.
|
|
||||||
func IsBissextil(t time.Time) bool { return isYearBissextil(t.Year()) }
|
|
||||||
|
|
||||||
// IsWeekend retourne vrai si la date est située dans le weekend.
|
|
||||||
func IsWeekend(t time.Time) bool {
|
|
||||||
d := t.Weekday()
|
|
||||||
|
|
||||||
return d != time.Saturday && d != time.Sunday
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsBeginOfMonth retourne vrai si la date est dans le premier jour du mois.
|
|
||||||
func IsBeginOfMonth(t time.Time) bool { return t.Day() == 1 }
|
|
||||||
|
|
||||||
// IsEndOfMonth retourne vrai si la date est dans le dernier jour du mois.
|
|
||||||
func IsEndOfMonth(t time.Time) bool { return t.Day() == DaysInMonth(t) }
|
|
||||||
|
|
||||||
// IsBeginOfYear retourne vrai si la date est dans le premier jour de l’année.
|
|
||||||
func IsBeginOfYear(t time.Time) bool { return IsBeginOfMonth(t) && t.Month() == time.January }
|
|
||||||
|
|
||||||
// IsEndOfYear retourne vrai si la date est dans le dernier jour de l’année.
|
|
||||||
func IsEndOfYear(t time.Time) bool { return IsEndOfMonth(t) && t.Month() == time.December }
|
|
||||||
|
|
||||||
// IsToday retourne vrai si la date est située aujourd’hui.
|
|
||||||
func IsToday(t time.Time) bool {
|
|
||||||
y, m, d := t.Date()
|
|
||||||
y0, m0, d0 := time.Now().In(t.Location()).Date()
|
|
||||||
|
|
||||||
return y == y0 && m == m0 && d == d0
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsTomorrow retourne vrai si la date est située demain.
|
|
||||||
func IsTomorrow(t time.Time) bool {
|
|
||||||
n := time.Now().In(t.Location())
|
|
||||||
y, m, d := t.Date()
|
|
||||||
y0, m0, d0 := n.Date()
|
|
||||||
|
|
||||||
if d > 1 {
|
|
||||||
return y == y0 && m == m0 && d == d0+1
|
|
||||||
}
|
|
||||||
|
|
||||||
if m > time.January {
|
|
||||||
return y == y0 && m == m0+1 && IsEndOfMonth(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
return y == y0+1 && IsEndOfYear(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsYesterday retourne vrai si la date est située hier.
|
|
||||||
func IsYesterday(t time.Time) bool {
|
|
||||||
n := time.Now().In(t.Location())
|
|
||||||
y, m, d := t.Date()
|
|
||||||
y0, m0, d0 := n.Date()
|
|
||||||
|
|
||||||
if d < DaysInMonth(t) {
|
|
||||||
return y == y0 && m == m0 && d == d0-1
|
|
||||||
}
|
|
||||||
|
|
||||||
if m < time.December {
|
|
||||||
return y == y0 && m == m0-1 && IsBeginOfMonth(n)
|
|
||||||
}
|
|
||||||
|
|
||||||
return y == y0-1 && IsBeginOfYear(n)
|
|
||||||
}
|
|
|
@ -1,266 +0,0 @@
|
||||||
package datetime
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
. "gitea.zaclys.com/bvaudour/gob/option"
|
|
||||||
)
|
|
||||||
|
|
||||||
func addUnit[I int | int64](t time.Time, duration I, unit time.Duration) time.Time {
|
|
||||||
return t.Add(time.Duration(duration) * unit)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddNanoseconds ajoute d ns à la date.
|
|
||||||
func AddNanoseconds[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Nanosecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddMicroseconds ajoute d μs à la date.
|
|
||||||
func AddMicroseconds[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Microsecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddMilliseconds ajoute d ms à la date.
|
|
||||||
func AddMilliseconds[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Millisecond)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddSeconds ajoute d s à la date.
|
|
||||||
func AddSeconds[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Second)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddMinutes ajoute d min à la date.
|
|
||||||
func AddMinutes[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Minute)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddHours ajoute d heures à la date.
|
|
||||||
func AddHours[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Hour)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddDays ajoute d jours à la date.
|
|
||||||
func AddDays[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Day)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddWeeks ajoute d semaines à la date.
|
|
||||||
func AddWeeks[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return addUnit(t, d, Week)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddMonths ajoute d mois à la date.
|
|
||||||
func AddMonths[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return t.AddDate(0, int(d), 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddYears ajoute d années à la date.
|
|
||||||
func AddYears[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return t.AddDate(int(d), 0, 0)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddDecades ajoute d×10 années à la date.
|
|
||||||
func AddDecades[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return AddYears(t, 10*d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddCenturies ajoute d siècles à la date.
|
|
||||||
func AddCenturies[I int | int64](t time.Time, d I) time.Time {
|
|
||||||
return AddYears(t, 100*d)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTZ(tz ...string) (result Option[*time.Location]) {
|
|
||||||
if len(tz) > 0 {
|
|
||||||
location, err := time.LoadLocation(tz[0])
|
|
||||||
if err == nil {
|
|
||||||
return Some(location)
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
return Some(DefaultTZ)
|
|
||||||
}
|
|
||||||
|
|
||||||
func toTZ(t time.Time, tz ...string) Result[time.Time] {
|
|
||||||
if l, ok := getTZ(tz...).Get(); ok {
|
|
||||||
return Ok(t.In(l))
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(tz) == 0 {
|
|
||||||
return Ok(t.In(DefaultTZ))
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err[time.Time](fmt.Errorf(errInvalidTZ, tz))
|
|
||||||
}
|
|
||||||
|
|
||||||
// ToTimezone retourne la date dans le fuseau horaire indiqué.
|
|
||||||
func ToTimezone(t time.Time, tz string) Result[time.Time] {
|
|
||||||
return toTZ(t, tz)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Local retourne la date dans le fuseau horaire local.
|
|
||||||
func Local(t time.Time) time.Time {
|
|
||||||
return t.In(time.Local)
|
|
||||||
}
|
|
||||||
|
|
||||||
// UTC retourne la date dans le fuseau UTC.
|
|
||||||
func UTC(t time.Time) time.Time {
|
|
||||||
return t.In(time.UTC)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Date modifie la date avec l’année, le mois et le jour fournis.
|
|
||||||
func Date(t time.Time, year, month, day int) time.Time {
|
|
||||||
h, m, s := t.Clock()
|
|
||||||
e := t.Nanosecond()
|
|
||||||
l := t.Location()
|
|
||||||
|
|
||||||
return time.Date(year, time.Month(month-1), day, h, m, s, e, l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clock modifie l’heure de la date.
|
|
||||||
func Clock(t time.Time, hour, minute, second int, nano ...int) time.Time {
|
|
||||||
y, m, d := t.Date()
|
|
||||||
l := t.Location()
|
|
||||||
e := 0
|
|
||||||
|
|
||||||
if len(nano) > 0 {
|
|
||||||
e = nano[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return time.Date(y, m, d, hour, minute, second, e, l)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetNano modifie les nanosecondes de la date.
|
|
||||||
func SetNano(t time.Time, nano int) time.Time {
|
|
||||||
h, m, s := t.Clock()
|
|
||||||
|
|
||||||
return Clock(t, h, m, s, nano)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetSecond modifie la seconde de la date (et éventuellement la ns).
|
|
||||||
func SetSecond(t time.Time, second int, nano ...int) time.Time {
|
|
||||||
h, m := t.Hour(), t.Minute()
|
|
||||||
e := t.Nanosecond()
|
|
||||||
if len(nano) > 0 {
|
|
||||||
e = nano[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return Clock(t, h, m, second, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMinute modifie la minute de la date (et éventuellement la s et la ns).
|
|
||||||
func SetMinute(t time.Time, minute int, other ...int) time.Time {
|
|
||||||
h, s, e := t.Hour(), t.Second(), t.Nanosecond()
|
|
||||||
if len(other) > 0 {
|
|
||||||
s = other[0]
|
|
||||||
if len(other) > 1 {
|
|
||||||
e = other[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Clock(t, h, minute, s, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetHour modifie l’heure de la date (et éventuellement la min, s & ns).
|
|
||||||
func SetHour(t time.Time, hour int, other ...int) time.Time {
|
|
||||||
m, s, e := t.Minute(), t.Second(), t.Nanosecond()
|
|
||||||
if len(other) > 0 {
|
|
||||||
m = other[0]
|
|
||||||
if len(other) > 1 {
|
|
||||||
s = other[1]
|
|
||||||
if len(other) > 2 {
|
|
||||||
e = other[2]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Clock(t, hour, m, s, e)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetDay modifie le jour de la date.
|
|
||||||
func SetDay(t time.Time, day int) time.Time {
|
|
||||||
y, m := t.Year(), t.Month()
|
|
||||||
|
|
||||||
return Date(t, y, int(m+1), day)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetMonth modifie le mois de la date (et éventuellement le jour).
|
|
||||||
func SetMonth(t time.Time, month int, day ...int) time.Time {
|
|
||||||
y, d := t.Year(), t.Day()
|
|
||||||
if len(day) > 0 {
|
|
||||||
d = day[0]
|
|
||||||
}
|
|
||||||
|
|
||||||
return Date(t, y, month, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetYear modifie l’année de la date (et éventuellement le mois et le jour).
|
|
||||||
func SetYear(t time.Time, year int, other ...int) time.Time {
|
|
||||||
m, d := int(t.Month()+1), t.Day()
|
|
||||||
if len(other) > 0 {
|
|
||||||
m = other[0]
|
|
||||||
if len(other) > 1 {
|
|
||||||
d = other[1]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Date(t, year, m, d)
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeginOfSecond retourne la date au début de la seconde en cours.
|
|
||||||
func BeginOfSecond(t time.Time) time.Time { return SetNano(t, 0) }
|
|
||||||
|
|
||||||
// EndOfSecond retourne la date à la fin de la seconde en cours.
|
|
||||||
func EndOfSecond(t time.Time) time.Time { return SetNano(t, 999999999) }
|
|
||||||
|
|
||||||
// BeginOfMinute retourne la date au début de la minute en cours.
|
|
||||||
func BeginOfMinute(t time.Time) time.Time { return SetSecond(t, 0, 0) }
|
|
||||||
|
|
||||||
// EndOfMinute retourne la date à la fin de la minute en cours.
|
|
||||||
func EndOfMinute(t time.Time) time.Time { return SetSecond(t, 59, 999999999) }
|
|
||||||
|
|
||||||
// BeginOfHour retourne la date au début de l’heure en cours.
|
|
||||||
func BeginOfHour(t time.Time) time.Time { return SetMinute(t, 0, 0, 0) }
|
|
||||||
|
|
||||||
// EndOfHour retourne la date à la fin de l’heure en cours.
|
|
||||||
func EndOfHour(t time.Time) time.Time { return SetMinute(t, 59, 59, 999999999) }
|
|
||||||
|
|
||||||
// BeginOfDay retourne la date au début du jour en cours.
|
|
||||||
func BeginOfDay(t time.Time) time.Time { return SetHour(t, 0, 0, 0, 0) }
|
|
||||||
|
|
||||||
// EndOfDay retourne la date à la fin du jour en cours.
|
|
||||||
func EndOfDay(t time.Time) time.Time { return SetHour(t, 23, 59, 59, 999999999) }
|
|
||||||
|
|
||||||
// BeginOfWeek retourne la date au début de la semaine en cours.
|
|
||||||
func BeginOfWeek(t time.Time) time.Time {
|
|
||||||
d := t.Weekday()
|
|
||||||
if d == time.Sunday {
|
|
||||||
d += 7
|
|
||||||
}
|
|
||||||
|
|
||||||
return BeginOfDay(t.AddDate(0, 0, 1-int(d)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// EndOfWeek retourne la date à la fin de la semaine en cours.
|
|
||||||
func EndOfWeek(t time.Time) time.Time {
|
|
||||||
d := t.Weekday()
|
|
||||||
if d == time.Sunday {
|
|
||||||
d += 7
|
|
||||||
}
|
|
||||||
|
|
||||||
return EndOfDay(t.AddDate(0, 0, 7-int(d)))
|
|
||||||
}
|
|
||||||
|
|
||||||
// BeginOfMonth retourne la date au début du mois en cours.
|
|
||||||
func BeginOfMonth(t time.Time) time.Time { return BeginOfDay(SetDay(t, 1)) }
|
|
||||||
|
|
||||||
// EndOfMonth retourne la date à la fin du mois en cours.
|
|
||||||
func EndOfMonth(t time.Time) time.Time { return EndOfDay(SetDay(t, DaysInMonth(t))) }
|
|
||||||
|
|
||||||
// BeginOfYear retourne la date au début de l’année en cours.
|
|
||||||
func BeginOfYear(t time.Time) time.Time { return BeginOfDay(SetMonth(t, 1, 1)) }
|
|
||||||
|
|
||||||
// EndOfYear retourne la date à la fin de l’année en cours.
|
|
||||||
func EndOfYear(t time.Time) time.Time { return EndOfDay(SetMonth(t, 12, 31)) }
|
|
|
@ -1,23 +1,25 @@
|
||||||
package datetime
|
package datetime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
. "gitea.zaclys.com/bvaudour/gob/option"
|
. "gitea.zaclys.com/bvaudour/gob/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func isValueZero(e string) bool {
|
||||||
|
return e == "" || e == "0" || e == "0000-00-00 00:00:00" || e == "0000-00-00" || e == "00:00:00"
|
||||||
|
}
|
||||||
|
|
||||||
func format2layout(f string) string {
|
func format2layout(f string) string {
|
||||||
var buffer strings.Builder
|
var buffer strings.Builder
|
||||||
|
|
||||||
runes := []rune(f)
|
runes := []rune(f)
|
||||||
for i := 0; i < len(runes); i++ {
|
for i := 0; i < len(runes); i++ {
|
||||||
if layout, ok := parsers[runes[i]]; ok {
|
if layout, ok := parsers[runes[i]]; ok {
|
||||||
buffer.WriteString(layout)
|
buffer.WriteString(layout)
|
||||||
} else {
|
} else {
|
||||||
switch runes[i] {
|
switch runes[i] {
|
||||||
case '\\': // raw output, no parse
|
case '\\': // Indique que le caractère suivant ne doit pas être parsé
|
||||||
buffer.WriteRune(runes[i+1])
|
buffer.WriteRune(runes[i+1])
|
||||||
i++
|
i++
|
||||||
continue
|
continue
|
||||||
|
@ -26,70 +28,43 @@ func format2layout(f string) string {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return buffer.String()
|
return buffer.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseInLocation(value, layout string, tz ...string) Result[time.Time] {
|
func parseInLocation(e, f string, tz ...string) (t Option[time.Time]) {
|
||||||
location := DefaultTZ
|
l := timezone(tz...)
|
||||||
if len(tz) > 0 {
|
if tt, err := time.ParseInLocation(f, e, l); err == nil {
|
||||||
var err error
|
t = Some(tt)
|
||||||
if location, err = time.LoadLocation(tz[0]); err != nil {
|
|
||||||
return Err[time.Time](fmt.Errorf(errInvalidTZ, tz[0]))
|
|
||||||
}
|
}
|
||||||
}
|
return
|
||||||
|
|
||||||
t, err := time.ParseInLocation(layout, value, location)
|
|
||||||
if err == nil {
|
|
||||||
return Ok(t)
|
|
||||||
}
|
|
||||||
return Err[time.Time](fmt.Errorf(errInvalidValue, value))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Guess tente de parser la chaîne de caractères en date en essayant de deviner le format.
|
func parseFromLayout(e, f string, tz ...string) (t Option[time.Time]) {
|
||||||
// Si le fuseau horaire n’est pas précisé dans la chaîne, le fuseau utilisé est tz (si fourni) ou le fuseau horaire par défaut.
|
if isValueZero(e) {
|
||||||
func Guess(value string, tz ...string) Result[time.Time] {
|
return
|
||||||
if value == "" || value == "0" || value == "0000-00-00 00:00:00" || value == "0000-00-00" || value == "00:00:00" {
|
|
||||||
return Zero(tz...)
|
|
||||||
}
|
}
|
||||||
|
return parseInLocation(e, f, tz...)
|
||||||
|
}
|
||||||
|
|
||||||
switch value {
|
func guess(e string, tz ...string) (t Option[time.Time]) {
|
||||||
|
if isValueZero(e) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch e {
|
||||||
case "now":
|
case "now":
|
||||||
return Now(tz...)
|
return Some(now(tz...))
|
||||||
case "yesterday":
|
case "yesterday":
|
||||||
return Yesterday(tz...)
|
return Some(yesterday(tz...))
|
||||||
case "tomorrow":
|
case "tomorrow":
|
||||||
return Tomorrow(tz...)
|
return Some(tomorrow(tz...))
|
||||||
}
|
}
|
||||||
|
for _, l := range layouts {
|
||||||
if len(tz) > 0 {
|
if t = parseInLocation(e, l, tz...); t.IsDefined() {
|
||||||
if _, err := time.LoadLocation(tz[0]); err != nil {
|
break
|
||||||
return Err[time.Time](fmt.Errorf(errInvalidTZ, tz[0]))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return
|
||||||
for _, layout := range layouts {
|
|
||||||
t := parseInLocation(layout, value, tz...)
|
|
||||||
if t.IsOk() {
|
|
||||||
return t
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err[time.Time](fmt.Errorf(errInvalidValue, value))
|
|
||||||
}
|
}
|
||||||
|
func parse(e, f string, tz ...string) Option[time.Time] {
|
||||||
// ParseFromLayout parse la chaîne de caractères en date à partir du layout (façon Go) fourni.
|
return parseFromLayout(e, format2layout(f), tz...)
|
||||||
// Si le fuseau horaire n’est pas précisé dans la chaîne, le fuseau utilisé est tz (si fourni) ou le fuseau horaire par défaut.
|
|
||||||
func ParseFromLayout(value, layout string, tz ...string) Result[time.Time] {
|
|
||||||
if value == "" || value == "0" || value == "0000-00-00 00:00:00" || value == "0000-00-00" || value == "00:00:00" {
|
|
||||||
return Zero(tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
return parseInLocation(value, layout, tz...)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse parse la chaîne de caractères en date à partir du format (dans le style PHP) fourni.
|
|
||||||
// Si le fuseau horaire n’est pas précisé dans la chaîne, le fuseau utilisé est tz (si fourni) ou le fuseau horaire par défaut.
|
|
||||||
func Parse(value, format string, tz ...string) Result[time.Time] {
|
|
||||||
return ParseFromLayout(value, format2layout(format), tz...)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,119 +1,155 @@
|
||||||
package datetime
|
package datetime
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"time"
|
|
||||||
|
|
||||||
. "gitea.zaclys.com/bvaudour/gob/option"
|
. "gitea.zaclys.com/bvaudour/gob/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Range représente une période entre deux dates.
|
// TimeComparator représente tout type d’indication de temps.
|
||||||
type Range struct {
|
type TimeComparator[E any] interface {
|
||||||
begin time.Time
|
Eq(E) bool
|
||||||
end time.Time
|
Ne(E) bool
|
||||||
|
Gt(E) bool
|
||||||
|
Ge(E) bool
|
||||||
|
Lt(E) bool
|
||||||
|
Le(E) bool
|
||||||
|
IsNow() bool
|
||||||
|
IsPast() bool
|
||||||
|
IsFuture() bool
|
||||||
|
Now() E
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewRange initialise une période.
|
// Min retourne le temps le plus petit.
|
||||||
// Si t1 > t2, la date début de la période sera t2, et inversement si t1 < t2.
|
func Min[C TimeComparator[C]](e C, args ...C) C {
|
||||||
func NewRange(t1, t2 time.Time) Range {
|
out := e
|
||||||
if Gt(t1, t2) {
|
for _, a := range args {
|
||||||
t1, t2 = t2, t1
|
if a.Lt(out) {
|
||||||
|
out = a
|
||||||
}
|
}
|
||||||
|
|
||||||
return Range{
|
|
||||||
begin: t1,
|
|
||||||
end: t2,
|
|
||||||
}
|
}
|
||||||
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
// Begin retourne la date de début de la période.
|
// Max retourne le temps le plus grand.
|
||||||
func (r Range) Begin() time.Time { return r.begin }
|
func Max[C TimeComparator[C]](e C, args ...C) C {
|
||||||
|
out := e
|
||||||
|
for _, a := range args {
|
||||||
|
if a.Gt(out) {
|
||||||
|
out = a
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
// End retourne la date de fin de la période.
|
// Range représente une période entre deux bornes temporelles.
|
||||||
func (r Range) End() time.Time { return r.end }
|
type Range[C TimeComparator[C]] struct {
|
||||||
|
begin, end C
|
||||||
|
}
|
||||||
|
|
||||||
// BeforeDate retourne vrai si la date est située avant la période.
|
// NewRange retourne une période entre begin et end.
|
||||||
func (r Range) BeforeDate(t time.Time) bool { return Lt(r.end, t) }
|
// Si begin < end, les bornes sont inversées.
|
||||||
|
func NewRange[C TimeComparator[C]](begin, end C) Range[C] {
|
||||||
|
if begin.Gt(end) {
|
||||||
|
begin, end = end, begin
|
||||||
|
}
|
||||||
|
|
||||||
// AfterDate retourne vrai si la date est située après la période.
|
return Range[C]{begin, end}
|
||||||
func (r Range) AfterDate(t time.Time) bool { return Gt(r.begin, t) }
|
}
|
||||||
|
|
||||||
// ContainsDate retourne vrai si t ∈ [begin; end].
|
// Begin retourne le début de la période.
|
||||||
func (r Range) ContainsDate(t time.Time) bool { return Le(r.begin, t) && Ge(r.end, t) }
|
func (r Range[C]) Begin() C { return r.begin }
|
||||||
|
|
||||||
// ContainsDateStrictBegin retourne vrai si t ∈ ]begin; end].
|
// End retourne la fin de la période.
|
||||||
func (r Range) ContainsDateStrictBegin(t time.Time) bool { return Lt(r.begin, t) && Ge(r.end, t) }
|
func (r Range[C]) End() C { return r.end }
|
||||||
|
|
||||||
// ContainsDateStrictEnd retourne vrai si t ∈ [begin; end[.
|
// Before retourne vrai si e est située avant la période.
|
||||||
func (r Range) ContainsDateStrictEnd(t time.Time) bool { return Le(r.begin, t) && Gt(r.end, t) }
|
func (r Range[C]) Before(e C) bool { return e.Lt(r.begin) }
|
||||||
|
|
||||||
// ContainsDateStrict retourne vrai si t ∈ ]begin; end[.
|
// After retourne vrai si e est située après la période.
|
||||||
func (r Range) ContainsDateStrict(t time.Time) bool { return Lt(r.begin, t) && Gt(r.end, t) }
|
func (r Range[C]) After(e C) bool { return e.Gt(r.end) }
|
||||||
|
|
||||||
// IsFuture retourne vrai si la période est située dans le futur.
|
// Contains retourne vrai si e ∈ [begin;end].
|
||||||
func (r Range) IsFuture() bool { return r.AfterDate(time.Now()) }
|
func (r Range[C]) Contains(e C) bool { return e.Ge(r.begin) && e.Le(r.end) }
|
||||||
|
|
||||||
// IsPast retourne vrai si la période est située dans le passé.
|
// ContainsStrictLeft retourne vrai si e ∈ ]begin;end].
|
||||||
func (r Range) IsPast() bool { return r.BeforeDate(time.Now()) }
|
func (r Range[C]) ContainsStrictLeft(e C) bool { return e.Gt(r.begin) && e.Le(r.end) }
|
||||||
|
|
||||||
|
// ContainsStrictRight retourne vrai si e ∈ [begin;end[.
|
||||||
|
func (r Range[C]) ContainsStrictRight(e C) bool { return e.Ge(r.begin) && e.Lt(r.end) }
|
||||||
|
|
||||||
|
// ContainsStrict retourne vrai si e ∈ ]begin;end[.
|
||||||
|
func (r Range[C]) ContainsStrict(e C) bool { return e.Gt(r.begin) && e.Lt(r.end) }
|
||||||
|
|
||||||
// IsNow retourne vrai si la période est en cours.
|
// IsNow retourne vrai si la période est en cours.
|
||||||
func (r Range) IsNow() bool { return r.ContainsDate(time.Now()) }
|
func (r Range[C]) IsNow() bool { return r.Contains(r.begin.Now()) }
|
||||||
|
|
||||||
// Before retourne vrai si r est avant r2 sans la recouvrir.
|
// IsPast retourne vrai si la période est située dans le passé.
|
||||||
func (r Range) Before(r2 Range) bool { return Le(r.end, r2.begin) }
|
func (r Range[C]) IsPast() bool { return r.Before(r.begin.Now()) }
|
||||||
|
|
||||||
// After retourne vrai si r est après r2 sans la recouvrir.
|
// IsFuture retourne vrai la période est située dans le futur.
|
||||||
func (r Range) After(r2 Range) bool { return Ge(r.begin, r2.end) }
|
func (r Range[C]) IsFuture() bool { return r.After(r.begin.Now()) }
|
||||||
|
|
||||||
// Contains retourne vrai si r inclut complètement r2.
|
// BeforeRange retourne vrai si r1 est terminée avant que r2 commence.
|
||||||
func (r Range) Contains(r2 Range) bool { return Le(r.begin, r2.begin) && Ge(r.end, r2.end) }
|
func (r1 Range[C]) BeforeRange(r2 Range[C]) bool { return r1.end.Le(r2.begin) }
|
||||||
|
|
||||||
// In retourne vrai si r est complètement inclus dans r2.
|
// AfterRange retourne vrai si r2 est terminée avec que r1 commence.
|
||||||
func (r Range) In(r2 Range) bool { return r2.Contains(r) }
|
func (r1 Range[C]) AfterRange(r2 Range[C]) bool { return r2.BeforeRange(r1) }
|
||||||
|
|
||||||
// Excludes retourne vrai si les périodes ne se chevauchent pas.
|
// ContainsRange retourne vrai si r2 est intégralement comprise dans r1.
|
||||||
func (r Range) Excludes(r2 Range) bool { return Le(r.end, r2.begin) || Ge(r.begin, r2.end) }
|
func (r1 Range[C]) ContainsRange(r2 Range[C]) bool {
|
||||||
|
return r1.begin.Le(r2.begin) && r1.end.Ge(r2.end)
|
||||||
|
}
|
||||||
|
|
||||||
// Overlaps retourne vrai si les périodes se chevauchent.
|
// InRange retourne vrai si r2 comprend intégralement r1.
|
||||||
func (r Range) Overlaps(r2 Range) bool { return Lt(r.begin, r2.end) && Gt(r.end, r2.begin) }
|
func (r1 Range[C]) InRange(r2 Range[C]) bool { return r2.ContainsRange(r1) }
|
||||||
|
|
||||||
// Intersection retourne la période commune aux deux périodes, si elle existe.
|
// Excludes retourne vrai si r1 et r2 ne se chevauchent pas.
|
||||||
func (r Range) Intersection(r2 Range) (result Option[Range]) {
|
func (r1 Range[C]) Excludes(r2 Range[C]) bool {
|
||||||
if r.Overlaps(r2) {
|
return r1.end.Le(r2.begin) || r1.begin.Ge(r2.end)
|
||||||
result = Some(NewRange(Max(r.begin, r2.begin), Min(r.end, r2.end)))
|
}
|
||||||
|
|
||||||
|
// Overlaps retourne vrai si r1 et r2 se chevauchent.
|
||||||
|
func (r1 Range[C]) Overlaps(r2 Range[C]) bool {
|
||||||
|
return r1.begin.Lt(r2.end) && r1.end.Gt(r2.begin)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intersection retourne la période commune entre deux périodes.
|
||||||
|
func (r1 Range[C]) Intersection(r2 Range[C]) (result Option[Range[C]]) {
|
||||||
|
if r1.Overlaps(r2) {
|
||||||
|
result = Some(NewRange(Max(r1.begin, r2.begin), Min(r1.end, r2.end)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Joins retourne la plus grande période contiguë entre deux période, si elle existe.
|
// Joins retourne la plus grande période contiguë formée par deux périodes.
|
||||||
func (r Range) Joins(r2 Range) (result Option[Range]) {
|
func (r1 Range[C]) Joins(r2 Range[C]) (result Option[Range[C]]) {
|
||||||
if Le(r.begin, r2.end) && Ge(r.end, r2.begin) {
|
if r1.begin.Le(r2.end) && r1.end.Ge(r2.begin) {
|
||||||
result = Some(NewRange(Min(r.begin, r2.begin), Max(r.end, r2.end)))
|
result = Some(NewRange(Min(r1.begin, r2.begin), Max(r1.end, r2.end)))
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Diff retourne l’ensemble des périodes non communes aux deux périodes.
|
// Diff retourne la liste des périodes qui ne se chevauchent pas.
|
||||||
func (r Range) Diff(r2 Range) (result []Range) {
|
func (r1 Range[C]) Diff(r2 Range[C]) (result []Range[C]) {
|
||||||
if Ne(r.begin, r2.begin) {
|
if r1.begin.Ne(r2.begin) {
|
||||||
begin := Min(r.begin, r2.begin)
|
begin := Min(r1.begin, r2.begin)
|
||||||
var end time.Time
|
var end C
|
||||||
if begin == r.begin {
|
if begin.Eq(r1.begin) {
|
||||||
end = Min(r.end, r2.begin)
|
end = Min(r1.end, r2.begin)
|
||||||
} else {
|
} else {
|
||||||
end = Min(r2.end, r.begin)
|
end = Min(r2.end, r1.begin)
|
||||||
}
|
}
|
||||||
result = append(result, NewRange(begin, end))
|
result = append(result, NewRange(begin, end))
|
||||||
}
|
}
|
||||||
|
|
||||||
if Ne(r.end, r2.end) {
|
if r1.end.Ne(r2.end) {
|
||||||
end := Max(r.end, r2.end)
|
end := Max(r1.end, r2.end)
|
||||||
var begin time.Time
|
var begin C
|
||||||
if end == r.end {
|
if end.Eq(r1.end) {
|
||||||
begin = Max(r.begin, r2.end)
|
begin = Max(r1.begin, r2.end)
|
||||||
} else {
|
} else {
|
||||||
begin = Max(r2.begin, r.end)
|
begin = Max(r2.begin, r1.end)
|
||||||
}
|
}
|
||||||
result = append(result, NewRange(begin, end))
|
result = append(result, NewRange(begin, end))
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,133 @@
|
||||||
|
package datetime
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type integer interface {
|
||||||
|
~int | ~int8 | ~int16 | ~int32 | ~int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type uinteger interface {
|
||||||
|
~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64
|
||||||
|
}
|
||||||
|
|
||||||
|
type float interface {
|
||||||
|
~float32 | ~float64
|
||||||
|
}
|
||||||
|
|
||||||
|
type number interface {
|
||||||
|
integer | uinteger | float
|
||||||
|
}
|
||||||
|
|
||||||
|
func cmp[N number](n1, n2 N) int {
|
||||||
|
switch {
|
||||||
|
case n1 < n2:
|
||||||
|
return -1
|
||||||
|
case n1 == n2:
|
||||||
|
return 0
|
||||||
|
default:
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func abs[N integer | float](n N) N {
|
||||||
|
if n < 0 {
|
||||||
|
return -n
|
||||||
|
}
|
||||||
|
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func spl[N integer | uinteger](e []N, n int) (ed, ec []N) {
|
||||||
|
ed = e
|
||||||
|
if len(e) > n {
|
||||||
|
ed, ec = e[:n], e[n:]
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func bissextil(y int) bool { return y%4 == 0 && !(y%100 == 0 && y%400 != 0) }
|
||||||
|
func monthLen(y int, m uint) uint {
|
||||||
|
switch m {
|
||||||
|
case February:
|
||||||
|
if bissextil(y) {
|
||||||
|
return 29
|
||||||
|
}
|
||||||
|
return 28
|
||||||
|
case April, June, September, November:
|
||||||
|
return 30
|
||||||
|
case January, March, May, July, August, October, December:
|
||||||
|
return 31
|
||||||
|
default:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func yearLen(y int) uint {
|
||||||
|
if bissextil(y) {
|
||||||
|
return 366
|
||||||
|
}
|
||||||
|
return 365
|
||||||
|
}
|
||||||
|
|
||||||
|
func sit(h, i uint, args ...uint) float64 {
|
||||||
|
var s, v uint
|
||||||
|
if len(args) > 0 {
|
||||||
|
s = args[0]
|
||||||
|
if len(args) > 1 {
|
||||||
|
v = args[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
v += s*MillisecondPerSecond + i*MillisecondPerMinute + h*MillisecondPerHour
|
||||||
|
return float64(v) * float64(BeatPerDay) / float64(MillisecondPerDay)
|
||||||
|
}
|
||||||
|
|
||||||
|
func timezone(tz ...string) *time.Location {
|
||||||
|
if len(tz) > 0 {
|
||||||
|
if l, err := time.LoadLocation(tz[0]); err == nil {
|
||||||
|
return l
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DefaultTZ
|
||||||
|
}
|
||||||
|
func toTZ(t time.Time, tz ...string) time.Time { return t.In(timezone(tz...)) }
|
||||||
|
func now(tz ...string) time.Time { return toTZ(time.Now(), tz...) }
|
||||||
|
func yesterday(tz ...string) time.Time { return now(tz...).AddDate(0, 0, -1) }
|
||||||
|
func tomorrow(tz ...string) time.Time { return now(tz...).AddDate(0, 0, 1) }
|
||||||
|
|
||||||
|
func fromDT(y int, m, d, h, i, s, v uint, l *time.Location) time.Time {
|
||||||
|
return time.Date(y, time.Month(m-1), int(d), int(h), int(i), int(s), int(d*NanosecondPerMillisecond), l)
|
||||||
|
}
|
||||||
|
func fromD(y int, m, d uint, l *time.Location) time.Time { return fromDT(y, m, d, 0, 0, 0, 0, l) }
|
||||||
|
func fromT(h, i, s, v uint, l *time.Location) time.Time {
|
||||||
|
t := now().In(l)
|
||||||
|
y, m, d := t.Year(), uint(t.Month()-1), uint(t.Day())
|
||||||
|
return fromDT(y, m, d, h, i, s, v, l)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clock
|
||||||
|
func formatC(h, i uint, args ...uint) (uint, uint, uint, uint, Precision) {
|
||||||
|
l := len(args)
|
||||||
|
p, s, v := PrecisionMinute-Precision(l), uint(0), uint(0)
|
||||||
|
if l > 0 {
|
||||||
|
s = args[0]
|
||||||
|
if l > 1 {
|
||||||
|
v = args[1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return h, i, s, v, p
|
||||||
|
}
|
||||||
|
func ms(h, i, s, n uint) uint {
|
||||||
|
return h*MillisecondPerHour + i*MillisecondPerMinute + s*MillisecondPerSecond + n
|
||||||
|
}
|
||||||
|
|
||||||
|
// Date
|
||||||
|
func validM(m uint) bool { return m >= January && m <= December }
|
||||||
|
func validD(y int, m, d uint) bool { return validM(m) && d > 0 && d < monthLen(y, m) }
|
||||||
|
func getD[N integer | uinteger](d date, t string) N { return N((d & maskDate[t]) >> shiftDate[t]) }
|
||||||
|
func setD[N integer | uinteger](e N, t string) date { return date(e<<shiftDate[t]) & maskDate[t] }
|
||||||
|
func replD[N integer | uinteger](d date, e N, t string) date {
|
||||||
|
return (d & ^maskDate[t]) | setD(e, t)
|
||||||
|
}
|
||||||
|
|
||||||
|
func diffBow(d uint) int { return int(Monday) - ((int(d) + DayPerWeek) % DayPerWeek) }
|
||||||
|
func diffEow(d uint) int { return DayPerWeek - ((int(d) + DayPerWeek) % DayPerWeek) }
|
Loading…
Reference in New Issue