Module datetime réécrit
This commit is contained in:
		
							parent
							
								
									0700fced7b
								
							
						
					
					
						commit
						41e37d8398
					
				
					 14 changed files with 1894 additions and 917 deletions
				
			
		
							
								
								
									
										414
									
								
								datetime/clock.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								datetime/clock.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
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 (
 | 
			
		||||
	// Fuseau horaire par défaut
 | 
			
		||||
	DefaultTZ = time.Local
 | 
			
		||||
	// représentation de l’unité sous forme de caractère
 | 
			
		||||
	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)
 | 
			
		||||
	shortDays = []string{
 | 
			
		||||
| 
						 | 
				
			
			@ -115,143 +335,22 @@ var (
 | 
			
		|||
		'U': format_U, // Secondes depuis l’époque Unix (1er Janvier 1970, 0h00 00s GMT)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	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)
 | 
			
		||||
	amPmLow = map[bool]string{
 | 
			
		||||
		true:  "am",
 | 
			
		||||
		false: "pm",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	layouts = []string{
 | 
			
		||||
		DayDateTimeLayout,
 | 
			
		||||
		DateTimeLayout, DateTimeNanoLayout, ShortDateTimeLayout, ShortDateTimeNanoLayout,
 | 
			
		||||
		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",
 | 
			
		||||
	amPmUp = map[bool]string{
 | 
			
		||||
		true:  "AM",
 | 
			
		||||
		false: "PM",
 | 
			
		||||
	}
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
const (
 | 
			
		||||
	// Unités de durée
 | 
			
		||||
	Nanosecond  = time.Nanosecond
 | 
			
		||||
	Microsecond = time.Microsecond
 | 
			
		||||
	Millisecond = time.Millisecond
 | 
			
		||||
	Second      = time.Second
 | 
			
		||||
	Minute      = time.Minute
 | 
			
		||||
	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"
 | 
			
		||||
 | 
			
		||||
	formatP = map[Precision]string{
 | 
			
		||||
		PrecisionMinute:      "H:iT",
 | 
			
		||||
		PrecisionSecond:      "H:i:sT",
 | 
			
		||||
		PrecisionMillisecond: "H:i:s.vT",
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// Fuseau horaire par défaut
 | 
			
		||||
	DefaultTZ = time.Local
 | 
			
		||||
)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -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...)
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										374
									
								
								datetime/date.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										374
									
								
								datetime/date.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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) }
 | 
			
		||||
							
								
								
									
										522
									
								
								datetime/datetime.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										522
									
								
								datetime/datetime.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"math"
 | 
			
		||||
	"time"
 | 
			
		||||
	"fmt"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// DiffInYears retourne (t1 - t2) exprimé en années.
 | 
			
		||||
func DiffInYears(t1, t2 time.Time) int64 {
 | 
			
		||||
	y1, m1, d1 := t1.Date()
 | 
			
		||||
	y2, m2, d2 := t2.Date()
 | 
			
		||||
// Unit est une unité de durée.
 | 
			
		||||
type Unit uint
 | 
			
		||||
 | 
			
		||||
	dy, dm, dd := y1-y2, m1-m2, d1-d2
 | 
			
		||||
	if dm < 0 || (dm == 0 && dd < 0) {
 | 
			
		||||
		dy--
 | 
			
		||||
	}
 | 
			
		||||
	if dy < 0 && (dd != 0 || dm != 0) {
 | 
			
		||||
		dy++
 | 
			
		||||
// Duration est une durée entre deux repères de temps.
 | 
			
		||||
type Duration int
 | 
			
		||||
 | 
			
		||||
// NewDuration retourne une durée à partir d’une valeur et d’une unité.
 | 
			
		||||
func NewDuration(value int, unit Unit) Duration {
 | 
			
		||||
	if unit == NoUnit {
 | 
			
		||||
		return DurationNil
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return int64(dy)
 | 
			
		||||
	return (Duration(value) << bitsUnit) | Duration(unit)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DiffInMonths retourne (t1 - t2) exprimé en mois.
 | 
			
		||||
func DiffInMonths(t1, t2 time.Time) int64 {
 | 
			
		||||
	y1, m1, d1 := t1.Date()
 | 
			
		||||
	y2, m2, d2 := t2.Date()
 | 
			
		||||
// Value retourne la valeur de la durée, sans l’unité.
 | 
			
		||||
func (d Duration) Value() int { return int(d >> bitsUnit) }
 | 
			
		||||
 | 
			
		||||
	dy, dm, dd := y1-y2, m1-m2, d1-d2
 | 
			
		||||
	if dd < 0 {
 | 
			
		||||
		dm--
 | 
			
		||||
	}
 | 
			
		||||
	if dy == 0 && dm == 0 {
 | 
			
		||||
		return int64(dm)
 | 
			
		||||
	}
 | 
			
		||||
	if dy == 0 && dm != 0 && dd != 0 {
 | 
			
		||||
		dh := abs(DiffInHours(t1, t2))
 | 
			
		||||
		if int(dh) < DaysInMonth(t1)*HoursPerDay {
 | 
			
		||||
			return int64(0)
 | 
			
		||||
		}
 | 
			
		||||
		return int64(dm)
 | 
			
		||||
// Unit retourne l’unité de durée.
 | 
			
		||||
func (d Duration) Unit() Unit { return Unit(d & maskUnit) }
 | 
			
		||||
 | 
			
		||||
// Duration retourne la valeur et l’unité de la durée.
 | 
			
		||||
func (d Duration) Duration() (int, Unit) { return d.Value(), d.Unit() }
 | 
			
		||||
 | 
			
		||||
// IsNil retourne vrai si la durée ne représente pas une durée valide.
 | 
			
		||||
func (d Duration) IsNil() bool { return d.Unit() == NoUnit }
 | 
			
		||||
 | 
			
		||||
// IsClock retourne vrai si la durée est dans une unité de temps sur 24h.
 | 
			
		||||
func (d Duration) IsClock() bool { u := d.Unit(); return u > NoUnit && u < Day }
 | 
			
		||||
 | 
			
		||||
// 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))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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()
 | 
			
		||||
	v, u := d.Value(), d.Unit()
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("%d%c", v, unitToByte[u])
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,46 +6,13 @@ import (
 | 
			
		|||
	"time"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
func abs[N ~int | ~int64](e N) N {
 | 
			
		||||
	if e < 0 {
 | 
			
		||||
		return -e
 | 
			
		||||
	}
 | 
			
		||||
	return e
 | 
			
		||||
}
 | 
			
		||||
func gmtDiff(t time.Time) (hour, minute int) {
 | 
			
		||||
	g := toTZ(t, "GMT")
 | 
			
		||||
	d0, h0, m0 := t.Day(), t.Hour(), t.Minute()
 | 
			
		||||
	d1, h1, m1 := g.Day(), g.Hour(), g.Minute()
 | 
			
		||||
 | 
			
		||||
func isYearBissextil(year int) bool { return year%4 == 0 && !(year%100 == 0 && year%400 != 0) }
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
	m := (d0-d1)*MinutePerDay + (h0-h1)*MinutePerHour + (m0 - m1)
 | 
			
		||||
	return m / MinutePerHour, m % MillisecondPerHour
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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 shortMonths[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
 | 
			
		||||
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_L(t time.Time) string {
 | 
			
		||||
	if isYearBissextil(t.Year()) {
 | 
			
		||||
	if bissextil(t.Year()) {
 | 
			
		||||
		return "1"
 | 
			
		||||
	}
 | 
			
		||||
	return "0"
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Heure
 | 
			
		||||
func format_a(t time.Time) string {
 | 
			
		||||
	if t.Hour() < 12 {
 | 
			
		||||
		return "am"
 | 
			
		||||
	}
 | 
			
		||||
	return "pm"
 | 
			
		||||
func format_a(t time.Time) string { return amPmLow[t.Hour() < 12] }
 | 
			
		||||
func format_A(t time.Time) string { return amPmUp[t.Hour() < 12] }
 | 
			
		||||
func format_B(t time.Time) string {
 | 
			
		||||
	h, m, s := t.Clock()
 | 
			
		||||
	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 {
 | 
			
		||||
	h := t.Hour() % 12
 | 
			
		||||
	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_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_v(t time.Time) string { return fmt.Sprintf("%03d", t.Nanosecond()/1000000) }
 | 
			
		||||
func format_u(t time.Time) string { return fmt.Sprintf("%06d", t.Nanosecond()/1000) }
 | 
			
		||||
func format_v(t time.Time) string {
 | 
			
		||||
	return fmt.Sprintf("%03d", t.Nanosecond()/NanosecondPerMillisecond)
 | 
			
		||||
}
 | 
			
		||||
func format_u(t time.Time) string {
 | 
			
		||||
	return fmt.Sprintf("%06d", t.Nanosecond()/NanosecondPerMicrosecond)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Fuseau horaire
 | 
			
		||||
func format_T(t time.Time) string {
 | 
			
		||||
| 
						 | 
				
			
			@ -121,12 +87,12 @@ func format_T(t time.Time) string {
 | 
			
		|||
	if !strings.Contains(name, "/") {
 | 
			
		||||
		return name
 | 
			
		||||
	}
 | 
			
		||||
	diff := gmtDiff(t)
 | 
			
		||||
	h, m := diff/Hour, (diff%Hour)/Minute
 | 
			
		||||
	h, m := gmtDiff(t)
 | 
			
		||||
	s := "+"
 | 
			
		||||
	if h < 0 {
 | 
			
		||||
		s = "-"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if m == 0 {
 | 
			
		||||
		return fmt.Sprintf("%s%02d", s, abs(h))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -140,33 +106,37 @@ func format_I(t time.Time) string {
 | 
			
		|||
	return "0"
 | 
			
		||||
}
 | 
			
		||||
func format_O(t time.Time) string {
 | 
			
		||||
	diff := gmtDiff(t)
 | 
			
		||||
	h, m := diff/Hour, (diff%Hour)/Minute
 | 
			
		||||
	h, m := gmtDiff(t)
 | 
			
		||||
	s := "+"
 | 
			
		||||
	if h < 0 {
 | 
			
		||||
		s = "-"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("%s%02d%02d", s, abs(h), abs(m))
 | 
			
		||||
}
 | 
			
		||||
func format_P(t time.Time) string {
 | 
			
		||||
	diff := gmtDiff(t)
 | 
			
		||||
	h, m := diff/Hour, (diff%Hour)/Minute
 | 
			
		||||
	h, m := gmtDiff(t)
 | 
			
		||||
	s := "+"
 | 
			
		||||
	if h < 0 {
 | 
			
		||||
		s = "-"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("%s%02d:%02d", s, abs(h), abs(m))
 | 
			
		||||
}
 | 
			
		||||
func format_p(t time.Time) string {
 | 
			
		||||
	diff := gmtDiff(t)
 | 
			
		||||
	h, m := gmtDiff(t)
 | 
			
		||||
	diff := h*MinutePerHour + m
 | 
			
		||||
	if diff == 0 {
 | 
			
		||||
		return "Z"
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return format_P(t)
 | 
			
		||||
}
 | 
			
		||||
func format_Z(t time.Time) string {
 | 
			
		||||
	diff := gmtDiff(t)
 | 
			
		||||
	return fmt.Sprintf("%d", diff/Second)
 | 
			
		||||
	h, m := gmtDiff(t)
 | 
			
		||||
	diff := h*SecondPerHour + m*SecondPerMinute
 | 
			
		||||
 | 
			
		||||
	return fmt.Sprintf("%d", diff)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// 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()) }
 | 
			
		||||
 | 
			
		||||
// Format retourne la représentation de la date dans le format indiqué.
 | 
			
		||||
// 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 {
 | 
			
		||||
func formatT(t time.Time, format string) string {
 | 
			
		||||
	var buffer strings.Builder
 | 
			
		||||
 | 
			
		||||
	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
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"strings"
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	. "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 {
 | 
			
		||||
	var buffer strings.Builder
 | 
			
		||||
 | 
			
		||||
	runes := []rune(f)
 | 
			
		||||
	for i := 0; i < len(runes); i++ {
 | 
			
		||||
		if layout, ok := parsers[runes[i]]; ok {
 | 
			
		||||
			buffer.WriteString(layout)
 | 
			
		||||
		} else {
 | 
			
		||||
			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])
 | 
			
		||||
				i++
 | 
			
		||||
				continue
 | 
			
		||||
| 
						 | 
				
			
			@ -26,70 +28,43 @@ func format2layout(f string) string {
 | 
			
		|||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return buffer.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
func parseInLocation(value, layout string, tz ...string) Result[time.Time] {
 | 
			
		||||
	location := DefaultTZ
 | 
			
		||||
	if len(tz) > 0 {
 | 
			
		||||
		var err error
 | 
			
		||||
		if location, err = time.LoadLocation(tz[0]); err != nil {
 | 
			
		||||
			return Err[time.Time](fmt.Errorf(errInvalidTZ, tz[0]))
 | 
			
		||||
		}
 | 
			
		||||
func parseInLocation(e, f string, tz ...string) (t Option[time.Time]) {
 | 
			
		||||
	l := timezone(tz...)
 | 
			
		||||
	if tt, err := time.ParseInLocation(f, e, l); err == nil {
 | 
			
		||||
		t = Some(tt)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	t, err := time.ParseInLocation(layout, value, location)
 | 
			
		||||
	if err == nil {
 | 
			
		||||
		return Ok(t)
 | 
			
		||||
	}
 | 
			
		||||
	return Err[time.Time](fmt.Errorf(errInvalidValue, value))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Guess tente de parser la chaîne de caractères en date en essayant de deviner le format.
 | 
			
		||||
// 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 Guess(value 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...)
 | 
			
		||||
func parseFromLayout(e, f string, tz ...string) (t Option[time.Time]) {
 | 
			
		||||
	if isValueZero(e) {
 | 
			
		||||
		return
 | 
			
		||||
	}
 | 
			
		||||
	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":
 | 
			
		||||
		return Now(tz...)
 | 
			
		||||
		return Some(now(tz...))
 | 
			
		||||
	case "yesterday":
 | 
			
		||||
		return Yesterday(tz...)
 | 
			
		||||
		return Some(yesterday(tz...))
 | 
			
		||||
	case "tomorrow":
 | 
			
		||||
		return Tomorrow(tz...)
 | 
			
		||||
		return Some(tomorrow(tz...))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if len(tz) > 0 {
 | 
			
		||||
		if _, err := time.LoadLocation(tz[0]); err != nil {
 | 
			
		||||
			return Err[time.Time](fmt.Errorf(errInvalidTZ, tz[0]))
 | 
			
		||||
	for _, l := range layouts {
 | 
			
		||||
		if t = parseInLocation(e, l, tz...); t.IsDefined() {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	for _, layout := range layouts {
 | 
			
		||||
		t := parseInLocation(layout, value, tz...)
 | 
			
		||||
		if t.IsOk() {
 | 
			
		||||
			return t
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Err[time.Time](fmt.Errorf(errInvalidValue, value))
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseFromLayout parse la chaîne de caractères en date à partir du layout (façon Go) 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 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...)
 | 
			
		||||
func parse(e, f string, tz ...string) Option[time.Time] {
 | 
			
		||||
	return parseFromLayout(e, format2layout(f), tz...)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,119 +1,155 @@
 | 
			
		|||
package datetime
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"time"
 | 
			
		||||
 | 
			
		||||
	. "gitea.zaclys.com/bvaudour/gob/option"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// Range représente une période entre deux dates.
 | 
			
		||||
type Range struct {
 | 
			
		||||
	begin time.Time
 | 
			
		||||
	end   time.Time
 | 
			
		||||
// TimeComparator représente tout type d’indication de temps.
 | 
			
		||||
type TimeComparator[E any] interface {
 | 
			
		||||
	Eq(E) bool
 | 
			
		||||
	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.
 | 
			
		||||
// Si t1 > t2, la date début de la période sera t2, et inversement si t1 < t2.
 | 
			
		||||
func NewRange(t1, t2 time.Time) Range {
 | 
			
		||||
	if Gt(t1, t2) {
 | 
			
		||||
		t1, t2 = t2, t1
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return Range{
 | 
			
		||||
		begin: t1,
 | 
			
		||||
		end:   t2,
 | 
			
		||||
// Min retourne le temps le plus petit.
 | 
			
		||||
func Min[C TimeComparator[C]](e C, args ...C) C {
 | 
			
		||||
	out := e
 | 
			
		||||
	for _, a := range args {
 | 
			
		||||
		if a.Lt(out) {
 | 
			
		||||
			out = a
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	return out
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Begin retourne la date de début de la période.
 | 
			
		||||
func (r Range) Begin() time.Time { return r.begin }
 | 
			
		||||
// Max retourne le temps le plus grand.
 | 
			
		||||
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.
 | 
			
		||||
func (r Range) End() time.Time { return r.end }
 | 
			
		||||
// Range représente une période entre deux bornes temporelles.
 | 
			
		||||
type Range[C TimeComparator[C]] struct {
 | 
			
		||||
	begin, end C
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// BeforeDate retourne vrai si la date est située avant la période.
 | 
			
		||||
func (r Range) BeforeDate(t time.Time) bool { return Lt(r.end, t) }
 | 
			
		||||
// NewRange retourne une période entre begin et end.
 | 
			
		||||
// 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.
 | 
			
		||||
func (r Range) AfterDate(t time.Time) bool { return Gt(r.begin, t) }
 | 
			
		||||
	return Range[C]{begin, end}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ContainsDate retourne vrai si t ∈ [begin; end].
 | 
			
		||||
func (r Range) ContainsDate(t time.Time) bool { return Le(r.begin, t) && Ge(r.end, t) }
 | 
			
		||||
// Begin retourne le début de la période.
 | 
			
		||||
func (r Range[C]) Begin() C { return r.begin }
 | 
			
		||||
 | 
			
		||||
// ContainsDateStrictBegin retourne vrai si t ∈ ]begin; end].
 | 
			
		||||
func (r Range) ContainsDateStrictBegin(t time.Time) bool { return Lt(r.begin, t) && Ge(r.end, t) }
 | 
			
		||||
// End retourne la fin de la période.
 | 
			
		||||
func (r Range[C]) End() C { return r.end }
 | 
			
		||||
 | 
			
		||||
// ContainsDateStrictEnd retourne vrai si t ∈ [begin; end[.
 | 
			
		||||
func (r Range) ContainsDateStrictEnd(t time.Time) bool { return Le(r.begin, t) && Gt(r.end, t) }
 | 
			
		||||
// Before retourne vrai si e est située avant la période.
 | 
			
		||||
func (r Range[C]) Before(e C) bool { return e.Lt(r.begin) }
 | 
			
		||||
 | 
			
		||||
// ContainsDateStrict retourne vrai si t ∈ ]begin; end[.
 | 
			
		||||
func (r Range) ContainsDateStrict(t time.Time) bool { return Lt(r.begin, t) && Gt(r.end, t) }
 | 
			
		||||
// After retourne vrai si e est située après la période.
 | 
			
		||||
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.
 | 
			
		||||
func (r Range) IsFuture() bool { return r.AfterDate(time.Now()) }
 | 
			
		||||
// Contains retourne vrai si e ∈ [begin;end].
 | 
			
		||||
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é.
 | 
			
		||||
func (r Range) IsPast() bool { return r.BeforeDate(time.Now()) }
 | 
			
		||||
// ContainsStrictLeft retourne vrai si e ∈ ]begin;end].
 | 
			
		||||
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.
 | 
			
		||||
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.
 | 
			
		||||
func (r Range) Before(r2 Range) bool { return Le(r.end, r2.begin) }
 | 
			
		||||
// IsPast retourne vrai si la période est située dans le passé.
 | 
			
		||||
func (r Range[C]) IsPast() bool { return r.Before(r.begin.Now()) }
 | 
			
		||||
 | 
			
		||||
// After retourne vrai si r est après r2 sans la recouvrir.
 | 
			
		||||
func (r Range) After(r2 Range) bool { return Ge(r.begin, r2.end) }
 | 
			
		||||
// IsFuture retourne vrai la période est située dans le futur.
 | 
			
		||||
func (r Range[C]) IsFuture() bool { return r.After(r.begin.Now()) }
 | 
			
		||||
 | 
			
		||||
// Contains retourne vrai si r inclut complètement r2.
 | 
			
		||||
func (r Range) Contains(r2 Range) bool { return Le(r.begin, r2.begin) && Ge(r.end, r2.end) }
 | 
			
		||||
// BeforeRange retourne vrai si r1 est terminée avant que r2 commence.
 | 
			
		||||
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.
 | 
			
		||||
func (r Range) In(r2 Range) bool { return r2.Contains(r) }
 | 
			
		||||
// AfterRange retourne vrai si r2 est terminée avec que r1 commence.
 | 
			
		||||
func (r1 Range[C]) AfterRange(r2 Range[C]) bool { return r2.BeforeRange(r1) }
 | 
			
		||||
 | 
			
		||||
// Excludes retourne vrai si les périodes ne se chevauchent pas.
 | 
			
		||||
func (r Range) Excludes(r2 Range) bool { return Le(r.end, r2.begin) || Ge(r.begin, r2.end) }
 | 
			
		||||
// ContainsRange retourne vrai si r2 est intégralement comprise dans r1.
 | 
			
		||||
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.
 | 
			
		||||
func (r Range) Overlaps(r2 Range) bool { return Lt(r.begin, r2.end) && Gt(r.end, r2.begin) }
 | 
			
		||||
// InRange retourne vrai si r2 comprend intégralement r1.
 | 
			
		||||
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.
 | 
			
		||||
func (r Range) Intersection(r2 Range) (result Option[Range]) {
 | 
			
		||||
	if r.Overlaps(r2) {
 | 
			
		||||
		result = Some(NewRange(Max(r.begin, r2.begin), Min(r.end, r2.end)))
 | 
			
		||||
// Excludes retourne vrai si r1 et r2 ne se chevauchent pas.
 | 
			
		||||
func (r1 Range[C]) Excludes(r2 Range[C]) bool {
 | 
			
		||||
	return r1.end.Le(r2.begin) || r1.begin.Ge(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
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Joins retourne la plus grande période contiguë entre deux période, si elle existe.
 | 
			
		||||
func (r Range) Joins(r2 Range) (result Option[Range]) {
 | 
			
		||||
	if Le(r.begin, r2.end) && Ge(r.end, r2.begin) {
 | 
			
		||||
		result = Some(NewRange(Min(r.begin, r2.begin), Max(r.end, r2.end)))
 | 
			
		||||
// Joins retourne la plus grande période contiguë formée par deux périodes.
 | 
			
		||||
func (r1 Range[C]) Joins(r2 Range[C]) (result Option[Range[C]]) {
 | 
			
		||||
	if r1.begin.Le(r2.end) && r1.end.Ge(r2.begin) {
 | 
			
		||||
		result = Some(NewRange(Min(r1.begin, r2.begin), Max(r1.end, r2.end)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Diff retourne l’ensemble des périodes non communes aux deux périodes.
 | 
			
		||||
func (r Range) Diff(r2 Range) (result []Range) {
 | 
			
		||||
	if Ne(r.begin, r2.begin) {
 | 
			
		||||
		begin := Min(r.begin, r2.begin)
 | 
			
		||||
		var end time.Time
 | 
			
		||||
		if begin == r.begin {
 | 
			
		||||
			end = Min(r.end, r2.begin)
 | 
			
		||||
// Diff retourne la liste des périodes qui ne se chevauchent pas.
 | 
			
		||||
func (r1 Range[C]) Diff(r2 Range[C]) (result []Range[C]) {
 | 
			
		||||
	if r1.begin.Ne(r2.begin) {
 | 
			
		||||
		begin := Min(r1.begin, r2.begin)
 | 
			
		||||
		var end C
 | 
			
		||||
		if begin.Eq(r1.begin) {
 | 
			
		||||
			end = Min(r1.end, r2.begin)
 | 
			
		||||
		} else {
 | 
			
		||||
			end = Min(r2.end, r.begin)
 | 
			
		||||
			end = Min(r2.end, r1.begin)
 | 
			
		||||
		}
 | 
			
		||||
		result = append(result, NewRange(begin, end))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if Ne(r.end, r2.end) {
 | 
			
		||||
		end := Max(r.end, r2.end)
 | 
			
		||||
		var begin time.Time
 | 
			
		||||
		if end == r.end {
 | 
			
		||||
			begin = Max(r.begin, r2.end)
 | 
			
		||||
	if r1.end.Ne(r2.end) {
 | 
			
		||||
		end := Max(r1.end, r2.end)
 | 
			
		||||
		var begin C
 | 
			
		||||
		if end.Eq(r1.end) {
 | 
			
		||||
			begin = Max(r1.begin, r2.end)
 | 
			
		||||
		} else {
 | 
			
		||||
			begin = Max(r2.begin, r.end)
 | 
			
		||||
			begin = Max(r2.begin, r1.end)
 | 
			
		||||
		}
 | 
			
		||||
		result = append(result, NewRange(begin, end))
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										133
									
								
								datetime/util.go
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										133
									
								
								datetime/util.go
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -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) }
 | 
			
		||||
							
								
								
									
										4
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										4
									
								
								go.mod
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
module gitea.zaclys.com/bvaudour/gob
 | 
			
		||||
 | 
			
		||||
go 1.21.1
 | 
			
		||||
go 1.21
 | 
			
		||||
 | 
			
		||||
require golang.org/x/crypto v0.13.0 // indirect
 | 
			
		||||
require golang.org/x/crypto v0.13.0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		
		Reference in a new issue