2022-10-27 16:00:57 +02:00
|
|
|
package timeext
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2022-10-27 16:07:42 +02:00
|
|
|
"math"
|
2022-10-27 16:00:57 +02:00
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
var TimezoneBerlin *time.Location
|
|
|
|
|
|
|
|
func init() {
|
|
|
|
var err error
|
|
|
|
TimezoneBerlin, err = time.LoadLocation("Europe/Berlin")
|
|
|
|
if err != nil {
|
|
|
|
panic(fmt.Sprintf("Could not load Timezone: %v", err))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimeToDatePart returns a timestamp at the start of the day which contains t (= 00:00:00)
|
2022-10-27 17:50:28 +02:00
|
|
|
func TimeToDatePart(t time.Time, tz *time.Location) time.Time {
|
|
|
|
t = t.In(tz)
|
2022-10-27 16:00:57 +02:00
|
|
|
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
|
|
|
}
|
|
|
|
|
2023-08-21 14:15:06 +02:00
|
|
|
// TimeToDayStart returns a timestamp at the start of the day which contains t (= 00:00:00)
|
|
|
|
func TimeToDayStart(t time.Time, tz *time.Location) time.Time {
|
|
|
|
t = t.In(tz)
|
|
|
|
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimeToDayEnd returns a timestamp at the end of the day which contains t (= 23:59:59)
|
|
|
|
func TimeToDayEnd(t time.Time, tz *time.Location) time.Time {
|
2023-08-21 14:23:44 +02:00
|
|
|
return TimeToDayStart(t, tz).AddDate(0, 0, 1).Add(-1)
|
2023-08-21 14:15:06 +02:00
|
|
|
}
|
|
|
|
|
2022-10-27 16:00:57 +02:00
|
|
|
// TimeToWeekStart returns a timestamp at the start of the week which contains t (= Monday 00:00:00)
|
2022-10-27 17:50:28 +02:00
|
|
|
func TimeToWeekStart(t time.Time, tz *time.Location) time.Time {
|
|
|
|
t = TimeToDatePart(t, tz)
|
2022-10-27 16:00:57 +02:00
|
|
|
|
|
|
|
delta := time.Duration(((int64(t.Weekday()) + 6) % 7) * 24 * int64(time.Hour))
|
|
|
|
t = t.Add(-1 * delta)
|
|
|
|
|
|
|
|
return t
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimeToMonthStart returns a timestamp at the start of the month which contains t (= yyyy-MM-00 00:00:00)
|
2022-10-27 17:50:28 +02:00
|
|
|
func TimeToMonthStart(t time.Time, tz *time.Location) time.Time {
|
|
|
|
t = t.In(tz)
|
2022-10-27 16:00:57 +02:00
|
|
|
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, t.Location())
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimeToMonthEnd returns a timestamp at the end of the month which contains t (= yyyy-MM-31 23:59:59.999999999)
|
2022-10-27 17:50:28 +02:00
|
|
|
func TimeToMonthEnd(t time.Time, tz *time.Location) time.Time {
|
|
|
|
return TimeToMonthStart(t, tz).AddDate(0, 1, 0).Add(-1)
|
2022-10-27 16:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// TimeToYearStart returns a timestamp at the start of the year which contains t (= yyyy-01-01 00:00:00)
|
2022-10-27 17:50:28 +02:00
|
|
|
func TimeToYearStart(t time.Time, tz *time.Location) time.Time {
|
|
|
|
t = t.In(tz)
|
2022-10-27 16:00:57 +02:00
|
|
|
return time.Date(t.Year(), 1, 1, 0, 0, 0, 0, t.Location())
|
|
|
|
}
|
|
|
|
|
|
|
|
// TimeToYearEnd returns a timestamp at the end of the month which contains t (= yyyy-12-31 23:59:59.999999999)
|
2022-10-27 17:50:28 +02:00
|
|
|
func TimeToYearEnd(t time.Time, tz *time.Location) time.Time {
|
|
|
|
return TimeToYearStart(t, tz).AddDate(1, 0, 0).Add(-1)
|
2022-10-27 16:00:57 +02:00
|
|
|
}
|
|
|
|
|
2024-07-04 16:24:49 +02:00
|
|
|
func TimeToNextYearStart(t time.Time, tz *time.Location) time.Time {
|
|
|
|
return TimeToYearStart(t, tz).AddDate(1, 0, 0)
|
|
|
|
}
|
|
|
|
|
2022-10-27 16:00:57 +02:00
|
|
|
// IsSameDayIncludingDateBoundaries returns true if t1 and t2 are part of the same day (TZ/Berlin), the boundaries of the day are
|
|
|
|
// inclusive, this means 2021-09-15T00:00:00 is still part of the day 2021-09-14
|
2022-10-27 17:50:28 +02:00
|
|
|
func IsSameDayIncludingDateBoundaries(t1 time.Time, t2 time.Time, tz *time.Location) bool {
|
|
|
|
dp1 := TimeToDatePart(t1, tz)
|
|
|
|
dp2 := TimeToDatePart(t2, tz)
|
2022-10-27 16:00:57 +02:00
|
|
|
|
|
|
|
if dp1.Equal(dp2) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
if dp1.AddDate(0, 0, 1).Equal(dp2) && dp2.Equal(t2) {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsDatePartEqual returns true if a and b have the same date part (`yyyy`, `MM` and `dd`)
|
2022-10-27 17:50:28 +02:00
|
|
|
func IsDatePartEqual(a time.Time, b time.Time, tz *time.Location) bool {
|
|
|
|
yy1, mm1, dd1 := a.In(tz).Date()
|
|
|
|
yy2, mm2, dd2 := b.In(tz).Date()
|
2022-10-27 16:00:57 +02:00
|
|
|
|
|
|
|
return yy1 == yy2 && mm1 == mm2 && dd1 == dd2
|
|
|
|
}
|
|
|
|
|
|
|
|
// WithTimePart returns a timestamp with the date-part (`yyyy`, `MM`, `dd`) from base
|
|
|
|
// and the time (`HH`, `mm`, `ss`) from the parameter
|
|
|
|
func WithTimePart(base time.Time, hour, minute, second int) time.Time {
|
2022-10-27 17:50:28 +02:00
|
|
|
datepart := TimeToDatePart(base, base.Location())
|
2022-10-27 16:00:57 +02:00
|
|
|
|
2022-10-29 15:11:08 +02:00
|
|
|
delta := time.Duration(int64(hour)*int64(time.Hour) + int64(minute)*int64(time.Minute) + int64(second)*int64(time.Second))
|
2022-10-27 16:00:57 +02:00
|
|
|
|
|
|
|
return datepart.Add(delta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// CombineDateAndTime returns a timestamp with the date-part (`yyyy`, `MM`, `dd`) from the d parameter
|
|
|
|
// and the time (`HH`, `mm`, `ss`) from the t parameter
|
|
|
|
func CombineDateAndTime(d time.Time, t time.Time) time.Time {
|
2022-10-27 17:50:28 +02:00
|
|
|
datepart := TimeToDatePart(d, d.Location())
|
2022-10-27 16:00:57 +02:00
|
|
|
|
2022-10-29 15:11:08 +02:00
|
|
|
delta := time.Duration(int64(t.Hour())*int64(time.Hour) + int64(t.Minute())*int64(time.Minute) + int64(t.Second())*int64(time.Second) + int64(t.Nanosecond())*int64(time.Nanosecond))
|
2022-10-27 16:00:57 +02:00
|
|
|
|
|
|
|
return datepart.Add(delta)
|
|
|
|
}
|
|
|
|
|
|
|
|
// IsSunday returns true if t is a sunday (in TZ/Berlin)
|
2022-10-27 17:50:28 +02:00
|
|
|
func IsSunday(t time.Time, tz *time.Location) bool {
|
|
|
|
if t.In(tz).Weekday() == time.Sunday {
|
2022-10-27 16:00:57 +02:00
|
|
|
return true
|
|
|
|
}
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
func DurationFromTime(hours int, minutes int, seconds int) time.Duration {
|
2022-10-29 15:11:08 +02:00
|
|
|
return time.Duration(int64(hours)*int64(time.Hour) + int64(minutes)*int64(time.Minute) + int64(seconds)*int64(time.Second))
|
2022-10-27 16:00:57 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
func Min(a time.Time, b time.Time) time.Time {
|
|
|
|
if a.UnixNano() < b.UnixNano() {
|
|
|
|
return a
|
|
|
|
} else {
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func Max(a time.Time, b time.Time) time.Time {
|
|
|
|
if a.UnixNano() > b.UnixNano() {
|
|
|
|
return a
|
|
|
|
} else {
|
|
|
|
return b
|
|
|
|
}
|
|
|
|
}
|
2022-10-27 16:07:42 +02:00
|
|
|
|
|
|
|
func UnixFloatSeconds(v float64) time.Time {
|
|
|
|
sec, dec := math.Modf(v)
|
|
|
|
return time.Unix(int64(sec), int64(dec*(1e9)))
|
|
|
|
}
|
2022-10-27 17:50:28 +02:00
|
|
|
|
|
|
|
func FloorTime(t time.Time) time.Time {
|
|
|
|
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, t.Location())
|
|
|
|
}
|
2024-03-30 03:01:55 +01:00
|
|
|
|
|
|
|
func SubtractYears(t time.Time, yearCount float64, tz *time.Location) time.Time {
|
|
|
|
t = t.In(tz)
|
|
|
|
|
|
|
|
if yearCount < 0 {
|
|
|
|
return AddYears(t, -yearCount, tz)
|
|
|
|
}
|
|
|
|
|
|
|
|
intCount, floatCount := math.Modf(yearCount)
|
|
|
|
|
2024-05-29 20:20:01 +02:00
|
|
|
t = t.AddDate(-int(intCount), 0, 0)
|
2024-03-30 03:01:55 +01:00
|
|
|
|
|
|
|
t0 := TimeToYearStart(t, tz)
|
|
|
|
t1 := TimeToYearEnd(t, tz)
|
|
|
|
|
|
|
|
return t.Add(time.Duration(float64(t1.Sub(t0)) * floatCount * -1))
|
|
|
|
}
|
|
|
|
|
|
|
|
func AddYears(t time.Time, yearCount float64, tz *time.Location) time.Time {
|
|
|
|
t = t.In(tz)
|
|
|
|
|
|
|
|
if yearCount < 0 {
|
|
|
|
return SubtractYears(t, -yearCount, tz)
|
|
|
|
}
|
|
|
|
|
|
|
|
intCount, floatCount := math.Modf(yearCount)
|
|
|
|
|
2024-05-29 20:20:01 +02:00
|
|
|
t = t.AddDate(int(intCount), 0, 0)
|
2024-03-30 03:01:55 +01:00
|
|
|
|
|
|
|
t0 := TimeToYearStart(t, tz)
|
|
|
|
t1 := TimeToYearEnd(t, tz)
|
|
|
|
|
|
|
|
return t.Add(time.Duration(float64(t1.Sub(t0)) * floatCount))
|
|
|
|
}
|