Màj du README + commentaires datetime plus précis + ajout de la méthode String() à Range & Duration + Parsage d’une durée + gestion des périodes avec borne infinie à droite et/ou à gauche

This commit is contained in:
Benjamin VAUDOUR 2023-11-04 11:39:54 +01:00
parent 41e37d8398
commit 976ac750b1
8 changed files with 277 additions and 123 deletions

View File

@ -37,6 +37,15 @@ Le paquet **convert** fournit le nécessaire pour convertir des variables typée
Tous ces types sont convertibles entre eux.
### datetime
Le paquet **datetime** implémente des structures pour gérer des temps :
- datetime.Clock : pour gérer une heure dans la journée,
- datetime.Date : pour gérer une date, sans indication de lheure,
- datetime.DateTime : pour gérer une date avec indication de lheure.
- Range : pour gérer une période entre deux temps.
### format
Le paquet **format** fournit le nécessaire pour formater la sortie terminal :

View File

@ -7,6 +7,14 @@ import (
type clock uint
// Precision représente la précision dune horloge.
// Par exemple :
// - 15:06 est une horloge précise à la minute,
// - 15:06:02 est précise à la seconde,
// - 15:06:02.257 est précise à la milliseconde.
//
// La précision est utilisée dans Clock pour les comparaisons :
// les comparaisons entre deux horloges se font à la précision
// le lhorloge la moins précise.
type Precision uint
func newC0(h, i uint, e ...uint) clock {
@ -213,11 +221,13 @@ 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.
// NewClock retourne une horloge à lheure h et la minute i dans le fuseau horaire par défaut.
// La précision est calculée automatiquement suivant que la seconde et la milliseconde sont également
// présentes dans args.
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.
// tz peut être mis sous la forme "Europe/Paris", "CET", "Local", etc.
func NewClockTZ(tz string, h uint, i uint, args ...uint) Clock {
c := NewClock(h, i, args...)
if c.valid() {
@ -227,7 +237,8 @@ func NewClockTZ(tz string, h uint, i uint, args ...uint) Clock {
return c
}
// NewClockFromTime retourne lheure à partir dune date Go.
// NewClockFromTime retourne lheure à partir dune date Go t.
// Si la précision p nest pas définie, cest une précision à la ms.
func NewClockFromTime(t time.Time, p ...Precision) Clock {
var (
pp = PrecisionMillisecond
@ -243,15 +254,16 @@ func NewClockFromTime(t time.Time, p ...Precision) Clock {
return setClock(ms(uint(h), uint(i), uint(s), uint(v)), pp, l)
}
// ClockNow retourne lheure actuelle. Si tz est renseignée,
// ClockNow retourne lheure actuelle avec une précision p. Si tz est renseignée,
// lheure est placée dans le fuseau horaire indiqué.
func ClockNow(p Precision, tz ...string) Clock {
return NewClockFromTime(now(tz...), p)
}
// Now retourne lheure actuelle avec la même précision et le même fuseau horaire que c.
func (c Clock) Now() Clock { return ClockNow(c.p(), c.location.String()) }
// ClockGuess retourne lheure à partir de e en essayant de deviner le format.
// ClockGuess retourne lheure à partir de e et à la précision p 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)
@ -260,7 +272,7 @@ func ClockGuess(p Precision, e string, tz ...string) Clock {
return ClockNil()
}
// ClockParse retourne lheure à partir de e en spécifiant le format f.
// ClockParse retourne lheure à partir de e et à la précision p 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)
@ -299,19 +311,19 @@ func (c Clock) Hour() uint { return c.h() }
// Clock retourne lheure, la minute, la seconde et la milliseconde.
func (c Clock) Clock() (h, i, s, v uint) { return c.h(), c.i(), c.s(), c.v() }
// SetMilli modifie la milliseconde.
// SetMilli modifie la milliseconde de la seconde.
func (c Clock) SetMilli(v uint) Clock { return newClock(c.setV(v), c.location) }
// SetSecond modifie la seconde.
// SetSecond modifie la seconde de la minute, et la milliseconde, si v est renseignée.
func (c Clock) SetSecond(s uint, v ...uint) Clock { return newClock(c.setS(s, v...), c.location) }
// SetMinute modifie la minute.
// SetMinute modifie la minute de lheure, ainsi que la seconde et la millisecondes si elles sont renseignées.
func (c Clock) SetMinute(i uint, args ...uint) Clock { return newClock(c.setI(i, args...), c.location) }
// SetHour modifie lheure.
// SetHour modifie lheure et, facultativement, la minute, la seconde et la milliseconde.
func (c Clock) SetHour(h uint, args ...uint) Clock { return newClock(c.setH(h, args...), c.location) }
// SetPrecision modifie la précision.
// SetPrecision retourne lhorloge avec la précision p.
func (c Clock) SetPrecision(p Precision) Clock { return newClock(c.setP(p), c.location) }
// Add ajoute un nombre dheures et de minutes, et, facultativement,
@ -327,7 +339,7 @@ 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.
// AddMilli ajoute une durée en millisecondes.
func (c Clock) AddMilli(v int) Clock { return newClock(c.addV(v), c.location) }
// AddDuration ajoute une durée.
@ -369,11 +381,12 @@ func (c Clock) In(l *time.Location) Clock {
return NewClockFromTime(c.ToTime().In(l))
}
// ToTimezone retourne lheure dans le fuseau horaire indiqué.
func (c Clock) ToTimezone(tz string) Clock { return c.In(timezone(tz)) }
// InTZ agit comme In mais en fournissant le fuseau horaire sous forme
// de chaîne de caractères.
func (c Clock) inTZ(tz string) Clock { return c.In(timezone(tz)) }
// Location retourne le fuseau horaire.
func (c Clock) Location() *time.Location { return c.location }
// TZ retourne le fuseau horaire.
func (c Clock) TZ() *time.Location { return c.location }
// IsDST retourne vrai si le fuseau horaire est à lheure dété.
func (c Clock) IsDST() bool { return c.dst(c.location) }
@ -398,14 +411,26 @@ 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()) }
// IsNow retourne vrai si lhorloge est à lheure actuelle.
func (c Clock) IsNow() bool { return c.Eq(c.Now()) }
// IsPast retourne vrai si lhorloge est située dans le passé.
func (c Clock) IsPast() bool { return c.Lt(c.Now()) }
// IsFuture retourne vrai si lhorloge est située dans le futur.
func (c Clock) IsFuture() bool { return c.Gt(c.Now()) }
func (c1 Clock) DiffInMillis(c2 Clock) int { return c1.subV(c2.clock) }
// DiffInMillis retourne c1 - c2 en millisecondes.
func (c1 Clock) DiffInMillis(c2 Clock) int { return c1.subV(c2.clock) }
// DiffInSeconds retourne c1 - c2 en secondes.
func (c1 Clock) DiffInSeconds(c2 Clock) int { return c1.subS(c2.clock) }
// DiffInMinutes retourne c1 - c2 en minutes.
func (c1 Clock) DiffInMinutes(c2 Clock) int { return c1.subI(c2.clock) }
func (c1 Clock) DiffInHours(c2 Clock) int { return c1.subH(c2.clock) }
// DiffInHours retourne c1 - c2 en heures.
func (c1 Clock) DiffInHours(c2 Clock) int { return c1.subH(c2.clock) }
// Format retourne une représentation de lheure au format spécifié.
func (c Clock) Format(format string) string { return c.f(format, c.location) }

View File

@ -103,17 +103,17 @@ const (
)
var (
// représentation de lunité 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',
// Représentation de lunité sous forme de caractères
unitToString = map[Unit]string{
NoUnit: "",
Millisecond: "ms",
Second: "s",
Minute: "m",
Hour: "h",
Day: "J",
Week: "S",
Month: "M",
Year: "A",
}
maskDate = map[string]date{

View File

@ -205,12 +205,14 @@ func newDate(t date, l *time.Location) Date {
return DateNil()
}
// NewDate retourne la date dans le fuseau horaire demandé.
// 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.
// NewDateFromTime retourne la date à partir dune date Go t.
func NewDateFromTime(t time.Time) Date {
y, m, d := t.Date()
l := t.Location()
@ -222,6 +224,7 @@ func NewDateFromTime(t time.Time) Date {
// 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.
@ -233,7 +236,7 @@ func DateGuess(e string, tz ...string) Date {
return DateNil()
}
// DateParse retourne la date à partir de v en spécifiant le format f.
// 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)
@ -263,7 +266,7 @@ 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.
// 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.
@ -290,7 +293,7 @@ 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.
// 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.
@ -314,7 +317,7 @@ 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.
// 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.
@ -329,11 +332,12 @@ func (t Date) In(l *time.Location) Date {
return NewDateFromTime(t.t(t.location).In(l))
}
// ToTimezone retourne la date dans le fuseau horaire indiqué.
// 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)) }
// Location retourne le fuseau horaire.
func (t Date) Location() *time.Location { return t.location }
// 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) }
@ -341,10 +345,11 @@ 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.
// 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 }
@ -354,21 +359,33 @@ 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()) }
// 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())
}
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) }
// 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) }
func (t1 Date) DiffInYears(t2 Date) int { return t1.subY(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(format string) string { return t.f(format, t.location) }
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) }

View File

@ -176,7 +176,7 @@ func (dt datetime) f(f string, l *time.Location) string {
}
func (dt datetime) str(l *time.Location) string { return dt.f("Y-m-d", l) }
// DateTime représente une indication de temps.
// DateTime représente une indication de temps (date + heure).
type DateTime struct {
datetime
location *time.Location
@ -193,7 +193,10 @@ func initDT(dt datetime, l *time.Location) DateTime {
return DateTime{dt, l}
}
// NewDateTime retourne un temps dans le fuseau horaire par défaut.
// NewDateTime retourne un temps dans le fuseau horaire par défaut avec :
// - y, m, d : année, mois, jour
// - h, i : heure, minute,
// - args : seconde, puis milliseconde.
// 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)
@ -209,7 +212,9 @@ func NewDateTimeTZ(tz string, y int, m, d, h, i uint, args ...uint) DateTime {
return dt
}
// NewDateTimeFromTime retourne le temps à partir dune date Go.
// NewDateTimeFromTime retourne le temps à partir dune date Go t.
// Si la précision p est fournie, cest la précision utilisée,
// sinon, cest la précision à la milliseconde.
func NewDateTimeFromTime(t time.Time, p ...Precision) DateTime {
var (
pp = PrecisionMillisecond
@ -226,15 +231,16 @@ func NewDateTimeFromTime(t time.Time, p ...Precision) DateTime {
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,
// DateTimeNow retourne le temps à la précision p. 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)
}
// Now retourne le temps actuel avec la précision et le fuseau horaire de dt.
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.
// DateTimeGuess retourne le temps à 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)
@ -243,7 +249,7 @@ func DateTimeGuess(p Precision, e string, tz ...string) DateTime {
return DateTimeNil()
}
// DateTimeParse retourne la date à partir de e en spécifiant le format f.
// DateTimeParse retourne le temps à 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)
@ -255,7 +261,7 @@ func DateTimeParse(p Precision, e, f string, tz ...string) DateTime {
// Precision retourne la précision de lheure.
func (dt DateTime) Precision() Precision { return dt.p() }
// IsNil retourne vrai si la date est nulle.
// IsNil retourne vrai si le temps est nul.
func (dt DateTime) IsNil() bool { return !dt.valid() }
// Year retourne lannée.
@ -264,7 +270,7 @@ func (dt DateTime) Year() int { return dt.y() }
// Month retourne le mois.
func (dt DateTime) Month() uint { return dt.m() }
// Day retourne le .
// Day retourne le jour.
func (dt DateTime) Day() uint { return dt.d() }
// Hour retourne lheure.
@ -318,32 +324,32 @@ 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 lannée.
// SetYear modifie lannée, et facultativement, le mois, le jour, etc.
func (dt DateTime) SetYear(y int, args ...uint) DateTime {
return initDT(dt.setY(y, args...), dt.location)
}
// SetMonth modifie le mois.
// SetMonth modifie le mois et facultativement le jour, lheure, etc.
func (dt DateTime) SetMonth(m uint, args ...uint) DateTime {
return initDT(dt.setM(m, args...), dt.location)
}
// SetDay modifie le jour.
// SetDay modifie le jour et facultativement lheure, la minute, etc..
func (dt DateTime) SetDay(d uint, args ...uint) DateTime {
return initDT(dt.setD(d, args...), dt.location)
}
// SetHour modifie lheure.
// SetHour modifie lheure et facultativement la minute, la seconde, etc.
func (dt DateTime) SetHour(h uint, args ...uint) DateTime {
return initDT(dt.setH(h, args...), dt.location)
}
// SetMinute modifie la minute.
// SetMinute modifie la minute et facultativement la seconde et la milliseconde.
func (dt DateTime) SetMinute(i uint, args ...uint) DateTime {
return initDT(dt.setI(i, args...), dt.location)
}
// SetSecond modifie la seconde.
// SetSecond modifie la seconde et facultativement la milliseconde.
func (dt DateTime) SetSecond(s uint, args ...uint) DateTime {
return initDT(dt.setS(s, args...), dt.location)
}
@ -395,52 +401,52 @@ func (dt DateTime) AddMilli(v int) DateTime { return initDT(dt.addV(v), dt.locat
// 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 dannée.
// BeginOfYear retourne le temps en début dannée au début du jour.
func (dt DateTime) BeginOfYear() DateTime { return initDT(dt.bY(), dt.location) }
// EndOfYear retourne la date en fin dannée.
// EndOfYear retourne le temps en fin dannée à la fin du jour.
func (dt DateTime) EndOfYear() DateTime { return initDT(dt.eY(), dt.location) }
// BeginOfMonth retourne la date en début de mois.
// BeginOfMonth retourne le temps en début de mois au début du jour.
func (dt DateTime) BeginOfMonth() DateTime { return initDT(dt.bM(), dt.location) }
// EndOfMonth retourne la date en fin de mois.
// EndOfMonth retourne le temps en fin de mois à la fin du jour.
func (dt DateTime) EndOfMonth() DateTime { return initDT(dt.eM(), dt.location) }
// BeginOfWeek retourne la date en début de semaine.
// BeginOfWeek retourne le temps en début de semaine au début du jour.
func (dt DateTime) BeginOfWeek() DateTime { return initDT(dt.bW(dt.location), dt.location) }
// EndOfWeek retourne la date en fin de semaine.
// EndOfWeek retourne le temps en fin de semaine à la fin du jour.
func (dt DateTime) EndOfWeek() DateTime { return initDT(dt.eW(dt.location), dt.location) }
// BeginOfDay retourne la date en début de jour.
// BeginOfDay retourne le temps en début de jour.
func (dt DateTime) BeginOfDay() DateTime { return initDT(dt.bD(), dt.location) }
// EndOfDay retourne la date en fin de jour.
// EndOfDay retourne le temps en fin de jour.
func (dt DateTime) EndOfDay() DateTime { return initDT(dt.eD(), dt.location) }
// BeginOfHour retourne la date en début dheure.
// BeginOfHour retourne le temps en début dheure.
func (dt DateTime) BeginOfHour() DateTime { return initDT(dt.bH(), dt.location) }
// EndOfHour retourne la date en fin dheure.
// EndOfHour retourne le temps en fin dheure.
func (dt DateTime) EndOfHour() DateTime { return initDT(dt.eH(), dt.location) }
// BeginOfMinute retourne la date en début de minute.
// BeginOfMinute retourne le temps en début de minute.
func (dt DateTime) BeginOfMinute() DateTime { return initDT(dt.bI(), dt.location) }
// EndOfMinute retourne la date en fin de minute.
// EndOfMinute retourne le temps en fin de minute.
func (dt DateTime) EndOfMinute() DateTime { return initDT(dt.eI(), dt.location) }
// BeginOfSecond retourne la date en début de seconde.
// BeginOfSecond retourne le temps en début de seconde.
func (dt DateTime) BeginOfSecond() DateTime { return initDT(dt.bS(), dt.location) }
// EndOfSecond retourne la date en fin de seconde.
// EndOfSecond retourne le temps en fin de seconde.
func (dt DateTime) EndOfSecond() DateTime { return initDT(dt.eS(), dt.location) }
// ToTime retourne la date dans le fuseau horaire indiqué.
// ToTime retourne le temps 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é.
// In retourne le temps dans le fuseau horaire indiqué.
func (dt DateTime) In(l *time.Location) DateTime {
if dt.IsNil() {
return DateTimeNil()
@ -449,11 +455,12 @@ func (dt DateTime) In(l *time.Location) DateTime {
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)) }
// InTZ agit comme In mais en fournissant le fuseau horaire sous forme
// de chaîne de caractères.
func (dt DateTime) InTZ(tz string) DateTime { return dt.In(timezone(tz)) }
// Location retourne le fuseau horaire.
func (dt DateTime) Location() *time.Location { return dt.location }
// TZ retourne le fuseau horaire.
func (dt DateTime) TZ() *time.Location { return dt.location }
// IsDST retourne vrai si le fuseau horaire est à lheure dété.
func (dt DateTime) IsDST() bool { return dt.dst(dt.location) }
@ -464,7 +471,7 @@ 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.
// Compare compare 2 temps après normalisation du fuseau horaire et de la précision.
func (dt1 DateTime) Compare(dt2 DateTime) int { return dt1.cmp(dt2.datetime) }
func (dt1 DateTime) Eq(dt2 DateTime) bool { return dt1.Compare(dt2) == 0 }
@ -474,11 +481,16 @@ 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()) }
// IsNow retourne vrai si le temps est le temps actuel.
func (dt DateTime) IsNow() bool { return dt.Eq(dt.Now()) }
// IsPast retourne vrai si le temps est situé dans le passé.
func (dt DateTime) IsPast() bool { return dt.Lt(dt.Now()) }
// IsPast retourne vrai si le temps est situé dans le futur.
func (dt DateTime) IsFuture() bool { return dt.Gt(dt.Now()) }
// DiffInMills retourne dt1-dt2 en millisecondes.
// DiffInMills retourne dt1 - dt2 en millisecondes.
func (dt1 DateTime) DiffInMillis(dt2 DateTime) int {
return dt1.subV(dt2.datetime, dt1.location, dt2.location)
}
@ -514,9 +526,9 @@ func (dt1 DateTime) DiffInMonths(dt2 DateTime) int { return dt1.subM(dt2.datetim
// 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é.
// Format retourne une représentation du temps 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',
// String retourne une représentation du temps 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) }

View File

@ -2,11 +2,15 @@ package datetime
import (
"fmt"
"regexp"
"strconv"
)
// Unit est une unité de durée.
type Unit uint
func (u Unit) String() string { return unitToString[u] }
// Duration est une durée entre deux repères de temps.
type Duration int
@ -19,6 +23,26 @@ func NewDuration(value int, unit Unit) Duration {
return (Duration(value) << bitsUnit) | Duration(unit)
}
// ParseDuration retourne une durée à partir dune chaîne de caractères.
func ParseDuration(e string) Duration {
r := regexp.MustCompile(`^(\d+)(\w+)$`)
if !r.MatchString(e) {
return DurationNil
}
spl := r.FindAllStringSubmatch(e, 1)[0]
v, _ := strconv.Atoi(spl[1])
u := NoUnit
for uu, su := range unitToString {
if su == spl[2] {
u = uu
break
}
}
return NewDuration(v, u)
}
// Value retourne la valeur de la durée, sans lunité.
func (d Duration) Value() int { return int(d >> bitsUnit) }
@ -51,5 +75,5 @@ func (d Duration) String() string {
v, u := d.Value(), d.Unit()
return fmt.Sprintf("%d%c", v, unitToByte[u])
return fmt.Sprintf("%d%s", v, u)
}

View File

@ -54,7 +54,7 @@ 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)))
return fmt.Sprintf("%03d", uint(sit(uint(h), uint(m), uint(s), uint(n))))
}
func format_g(t time.Time) string {
h := t.Hour() % 12

View File

@ -1,6 +1,8 @@
package datetime
import (
"fmt"
. "gitea.zaclys.com/bvaudour/gob/option"
)
@ -16,6 +18,8 @@ type TimeComparator[E any] interface {
IsPast() bool
IsFuture() bool
Now() E
String() string
IsNil() bool
}
// Min retourne le temps le plus petit.
@ -40,21 +44,74 @@ func Max[C TimeComparator[C]](e C, args ...C) C {
return out
}
// Range représente une période entre deux bornes temporelles.
func minB[C TimeComparator[C]](e1, e2 C) C {
if e1.IsNil() {
return e1
} else if e2.IsNil() {
return e2
}
return Min(e1, e2)
}
func maxB[C TimeComparator[C]](e1, e2 C) C {
if e1.IsNil() {
return e2
} else if e2.IsNil() {
return e1
}
return Max(e1, e2)
}
func minE[C TimeComparator[C]](e1, e2 C) C {
if e1.IsNil() {
return e2
} else if e2.IsNil() {
return e1
}
return Min(e1, e2)
}
func maxE[C TimeComparator[C]](e1, e2 C) C {
if e1.IsNil() {
return e1
} else if e2.IsNil() {
return e2
}
return Max(e1, e2)
}
// Range représente une période entre deux bornes temporelles begin et end.
// Si begin est nul, cela représente ]-∞ ; end].
// Se end est nul, cela représent [begin; +∞[.
type Range[C TimeComparator[C]] struct {
begin, end C
}
// NewRange retourne une période entre begin et end.
// Si begin < end, les bornes sont inversées.
// Si begin < end, le programme panique.
func NewRange[C TimeComparator[C]](begin, end C) Range[C] {
if begin.Gt(end) {
begin, end = end, begin
if !begin.IsNil() && !end.IsNil() && begin.Gt(end) {
panic("begin should be located in past of end.")
}
return Range[C]{begin, end}
}
func gt[C TimeComparator[C]](e C, strict ...bool) func(C) bool {
if len(strict) == 0 || !strict[0] {
return e.Ge
}
return e.Ge
}
func lt[C TimeComparator[C]](e C, strict ...bool) func(C) bool {
if len(strict) == 0 || !strict[0] {
return e.Le
}
return e.Le
}
func (r Range[C]) bE(e C, strict ...bool) bool { return r.end.IsNil() || lt(e, strict...)(r.end) }
func (r Range[C]) aE(e C, strict ...bool) bool { return !r.end.IsNil() && gt(e, strict...)(r.end) }
func (r Range[C]) bB(e C, strict ...bool) bool { return !r.begin.IsNil() || lt(e, strict...)(r.begin) }
func (r Range[C]) aB(e C, strict ...bool) bool { return r.begin.IsNil() || gt(e, strict...)(r.begin) }
// Begin retourne le début de la période.
func (r Range[C]) Begin() C { return r.begin }
@ -62,22 +119,22 @@ func (r Range[C]) Begin() C { return r.begin }
func (r Range[C]) End() C { return r.end }
// 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) }
func (r Range[C]) Before(e C) bool { return r.bB(e, true) }
// 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) }
func (r Range[C]) After(e C) bool { return r.aE(e, true) }
// Contains retourne vrai si e ∈ [begin;end].
func (r Range[C]) Contains(e C) bool { return e.Ge(r.begin) && e.Le(r.end) }
func (r Range[C]) Contains(e C) bool { return r.aB(e) && r.bE(e) }
// ContainsStrictLeft retourne vrai si e ∈ ]begin;end].
func (r Range[C]) ContainsStrictLeft(e C) bool { return e.Gt(r.begin) && e.Le(r.end) }
func (r Range[C]) ContainsStrictLeft(e C) bool { return r.aB(e, true) && r.bE(e) }
// ContainsStrictRight retourne vrai si e ∈ [begin;end[.
func (r Range[C]) ContainsStrictRight(e C) bool { return e.Ge(r.begin) && e.Lt(r.end) }
func (r Range[C]) ContainsStrictRight(e C) bool { return r.aB(e) && r.bE(e, true) }
// ContainsStrict retourne vrai si e ∈ ]begin;end[.
func (r Range[C]) ContainsStrict(e C) bool { return e.Gt(r.begin) && e.Lt(r.end) }
func (r Range[C]) ContainsStrict(e C) bool { return r.aB(e, true) && r.bE(e, true) }
// IsNow retourne vrai si la période est en cours.
func (r Range[C]) IsNow() bool { return r.Contains(r.begin.Now()) }
@ -89,14 +146,14 @@ func (r Range[C]) IsPast() bool { return r.Before(r.begin.Now()) }
func (r Range[C]) IsFuture() bool { return r.After(r.begin.Now()) }
// 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) }
func (r1 Range[C]) BeforeRange(r2 Range[C]) bool { return !r1.end.IsNil() && r2.bB(r1.end) }
// 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) }
func (r1 Range[C]) AfterRange(r2 Range[C]) bool { return !r1.begin.IsNil() && r2.aE(r1.begin) }
// 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)
return ((r2.begin.IsNil() && r1.begin.IsNil()) || r1.aB(r2.begin)) && ((r2.end.IsNil() && r1.end.IsNil()) || r1.bE(r2.end))
}
// InRange retourne vrai si r2 comprend intégralement r1.
@ -104,18 +161,18 @@ func (r1 Range[C]) InRange(r2 Range[C]) bool { return r2.ContainsRange(r1) }
// 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)
return (!r1.end.IsNil() && r2.bB(r1.end)) || (!r1.begin.IsNil() && r2.aE(r1.begin))
}
// 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)
return (r1.begin.IsNil() || r2.bE(r1.begin, true)) && (r1.end.IsNil() || r2.aB(r1.end, true))
}
// 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)))
result = Some(NewRange(maxB(r1.begin, r2.begin), minE(r1.end, r2.end)))
}
return
@ -123,8 +180,8 @@ func (r1 Range[C]) Intersection(r2 Range[C]) (result Option[Range[C]]) {
// 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)))
if (r1.begin.IsNil() || r2.bE(r1.begin)) && (r1.end.IsNil() || r2.aB(r1.end)) {
result = Some(NewRange(minB(r1.begin, r2.begin), maxE(r1.end, r2.end)))
}
return
@ -132,27 +189,37 @@ func (r1 Range[C]) Joins(r2 Range[C]) (result Option[Range[C]]) {
// 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, r1.begin)
b1, b2 := minB(r1.begin, r2.begin), maxB(r1.begin, r2.begin)
e1, e2 := minE(r1.end, r2.end), maxE(r1.end, r2.end)
if b1.Ne(b2) {
e := b2
if !e1.IsNil() {
e = Min(b2, e1)
}
result = append(result, NewRange(begin, end))
result = append(result, NewRange(b1, e))
}
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, r1.end)
if e1.Ne(e2) {
b := e1
if !b2.IsNil() {
b = Max(b2, e1)
}
result = append(result, NewRange(begin, end))
result = append(result, NewRange(b, e2))
}
return
}
// String retourne la représentation textuelle de la période.
func (r Range[C]) String() string {
b, e := r.begin.String(), r.end.String()
if r.begin.IsNil() {
b = "-∞"
}
if r.end.IsNil() {
e = "+∞"
}
return fmt.Sprintf("[%s ; %s]", b, e)
}