[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
+3
View File
@@ -8,4 +8,7 @@ const (
// Network settings
Hostname = "pico2w-clock"
EnableICMP = true
// Time settings
ActiveTimezone = "UTC"
)
+11 -10
View File
@@ -128,30 +128,31 @@ func main() {
lastSecond := -1
// Remove static call before the loop, then in the loop:
for {
currentTime := time.Now().Add(timeOffset).UTC()
currentSecond := currentTime.Second()
// Skip display refreshes if the second hasn't changed to save the i2c bus
if currentSecond != lastSecond {
lastSecond = currentSecond
// Alternate colon (:) with space ( ) every second
timeSeperator := ":"
if currentSecond % 2 == 1 {
if currentSecond%2 == 1 {
timeSeperator = " "
}
// Create the awful time string before displaying it
timeStr := fmt.Sprintf("%02d%s%02d%s%02d UTC",
currentTime.Hour(), timeSeperator,
currentTime.Minute(), timeSeperator,
currentTime.Second())
// Dynamically determine DST vs Standard time for this second
loc, zoneName := ResolveTimezone(ActiveTimezone, currentTime)
localTime := currentTime.In(loc)
timeStr := fmt.Sprintf("%02d%s%02d%s%02d %s",
localTime.Hour(), timeSeperator,
localTime.Minute(), timeSeperator,
localTime.Second(),
zoneName)
oled.ClearBuffer()
// Time
tinyfont.WriteLine(oled, defaultFont, 8, 32, timeStr, white)
// IP Address
tinyfont.WriteLine(oled, tinyFont, 0, 60, fmt.Sprintf("IP: %s", ipStr), white)
oled.Display()
}
+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
}