125 lines
3.2 KiB
Go
125 lines
3.2 KiB
Go
// Package timezone provides global timezone management for the application.
|
|
// Similar to PHP's date_default_timezone_set, this package allows setting
|
|
// a global timezone that affects all time.Now() calls.
|
|
package timezone
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
)
|
|
|
|
var (
|
|
// location is the global timezone location
|
|
location *time.Location
|
|
// tzName stores the timezone name for logging/debugging
|
|
tzName string
|
|
)
|
|
|
|
// Init initializes the global timezone setting.
|
|
// This should be called once at application startup.
|
|
// Example timezone values: "Asia/Shanghai", "America/New_York", "UTC"
|
|
func Init(tz string) error {
|
|
if tz == "" {
|
|
tz = "Asia/Shanghai" // Default timezone
|
|
}
|
|
|
|
loc, err := time.LoadLocation(tz)
|
|
if err != nil {
|
|
return fmt.Errorf("invalid timezone %q: %w", tz, err)
|
|
}
|
|
|
|
// Set the global Go time.Local to our timezone
|
|
// This affects time.Now() throughout the application
|
|
time.Local = loc
|
|
location = loc
|
|
tzName = tz
|
|
|
|
log.Printf("Timezone initialized: %s (UTC offset: %s)", tz, getUTCOffset(loc))
|
|
return nil
|
|
}
|
|
|
|
// getUTCOffset returns the current UTC offset for a location
|
|
func getUTCOffset(loc *time.Location) string {
|
|
_, offset := time.Now().In(loc).Zone()
|
|
hours := offset / 3600
|
|
minutes := (offset % 3600) / 60
|
|
if minutes < 0 {
|
|
minutes = -minutes
|
|
}
|
|
sign := "+"
|
|
if hours < 0 {
|
|
sign = "-"
|
|
hours = -hours
|
|
}
|
|
return fmt.Sprintf("%s%02d:%02d", sign, hours, minutes)
|
|
}
|
|
|
|
// Now returns the current time in the configured timezone.
|
|
// This is equivalent to time.Now() after Init() is called,
|
|
// but provided for explicit timezone-aware code.
|
|
func Now() time.Time {
|
|
if location == nil {
|
|
return time.Now()
|
|
}
|
|
return time.Now().In(location)
|
|
}
|
|
|
|
// Location returns the configured timezone location.
|
|
func Location() *time.Location {
|
|
if location == nil {
|
|
return time.Local
|
|
}
|
|
return location
|
|
}
|
|
|
|
// Name returns the configured timezone name.
|
|
func Name() string {
|
|
if tzName == "" {
|
|
return "Local"
|
|
}
|
|
return tzName
|
|
}
|
|
|
|
// StartOfDay returns the start of the given day (00:00:00) in the configured timezone.
|
|
func StartOfDay(t time.Time) time.Time {
|
|
loc := Location()
|
|
t = t.In(loc)
|
|
return time.Date(t.Year(), t.Month(), t.Day(), 0, 0, 0, 0, loc)
|
|
}
|
|
|
|
// Today returns the start of today (00:00:00) in the configured timezone.
|
|
func Today() time.Time {
|
|
return StartOfDay(Now())
|
|
}
|
|
|
|
// EndOfDay returns the end of the given day (23:59:59.999999999) in the configured timezone.
|
|
func EndOfDay(t time.Time) time.Time {
|
|
loc := Location()
|
|
t = t.In(loc)
|
|
return time.Date(t.Year(), t.Month(), t.Day(), 23, 59, 59, 999999999, loc)
|
|
}
|
|
|
|
// StartOfWeek returns the start of the week (Monday 00:00:00) for the given time.
|
|
func StartOfWeek(t time.Time) time.Time {
|
|
loc := Location()
|
|
t = t.In(loc)
|
|
weekday := int(t.Weekday())
|
|
if weekday == 0 {
|
|
weekday = 7 // Sunday is day 7
|
|
}
|
|
return time.Date(t.Year(), t.Month(), t.Day()-weekday+1, 0, 0, 0, 0, loc)
|
|
}
|
|
|
|
// StartOfMonth returns the start of the month (1st day 00:00:00) for the given time.
|
|
func StartOfMonth(t time.Time) time.Time {
|
|
loc := Location()
|
|
t = t.In(loc)
|
|
return time.Date(t.Year(), t.Month(), 1, 0, 0, 0, 0, loc)
|
|
}
|
|
|
|
// ParseInLocation parses a time string in the configured timezone.
|
|
func ParseInLocation(layout, value string) (time.Time, error) {
|
|
return time.ParseInLocation(layout, value, Location())
|
|
}
|