twitch-bot/internal/template/date/interval.go

95 lines
2.5 KiB
Go
Raw Normal View History

package date
import (
"fmt"
"strings"
"time"
)
type (
// Interval represents a human-minded diff of two dates which is in
// no way interchangeable with a time.Duration: The DateInterval
// takes each date component and subtracts them. This causes the
// 03/25 to be exactly one month distant from 02/25 even though the
// distance would be different than with 03/25 and 04/25 which is
// also exactly one month.
Interval struct {
Years int
Months int
Days int
Hours int
Minutes int
Seconds int
}
)
// NewInterval creates an Interval from two given dates
func NewInterval(a, b time.Time) (i Interval) {
var l, u time.Time
if a.Before(b) {
l, u = a.UTC(), b.UTC()
} else {
l, u = b.UTC(), a.UTC()
}
i.Years = u.Year() - l.Year()
i.Months = int(u.Month() - l.Month())
i.Days = u.Day() - l.Day()
i.Hours = u.Hour() - l.Hour()
i.Minutes = u.Minute() - l.Minute()
i.Seconds = u.Second() - l.Second()
if i.Seconds < 0 {
i.Minutes, i.Seconds = i.Minutes-1, i.Seconds+60 //nolint:mnd
}
if i.Minutes < 0 {
i.Hours, i.Minutes = i.Hours-1, i.Minutes+60 //nolint:mnd
}
if i.Hours < 0 {
i.Days, i.Hours = i.Days-1, i.Hours+24 //nolint:mnd
}
if i.Days < 0 {
// oh boi.
i.Months, i.Days = i.Months-1, daysInMonth(u.Year(), int(u.Month())-1)+i.Days
}
if i.Months < 0 {
i.Years, i.Months = i.Years-1, i.Months+12 //nolint:mnd
}
return i
}
func daysInMonth(year, month int) int {
return time.Date(year, time.Month(month+1), 1, 0, 0, 0, 0, time.Local).Add(-time.Second).Day()
}
// Format takes a template string analog to a strftime string and formats
// the Interval accordingly:
//
// %Y / %y = Years with / without leading digit to 2 places
// %M / %m = Months with / without leading digit to 2 places
// %D / %d = Days with / without leading digit to 2 places
// %H / %h = Hours with / without leading digit to 2 places
// %I / %i = Minutes with / without leading digit to 2 places
// %S / %s = Seconds with / without leading digit to 2 places
func (i Interval) Format(tplString string) string {
return strings.NewReplacer(
"%Y", fmt.Sprintf("%02d", i.Years),
"%y", fmt.Sprintf("%d", i.Years),
"%M", fmt.Sprintf("%02d", i.Months),
"%m", fmt.Sprintf("%d", i.Months),
"%D", fmt.Sprintf("%02d", i.Days),
"%d", fmt.Sprintf("%d", i.Days),
"%H", fmt.Sprintf("%02d", i.Hours),
"%h", fmt.Sprintf("%d", i.Hours),
"%I", fmt.Sprintf("%02d", i.Minutes),
"%i", fmt.Sprintf("%d", i.Minutes),
"%S", fmt.Sprintf("%02d", i.Seconds),
"%s", fmt.Sprintf("%d", i.Seconds),
).Replace(tplString)
}