gob/datetime/date.go

375 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

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

package datetime
import (
"time"
)
type 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 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 dune 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 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 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 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 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 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.
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 à 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 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) }