Skip to main content

firebird_wire/
tz.rs

1//! Tabela de zonas e tipos para TIME/TIMESTAMP WITH TIME ZONE (FB4+).
2//!
3//! As zonas NOMEADAS recebem ids de [`MAX_NAMED_ZONE`] (65535 = "GMT")
4//! decrescendo; a tabela [`ZONE_NAMES`] é indexada por `MAX_NAMED_ZONE - id`.
5//! As zonas baseadas em OFFSET usam `id = offset_em_minutos + 1439`
6//! (gerado de `/opt/firebird/include/firebird/TimeZones.h`; NÃO editar à mão).
7
8/// Maior id de zona nomeada (corresponde a `GMT`).
9pub const MAX_NAMED_ZONE: u16 = 65535;
10
11/// Ponto-base do código de zonas por offset: `id = offset_minutos + OFFSET_BASE`
12/// (confirmado ao vivo: a zona `+05:30` chega como id 1769 = 330 + 1439).
13pub const OFFSET_BASE: i32 = 1439;
14
15/// Nomes IANA das zonas nomeadas, do id mais alto (65535) ao mais baixo.
16pub static ZONE_NAMES: [&str; 638] = [
17    "GMT",
18    "ACT",
19    "AET",
20    "AGT",
21    "ART",
22    "AST",
23    "Africa/Abidjan",
24    "Africa/Accra",
25    "Africa/Addis_Ababa",
26    "Africa/Algiers",
27    "Africa/Asmara",
28    "Africa/Asmera",
29    "Africa/Bamako",
30    "Africa/Bangui",
31    "Africa/Banjul",
32    "Africa/Bissau",
33    "Africa/Blantyre",
34    "Africa/Brazzaville",
35    "Africa/Bujumbura",
36    "Africa/Cairo",
37    "Africa/Casablanca",
38    "Africa/Ceuta",
39    "Africa/Conakry",
40    "Africa/Dakar",
41    "Africa/Dar_es_Salaam",
42    "Africa/Djibouti",
43    "Africa/Douala",
44    "Africa/El_Aaiun",
45    "Africa/Freetown",
46    "Africa/Gaborone",
47    "Africa/Harare",
48    "Africa/Johannesburg",
49    "Africa/Juba",
50    "Africa/Kampala",
51    "Africa/Khartoum",
52    "Africa/Kigali",
53    "Africa/Kinshasa",
54    "Africa/Lagos",
55    "Africa/Libreville",
56    "Africa/Lome",
57    "Africa/Luanda",
58    "Africa/Lubumbashi",
59    "Africa/Lusaka",
60    "Africa/Malabo",
61    "Africa/Maputo",
62    "Africa/Maseru",
63    "Africa/Mbabane",
64    "Africa/Mogadishu",
65    "Africa/Monrovia",
66    "Africa/Nairobi",
67    "Africa/Ndjamena",
68    "Africa/Niamey",
69    "Africa/Nouakchott",
70    "Africa/Ouagadougou",
71    "Africa/Porto-Novo",
72    "Africa/Sao_Tome",
73    "Africa/Timbuktu",
74    "Africa/Tripoli",
75    "Africa/Tunis",
76    "Africa/Windhoek",
77    "America/Adak",
78    "America/Anchorage",
79    "America/Anguilla",
80    "America/Antigua",
81    "America/Araguaina",
82    "America/Argentina/Buenos_Aires",
83    "America/Argentina/Catamarca",
84    "America/Argentina/ComodRivadavia",
85    "America/Argentina/Cordoba",
86    "America/Argentina/Jujuy",
87    "America/Argentina/La_Rioja",
88    "America/Argentina/Mendoza",
89    "America/Argentina/Rio_Gallegos",
90    "America/Argentina/Salta",
91    "America/Argentina/San_Juan",
92    "America/Argentina/San_Luis",
93    "America/Argentina/Tucuman",
94    "America/Argentina/Ushuaia",
95    "America/Aruba",
96    "America/Asuncion",
97    "America/Atikokan",
98    "America/Atka",
99    "America/Bahia",
100    "America/Bahia_Banderas",
101    "America/Barbados",
102    "America/Belem",
103    "America/Belize",
104    "America/Blanc-Sablon",
105    "America/Boa_Vista",
106    "America/Bogota",
107    "America/Boise",
108    "America/Buenos_Aires",
109    "America/Cambridge_Bay",
110    "America/Campo_Grande",
111    "America/Cancun",
112    "America/Caracas",
113    "America/Catamarca",
114    "America/Cayenne",
115    "America/Cayman",
116    "America/Chicago",
117    "America/Chihuahua",
118    "America/Coral_Harbour",
119    "America/Cordoba",
120    "America/Costa_Rica",
121    "America/Creston",
122    "America/Cuiaba",
123    "America/Curacao",
124    "America/Danmarkshavn",
125    "America/Dawson",
126    "America/Dawson_Creek",
127    "America/Denver",
128    "America/Detroit",
129    "America/Dominica",
130    "America/Edmonton",
131    "America/Eirunepe",
132    "America/El_Salvador",
133    "America/Ensenada",
134    "America/Fort_Nelson",
135    "America/Fort_Wayne",
136    "America/Fortaleza",
137    "America/Glace_Bay",
138    "America/Godthab",
139    "America/Goose_Bay",
140    "America/Grand_Turk",
141    "America/Grenada",
142    "America/Guadeloupe",
143    "America/Guatemala",
144    "America/Guayaquil",
145    "America/Guyana",
146    "America/Halifax",
147    "America/Havana",
148    "America/Hermosillo",
149    "America/Indiana/Indianapolis",
150    "America/Indiana/Knox",
151    "America/Indiana/Marengo",
152    "America/Indiana/Petersburg",
153    "America/Indiana/Tell_City",
154    "America/Indiana/Vevay",
155    "America/Indiana/Vincennes",
156    "America/Indiana/Winamac",
157    "America/Indianapolis",
158    "America/Inuvik",
159    "America/Iqaluit",
160    "America/Jamaica",
161    "America/Jujuy",
162    "America/Juneau",
163    "America/Kentucky/Louisville",
164    "America/Kentucky/Monticello",
165    "America/Knox_IN",
166    "America/Kralendijk",
167    "America/La_Paz",
168    "America/Lima",
169    "America/Los_Angeles",
170    "America/Louisville",
171    "America/Lower_Princes",
172    "America/Maceio",
173    "America/Managua",
174    "America/Manaus",
175    "America/Marigot",
176    "America/Martinique",
177    "America/Matamoros",
178    "America/Mazatlan",
179    "America/Mendoza",
180    "America/Menominee",
181    "America/Merida",
182    "America/Metlakatla",
183    "America/Mexico_City",
184    "America/Miquelon",
185    "America/Moncton",
186    "America/Monterrey",
187    "America/Montevideo",
188    "America/Montreal",
189    "America/Montserrat",
190    "America/Nassau",
191    "America/New_York",
192    "America/Nipigon",
193    "America/Nome",
194    "America/Noronha",
195    "America/North_Dakota/Beulah",
196    "America/North_Dakota/Center",
197    "America/North_Dakota/New_Salem",
198    "America/Ojinaga",
199    "America/Panama",
200    "America/Pangnirtung",
201    "America/Paramaribo",
202    "America/Phoenix",
203    "America/Port-au-Prince",
204    "America/Port_of_Spain",
205    "America/Porto_Acre",
206    "America/Porto_Velho",
207    "America/Puerto_Rico",
208    "America/Punta_Arenas",
209    "America/Rainy_River",
210    "America/Rankin_Inlet",
211    "America/Recife",
212    "America/Regina",
213    "America/Resolute",
214    "America/Rio_Branco",
215    "America/Rosario",
216    "America/Santa_Isabel",
217    "America/Santarem",
218    "America/Santiago",
219    "America/Santo_Domingo",
220    "America/Sao_Paulo",
221    "America/Scoresbysund",
222    "America/Shiprock",
223    "America/Sitka",
224    "America/St_Barthelemy",
225    "America/St_Johns",
226    "America/St_Kitts",
227    "America/St_Lucia",
228    "America/St_Thomas",
229    "America/St_Vincent",
230    "America/Swift_Current",
231    "America/Tegucigalpa",
232    "America/Thule",
233    "America/Thunder_Bay",
234    "America/Tijuana",
235    "America/Toronto",
236    "America/Tortola",
237    "America/Vancouver",
238    "America/Virgin",
239    "America/Whitehorse",
240    "America/Winnipeg",
241    "America/Yakutat",
242    "America/Yellowknife",
243    "Antarctica/Casey",
244    "Antarctica/Davis",
245    "Antarctica/DumontDUrville",
246    "Antarctica/Macquarie",
247    "Antarctica/Mawson",
248    "Antarctica/McMurdo",
249    "Antarctica/Palmer",
250    "Antarctica/Rothera",
251    "Antarctica/South_Pole",
252    "Antarctica/Syowa",
253    "Antarctica/Troll",
254    "Antarctica/Vostok",
255    "Arctic/Longyearbyen",
256    "Asia/Aden",
257    "Asia/Almaty",
258    "Asia/Amman",
259    "Asia/Anadyr",
260    "Asia/Aqtau",
261    "Asia/Aqtobe",
262    "Asia/Ashgabat",
263    "Asia/Ashkhabad",
264    "Asia/Atyrau",
265    "Asia/Baghdad",
266    "Asia/Bahrain",
267    "Asia/Baku",
268    "Asia/Bangkok",
269    "Asia/Barnaul",
270    "Asia/Beirut",
271    "Asia/Bishkek",
272    "Asia/Brunei",
273    "Asia/Calcutta",
274    "Asia/Chita",
275    "Asia/Choibalsan",
276    "Asia/Chongqing",
277    "Asia/Chungking",
278    "Asia/Colombo",
279    "Asia/Dacca",
280    "Asia/Damascus",
281    "Asia/Dhaka",
282    "Asia/Dili",
283    "Asia/Dubai",
284    "Asia/Dushanbe",
285    "Asia/Famagusta",
286    "Asia/Gaza",
287    "Asia/Harbin",
288    "Asia/Hebron",
289    "Asia/Ho_Chi_Minh",
290    "Asia/Hong_Kong",
291    "Asia/Hovd",
292    "Asia/Irkutsk",
293    "Asia/Istanbul",
294    "Asia/Jakarta",
295    "Asia/Jayapura",
296    "Asia/Jerusalem",
297    "Asia/Kabul",
298    "Asia/Kamchatka",
299    "Asia/Karachi",
300    "Asia/Kashgar",
301    "Asia/Kathmandu",
302    "Asia/Katmandu",
303    "Asia/Khandyga",
304    "Asia/Kolkata",
305    "Asia/Krasnoyarsk",
306    "Asia/Kuala_Lumpur",
307    "Asia/Kuching",
308    "Asia/Kuwait",
309    "Asia/Macao",
310    "Asia/Macau",
311    "Asia/Magadan",
312    "Asia/Makassar",
313    "Asia/Manila",
314    "Asia/Muscat",
315    "Asia/Nicosia",
316    "Asia/Novokuznetsk",
317    "Asia/Novosibirsk",
318    "Asia/Omsk",
319    "Asia/Oral",
320    "Asia/Phnom_Penh",
321    "Asia/Pontianak",
322    "Asia/Pyongyang",
323    "Asia/Qatar",
324    "Asia/Qyzylorda",
325    "Asia/Rangoon",
326    "Asia/Riyadh",
327    "Asia/Saigon",
328    "Asia/Sakhalin",
329    "Asia/Samarkand",
330    "Asia/Seoul",
331    "Asia/Shanghai",
332    "Asia/Singapore",
333    "Asia/Srednekolymsk",
334    "Asia/Taipei",
335    "Asia/Tashkent",
336    "Asia/Tbilisi",
337    "Asia/Tehran",
338    "Asia/Tel_Aviv",
339    "Asia/Thimbu",
340    "Asia/Thimphu",
341    "Asia/Tokyo",
342    "Asia/Tomsk",
343    "Asia/Ujung_Pandang",
344    "Asia/Ulaanbaatar",
345    "Asia/Ulan_Bator",
346    "Asia/Urumqi",
347    "Asia/Ust-Nera",
348    "Asia/Vientiane",
349    "Asia/Vladivostok",
350    "Asia/Yakutsk",
351    "Asia/Yangon",
352    "Asia/Yekaterinburg",
353    "Asia/Yerevan",
354    "Atlantic/Azores",
355    "Atlantic/Bermuda",
356    "Atlantic/Canary",
357    "Atlantic/Cape_Verde",
358    "Atlantic/Faeroe",
359    "Atlantic/Faroe",
360    "Atlantic/Jan_Mayen",
361    "Atlantic/Madeira",
362    "Atlantic/Reykjavik",
363    "Atlantic/South_Georgia",
364    "Atlantic/St_Helena",
365    "Atlantic/Stanley",
366    "Australia/ACT",
367    "Australia/Adelaide",
368    "Australia/Brisbane",
369    "Australia/Broken_Hill",
370    "Australia/Canberra",
371    "Australia/Currie",
372    "Australia/Darwin",
373    "Australia/Eucla",
374    "Australia/Hobart",
375    "Australia/LHI",
376    "Australia/Lindeman",
377    "Australia/Lord_Howe",
378    "Australia/Melbourne",
379    "Australia/NSW",
380    "Australia/North",
381    "Australia/Perth",
382    "Australia/Queensland",
383    "Australia/South",
384    "Australia/Sydney",
385    "Australia/Tasmania",
386    "Australia/Victoria",
387    "Australia/West",
388    "Australia/Yancowinna",
389    "BET",
390    "BST",
391    "Brazil/Acre",
392    "Brazil/DeNoronha",
393    "Brazil/East",
394    "Brazil/West",
395    "CAT",
396    "CET",
397    "CNT",
398    "CST",
399    "CST6CDT",
400    "CTT",
401    "Canada/Atlantic",
402    "Canada/Central",
403    "Canada/East-Saskatchewan",
404    "Canada/Eastern",
405    "Canada/Mountain",
406    "Canada/Newfoundland",
407    "Canada/Pacific",
408    "Canada/Saskatchewan",
409    "Canada/Yukon",
410    "Chile/Continental",
411    "Chile/EasterIsland",
412    "Cuba",
413    "EAT",
414    "ECT",
415    "EET",
416    "EST",
417    "EST5EDT",
418    "Egypt",
419    "Eire",
420    "Etc/GMT",
421    "Etc/GMT+0",
422    "Etc/GMT+1",
423    "Etc/GMT+10",
424    "Etc/GMT+11",
425    "Etc/GMT+12",
426    "Etc/GMT+2",
427    "Etc/GMT+3",
428    "Etc/GMT+4",
429    "Etc/GMT+5",
430    "Etc/GMT+6",
431    "Etc/GMT+7",
432    "Etc/GMT+8",
433    "Etc/GMT+9",
434    "Etc/GMT-0",
435    "Etc/GMT-1",
436    "Etc/GMT-10",
437    "Etc/GMT-11",
438    "Etc/GMT-12",
439    "Etc/GMT-13",
440    "Etc/GMT-14",
441    "Etc/GMT-2",
442    "Etc/GMT-3",
443    "Etc/GMT-4",
444    "Etc/GMT-5",
445    "Etc/GMT-6",
446    "Etc/GMT-7",
447    "Etc/GMT-8",
448    "Etc/GMT-9",
449    "Etc/GMT0",
450    "Etc/Greenwich",
451    "Etc/UCT",
452    "Etc/UTC",
453    "Etc/Universal",
454    "Etc/Zulu",
455    "Europe/Amsterdam",
456    "Europe/Andorra",
457    "Europe/Astrakhan",
458    "Europe/Athens",
459    "Europe/Belfast",
460    "Europe/Belgrade",
461    "Europe/Berlin",
462    "Europe/Bratislava",
463    "Europe/Brussels",
464    "Europe/Bucharest",
465    "Europe/Budapest",
466    "Europe/Busingen",
467    "Europe/Chisinau",
468    "Europe/Copenhagen",
469    "Europe/Dublin",
470    "Europe/Gibraltar",
471    "Europe/Guernsey",
472    "Europe/Helsinki",
473    "Europe/Isle_of_Man",
474    "Europe/Istanbul",
475    "Europe/Jersey",
476    "Europe/Kaliningrad",
477    "Europe/Kiev",
478    "Europe/Kirov",
479    "Europe/Lisbon",
480    "Europe/Ljubljana",
481    "Europe/London",
482    "Europe/Luxembourg",
483    "Europe/Madrid",
484    "Europe/Malta",
485    "Europe/Mariehamn",
486    "Europe/Minsk",
487    "Europe/Monaco",
488    "Europe/Moscow",
489    "Europe/Nicosia",
490    "Europe/Oslo",
491    "Europe/Paris",
492    "Europe/Podgorica",
493    "Europe/Prague",
494    "Europe/Riga",
495    "Europe/Rome",
496    "Europe/Samara",
497    "Europe/San_Marino",
498    "Europe/Sarajevo",
499    "Europe/Saratov",
500    "Europe/Simferopol",
501    "Europe/Skopje",
502    "Europe/Sofia",
503    "Europe/Stockholm",
504    "Europe/Tallinn",
505    "Europe/Tirane",
506    "Europe/Tiraspol",
507    "Europe/Ulyanovsk",
508    "Europe/Uzhgorod",
509    "Europe/Vaduz",
510    "Europe/Vatican",
511    "Europe/Vienna",
512    "Europe/Vilnius",
513    "Europe/Volgograd",
514    "Europe/Warsaw",
515    "Europe/Zagreb",
516    "Europe/Zaporozhye",
517    "Europe/Zurich",
518    "Factory",
519    "GB",
520    "GB-Eire",
521    "GMT+0",
522    "GMT-0",
523    "GMT0",
524    "Greenwich",
525    "HST",
526    "Hongkong",
527    "IET",
528    "IST",
529    "Iceland",
530    "Indian/Antananarivo",
531    "Indian/Chagos",
532    "Indian/Christmas",
533    "Indian/Cocos",
534    "Indian/Comoro",
535    "Indian/Kerguelen",
536    "Indian/Mahe",
537    "Indian/Maldives",
538    "Indian/Mauritius",
539    "Indian/Mayotte",
540    "Indian/Reunion",
541    "Iran",
542    "Israel",
543    "JST",
544    "Jamaica",
545    "Japan",
546    "Kwajalein",
547    "Libya",
548    "MET",
549    "MIT",
550    "MST",
551    "MST7MDT",
552    "Mexico/BajaNorte",
553    "Mexico/BajaSur",
554    "Mexico/General",
555    "NET",
556    "NST",
557    "NZ",
558    "NZ-CHAT",
559    "Navajo",
560    "PLT",
561    "PNT",
562    "PRC",
563    "PRT",
564    "PST",
565    "PST8PDT",
566    "Pacific/Apia",
567    "Pacific/Auckland",
568    "Pacific/Bougainville",
569    "Pacific/Chatham",
570    "Pacific/Chuuk",
571    "Pacific/Easter",
572    "Pacific/Efate",
573    "Pacific/Enderbury",
574    "Pacific/Fakaofo",
575    "Pacific/Fiji",
576    "Pacific/Funafuti",
577    "Pacific/Galapagos",
578    "Pacific/Gambier",
579    "Pacific/Guadalcanal",
580    "Pacific/Guam",
581    "Pacific/Honolulu",
582    "Pacific/Johnston",
583    "Pacific/Kiritimati",
584    "Pacific/Kosrae",
585    "Pacific/Kwajalein",
586    "Pacific/Majuro",
587    "Pacific/Marquesas",
588    "Pacific/Midway",
589    "Pacific/Nauru",
590    "Pacific/Niue",
591    "Pacific/Norfolk",
592    "Pacific/Noumea",
593    "Pacific/Pago_Pago",
594    "Pacific/Palau",
595    "Pacific/Pitcairn",
596    "Pacific/Pohnpei",
597    "Pacific/Ponape",
598    "Pacific/Port_Moresby",
599    "Pacific/Rarotonga",
600    "Pacific/Saipan",
601    "Pacific/Samoa",
602    "Pacific/Tahiti",
603    "Pacific/Tarawa",
604    "Pacific/Tongatapu",
605    "Pacific/Truk",
606    "Pacific/Wake",
607    "Pacific/Wallis",
608    "Pacific/Yap",
609    "Poland",
610    "Portugal",
611    "ROC",
612    "ROK",
613    "SST",
614    "Singapore",
615    "SystemV/AST4",
616    "SystemV/AST4ADT",
617    "SystemV/CST6",
618    "SystemV/CST6CDT",
619    "SystemV/EST5",
620    "SystemV/EST5EDT",
621    "SystemV/HST10",
622    "SystemV/MST7",
623    "SystemV/MST7MDT",
624    "SystemV/PST8",
625    "SystemV/PST8PDT",
626    "SystemV/YST9",
627    "SystemV/YST9YDT",
628    "Turkey",
629    "UCT",
630    "US/Alaska",
631    "US/Aleutian",
632    "US/Arizona",
633    "US/Central",
634    "US/East-Indiana",
635    "US/Eastern",
636    "US/Hawaii",
637    "US/Indiana-Starke",
638    "US/Michigan",
639    "US/Mountain",
640    "US/Pacific",
641    "US/Pacific-New",
642    "US/Samoa",
643    "UTC",
644    "Universal",
645    "VST",
646    "W-SU",
647    "WET",
648    "Zulu",
649    "America/Nuuk",
650    "Asia/Qostanay",
651    "Pacific/Kanton",
652    "Europe/Kyiv",
653    "America/Ciudad_Juarez",
654    "America/Coyhaique",
655];
656
657// ---------------------------------------------------------------------------
658// Consultas de zona
659// ---------------------------------------------------------------------------
660
661/// Menor offset (em minutos) que uma zona baseada em offset pode representar.
662const MIN_OFFSET: i32 = -1439;
663/// Maior offset (em minutos) que uma zona baseada em offset pode representar.
664const MAX_OFFSET: i32 = 1439;
665
666/// Nome IANA de uma zona NOMEADA, ou `None` se `id` for uma zona por offset
667/// (use [`offset_minutes`]) ou um id desconhecido.
668pub fn zone_name(id: u16) -> Option<&'static str> {
669    let idx = MAX_NAMED_ZONE.checked_sub(id)? as usize;
670    ZONE_NAMES.get(idx).copied()
671}
672
673/// Offset em minutos se `id` codificar uma zona baseada em offset, senão `None`
674/// (nesse caso é uma zona nomeada — veja [`zone_name`]).
675pub fn offset_minutes(id: u16) -> Option<i16> {
676    let off = id as i32 - OFFSET_BASE;
677    (MIN_OFFSET..=MAX_OFFSET)
678        .contains(&off)
679        .then_some(off as i16)
680}
681
682/// Id de zona do Firebird para uma zona baseada em offset (minutos).
683pub fn offset_zone_id(offset_minutes: i16) -> u16 {
684    (offset_minutes as i32 + OFFSET_BASE) as u16
685}
686
687/// Rótulo legível de uma zona: o nome IANA, `±HH:MM` para zonas por offset, ou
688/// `zone <id>` quando o id não é reconhecido (uma zona mais nova que esta tabela).
689pub fn zone_label(id: u16) -> String {
690    if let Some(name) = zone_name(id) {
691        name.to_string()
692    } else if let Some(off) = offset_minutes(id) {
693        format_offset(off)
694    } else {
695        format!("zone {id}")
696    }
697}
698
699/// Formata um offset em minutos como `±HH:MM`.
700pub fn format_offset(minutes: i16) -> String {
701    let sign = if minutes < 0 { '-' } else { '+' };
702    let m = minutes.unsigned_abs() as u32;
703    format!("{sign}{:02}:{:02}", m / 60, m % 60)
704}
705
706#[cfg(test)]
707mod tests {
708    use super::*;
709
710    #[test]
711    fn named_zone_lookup() {
712        assert_eq!(zone_name(MAX_NAMED_ZONE), Some("GMT"));
713        // A última entrada da tabela.
714        let last = MAX_NAMED_ZONE - (ZONE_NAMES.len() as u16 - 1);
715        assert_eq!(zone_name(last), Some(ZONE_NAMES[ZONE_NAMES.len() - 1]));
716        // Um id de zona por offset não é nomeado.
717        assert_eq!(zone_name(OFFSET_BASE as u16), None);
718    }
719
720    #[test]
721    fn offset_zone_roundtrip() {
722        for off in [-1439i16, -180, -60, 0, 60, 330, 1439] {
723            let id = offset_zone_id(off);
724            assert_eq!(offset_minutes(id), Some(off));
725        }
726        // GMT por offset (id 1440) = +00:00.
727        assert_eq!(offset_minutes(OFFSET_BASE as u16), Some(0));
728        assert_eq!(format_offset(330), "+05:30");
729        assert_eq!(format_offset(-180), "-03:00");
730    }
731}