fix: migration
This commit is contained in:
@@ -105,9 +105,11 @@ func (s *ReminderService) SetEnabled(ctx context.Context, userID string, enabled
|
||||
}
|
||||
|
||||
// SetTimezone validates the IANA zone before storing so a bad value can never
|
||||
// break the (timezone-using) candidate scan.
|
||||
// break the (timezone-using) candidate scan. Legacy aliases are canonicalized
|
||||
// first (browsers report e.g. "Asia/Calcutta"): Go resolves them but a
|
||||
// Postgres without the tzdata backward links rejects them in AT TIME ZONE.
|
||||
func (s *ReminderService) SetTimezone(ctx context.Context, userID, tz string) error {
|
||||
tz = strings.TrimSpace(tz)
|
||||
tz = canonicalTZ(strings.TrimSpace(tz))
|
||||
if tz == "" {
|
||||
tz = "UTC"
|
||||
}
|
||||
|
||||
@@ -94,6 +94,11 @@ const fallbackTZ = "Asia/Kolkata"
|
||||
// genuine UTC user re-reports their real zone on next load.
|
||||
func (s *SadhnaService) resolveTZ(ctx context.Context, userID string) (string, *time.Location) {
|
||||
tz, _ := s.logs.UserTimezone(ctx, userID)
|
||||
// Canonicalize legacy aliases (e.g. stored "Asia/Calcutta") — the name
|
||||
// is fed into SQL AT TIME ZONE, which rejects aliases on a Postgres
|
||||
// without the tzdata backward links. Covers rows written before
|
||||
// SetTimezone started canonicalizing.
|
||||
tz = canonicalTZ(tz)
|
||||
if tz == "" || tz == "UTC" {
|
||||
tz = fallbackTZ
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
package service
|
||||
|
||||
// Legacy IANA timezone aliases → canonical names.
|
||||
//
|
||||
// Browsers report Intl.DateTimeFormat().resolvedOptions().timeZone, and the
|
||||
// ICU/CLDR data they ship still uses several LEGACY ids as its canonical
|
||||
// form — Safari and Chrome genuinely say "Asia/Calcutta", not "Asia/Kolkata".
|
||||
// Go's time.LoadLocation resolves these aliases, so they pass validation and
|
||||
// get stored; but a Postgres built against tzdata without the "backward"
|
||||
// links (Debian/Alpine images with the tzdata-legacy split) rejects them in
|
||||
// AT TIME ZONE with SQLSTATE 22023. Everything we store or hand to SQL goes
|
||||
// through canonicalTZ first.
|
||||
var legacyTZ = map[string]string{
|
||||
// Ids ICU/CLDR still reports as canonical (the ones browsers send).
|
||||
"Asia/Calcutta": "Asia/Kolkata",
|
||||
"Asia/Katmandu": "Asia/Kathmandu",
|
||||
"Asia/Rangoon": "Asia/Yangon",
|
||||
"Asia/Saigon": "Asia/Ho_Chi_Minh",
|
||||
"America/Buenos_Aires": "America/Argentina/Buenos_Aires",
|
||||
"America/Catamarca": "America/Argentina/Catamarca",
|
||||
"America/Cordoba": "America/Argentina/Cordoba",
|
||||
"America/Jujuy": "America/Argentina/Jujuy",
|
||||
"America/Mendoza": "America/Argentina/Mendoza",
|
||||
"America/Indianapolis": "America/Indiana/Indianapolis",
|
||||
"America/Louisville": "America/Kentucky/Louisville",
|
||||
"America/Godthab": "America/Nuuk",
|
||||
"Atlantic/Faeroe": "Atlantic/Faroe",
|
||||
"Pacific/Ponape": "Pacific/Pohnpei",
|
||||
"Pacific/Truk": "Pacific/Chuuk",
|
||||
"Europe/Kiev": "Europe/Kyiv",
|
||||
|
||||
// Other common backward links, in case a zone arrives from an older
|
||||
// client or was set by hand.
|
||||
"Asia/Ashkhabad": "Asia/Ashgabat",
|
||||
"Asia/Chongqing": "Asia/Shanghai",
|
||||
"Asia/Chungking": "Asia/Shanghai",
|
||||
"Asia/Dacca": "Asia/Dhaka",
|
||||
"Asia/Harbin": "Asia/Shanghai",
|
||||
"Asia/Istanbul": "Europe/Istanbul",
|
||||
"Asia/Kashgar": "Asia/Urumqi",
|
||||
"Asia/Macao": "Asia/Macau",
|
||||
"Asia/Tel_Aviv": "Asia/Jerusalem",
|
||||
"Asia/Thimbu": "Asia/Thimphu",
|
||||
"Asia/Ujung_Pandang": "Asia/Makassar",
|
||||
"Asia/Ulan_Bator": "Asia/Ulaanbaatar",
|
||||
"Africa/Asmera": "Africa/Asmara",
|
||||
"America/Coral_Harbour": "America/Atikokan",
|
||||
"Australia/ACT": "Australia/Sydney",
|
||||
"Australia/Canberra": "Australia/Sydney",
|
||||
"Australia/NSW": "Australia/Sydney",
|
||||
"Australia/North": "Australia/Darwin",
|
||||
"Australia/Queensland": "Australia/Brisbane",
|
||||
"Australia/South": "Australia/Adelaide",
|
||||
"Australia/Tasmania": "Australia/Hobart",
|
||||
"Australia/Victoria": "Australia/Melbourne",
|
||||
"Australia/West": "Australia/Perth",
|
||||
"US/Alaska": "America/Anchorage",
|
||||
"US/Arizona": "America/Phoenix",
|
||||
"US/Central": "America/Chicago",
|
||||
"US/Eastern": "America/New_York",
|
||||
"US/Hawaii": "Pacific/Honolulu",
|
||||
"US/Mountain": "America/Denver",
|
||||
"US/Pacific": "America/Los_Angeles",
|
||||
"GB": "Europe/London",
|
||||
"GB-Eire": "Europe/London",
|
||||
"Eire": "Europe/Dublin",
|
||||
"Egypt": "Africa/Cairo",
|
||||
"Hongkong": "Asia/Hong_Kong",
|
||||
"Iceland": "Atlantic/Reykjavik",
|
||||
"Israel": "Asia/Jerusalem",
|
||||
"Japan": "Asia/Tokyo",
|
||||
"NZ": "Pacific/Auckland",
|
||||
"Poland": "Europe/Warsaw",
|
||||
"Portugal": "Europe/Lisbon",
|
||||
"PRC": "Asia/Shanghai",
|
||||
"ROC": "Asia/Taipei",
|
||||
"ROK": "Asia/Seoul",
|
||||
"Singapore": "Asia/Singapore",
|
||||
"Turkey": "Europe/Istanbul",
|
||||
}
|
||||
|
||||
// canonicalTZ returns the canonical IANA name for tz, resolving legacy
|
||||
// aliases; unknown values pass through unchanged.
|
||||
func canonicalTZ(tz string) string {
|
||||
if c, ok := legacyTZ[tz]; ok {
|
||||
return c
|
||||
}
|
||||
return tz
|
||||
}
|
||||
Reference in New Issue
Block a user