gob/datetime/date.go

392 lines
12 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package datetime
import (
"time"
)
type 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 lheure 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 à partir de lannée, du mois et du jour.
// Si le fuseau horaire tz est renseigné, cest le fuseau utilisé,
// sinon, cest le fuseau par défaut.
func NewDate(y int, m, d uint, tz ...string) Date {
return newDate(newD(y, m, d), timezone(tz...))
}
// NewDateFromTime retourne la date à partir dune date Go t.
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...)) }
// Now retourne la date actuelle dans le même fuseau horaire que t.
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 e 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 lanné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 lanné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 lanné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 retourne 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 lanné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 lanné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 lanné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 lanné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 w 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 dune 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 lannée.
func (t Date) BeginOfYear() Date { return newDate(t.bY(), t.location) }
// EndOfYear retourne la date du dernier jour de lanné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 (e. dimanche).
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))
}
// InTZ agit comme In mais en fournissant le fuseau horaire sous forme
// de chaîne de caractères.
func (t Date) ToTimezone(tz string) Date { return t.In(timezone(tz)) }
// TZ retourne le fuseau horaire.
func (t Date) TZ() *time.Location { return t.location }
// IsDST retourne vrai si le fuseau horaire est à lheure 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 millisecondes.
func (t Date) TimestampMilli() int64 { return t.tv(t.location) }
// Compare compare 2 dates.
// La comparaison seffectue après normalisation, ie. dans le même fuseau horaire.
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 }
// IsNow retourne vrai si la date est située aujourdhui.
func (t Date) IsNow() bool { return t.Eq(t.Now()) }
// IsPast retourne vrai si la date est situé dans le passé.
func (t Date) IsPast() bool { return t.Lt(t.Now()) }
// IsFuture retourne vrai si la date est situé dans le futur.
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())
}
// DiffInDays retourne t1 - t2 en jours.
func (t1 Date) DiffInDays(t2 Date) int { return t1.subD(t2.date, t1.location, t2.location) }
// DiffInWeeks retourne t1 - t2 en semaines.
func (t1 Date) DiffInWeeks(t2 Date) int { return t1.subW(t2.date, t1.location, t2.location) }
// DiffInMonths retourne t1 - t2 en mois.
func (t1 Date) DiffInMonths(t2 Date) int { return t1.subM(t2.date) }
// DiffInYears retourne t1 - t2 en années.
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(f string) string { return t.f(f, t.location) }
// String retourne la date au format Y-m-d.
func (t Date) String() string { return t.str(t.location) }