[Issue #2] - Added timezone support with a list of support timezones
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2026-09-11 00:23:24 -04:00
parent cc96fbccc0
commit 8798092cc8
3 changed files with 105 additions and 10 deletions
+91
View File
@@ -0,0 +1,91 @@
package main
import (
"time"
)
type TimezoneConfig struct {
StandardName string
StandardOffset int
DaylightName string
DaylightOffset int
ObservesUSDST bool
}
// Map timezone aliases to standard/daylight offsets
var timezones = map[string]TimezoneConfig{
// Dynamic US zones (switch automatically between Standard and Daylight)
"US/Eastern": {"EST", -5 * 3600, "EDT", -4 * 3600, true},
"ET": {"EST", -5 * 3600, "EDT", -4 * 3600, true},
"US/Central": {"CST", -6 * 3600, "CDT", -5 * 3600, true},
"CT": {"CST", -6 * 3600, "CDT", -5 * 3600, true},
"US/Mountain": {"MST", -7 * 3600, "MDT", -6 * 3600, true},
"MT": {"MST", -7 * 3600, "MDT", -6 * 3600, true},
"US/Pacific": {"PST", -8 * 3600, "PDT", -7 * 3600, true},
"PT": {"PST", -8 * 3600, "PDT", -7 * 3600, true},
// Fixed non-DST zones
"UTC": {"UTC", 0, "UTC", 0, false},
"EST": {"EST", -5 * 3600, "EST", -5 * 3600, false},
"EDT": {"EDT", -4 * 3600, "EDT", -4 * 3600, false},
"CST": {"CST", -6 * 3600, "CST", -6 * 3600, false},
"CDT": {"CDT", -5 * 3600, "CDT", -5 * 3600, false},
"MST": {"MST", -7 * 3600, "MST", -7 * 3600, false},
"MDT": {"MDT", -6 * 3600, "MDT", -6 * 3600, false},
"PST": {"PST", -8 * 3600, "PST", -8 * 3600, false},
"PDT": {"PDT", -7 * 3600, "PDT", -7 * 3600, false},
}
// IsUSDST checks if the given UTC time falls in US Daylight Saving Time
// (Second Sunday in March at 02:00 local to first Sunday in November at 02:00 local).
func IsUSDST(t time.Time, stdOffsetSec int) bool {
month := t.Month()
if month < time.March || month > time.November {
return false // Dec, Jan, Feb
}
if month > time.March && month < time.November {
return true // Apr through Oct
}
day := t.Day()
weekday := int(t.Weekday())
if month == time.March {
// Second Sunday in March is between 8th and 14th
prevSunday := day - weekday
if prevSunday < 8 {
return false
}
if prevSunday >= 15 {
return true
}
// Transition occurs at 2:00 AM standard local time -> (2 - stdOffsetHours) in UTC
stdOffsetHours := stdOffsetSec / 3600
switchHourUTC := 2 - stdOffsetHours
return weekday != int(time.Sunday) || t.Hour() >= switchHourUTC
}
// November: first Sunday is between 1st and 7th
prevSunday := day - weekday
if prevSunday < 1 {
return true // Before first Sunday
}
// Fall-back occurs at 2:00 AM daylight local time -> (2 - (stdOffsetHours + 1)) in UTC
stdOffsetHours := stdOffsetSec / 3600
switchHourUTC := 2 - (stdOffsetHours + 1)
return weekday == int(time.Sunday) && t.Hour() < switchHourUTC
}
// ResolveTimezone dynamically determines the *time.Location and label
// based on whether the zone observes DST at the given UTC time.
func ResolveTimezone(name string, utcNow time.Time) (*time.Location, string) {
cfg, ok := timezones[name]
if !ok {
return time.FixedZone("UTC", 0), "UTC"
}
if cfg.ObservesUSDST && IsUSDST(utcNow, cfg.StandardOffset) {
return time.FixedZone(cfg.DaylightName, cfg.DaylightOffset), cfg.DaylightName
}
return time.FixedZone(cfg.StandardName, cfg.StandardOffset), cfg.StandardName
}