├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── db ├── Makefile └── tz-erl ├── include ├── tz_database.hrl └── tz_index.hrl ├── rebar ├── rebar.config └── src ├── erlang_localtime.app.src ├── ibuild.erl ├── localtime.erl └── localtime_dst.erl /.gitignore: -------------------------------------------------------------------------------- 1 | ebin/ -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: include/tz_index.hrl 2 | ./rebar compile 3 | 4 | check: 5 | ./rebar eunit 6 | 7 | include/tz_index.hrl: src/ibuild.erl include/tz_database.hrl 8 | cd include && ln -s ../src/ibuild.erl && escript ibuild.erl; EV=$$?; rm ibuild.erl; exit $$EV 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | Erlang Localtime 3 | === 4 | 5 | 6 | ### Public exports 7 | 8 | * `utc_to_local/2` – Converts UTC time to local according to specified Timezone 9 | * `local_to_utc/2` – Converts local time to UTC 10 | * `local_to_local/3` – Converts local time to local 11 | * `tz_name/2` – Returns a timezone name (E.g. MSK, MSD, etc) 12 | * `tz_shift/2` – Returns time difference between local datetime and GMT 13 | * `tz_shift/3` – Returns time difference between local datetime and required timezone 14 | 15 | ### Details 16 | 17 | #### Types 18 | * `DateTime` = `{date(), time()}`. 19 | * `TimeZone` = `TimeZoneFrom` = `TimeZoneTo` = `list()`, e.g. `"Europe/Moscow"`, `"America/NewYork"` or abbreviations `"MSK"`, `"MSD"`, etc. 20 | * `ZoneName` = `{StdAbbr :: list(), StdName :: list()}`, e.g. `{"MSK","MSK"}` 21 | * `ZoneShift` = `{Sign :: '+' | '-', Offset :: non_neg_integer(), RemOffset :: non_neg_integer()}` 22 | 23 | #### Dialyzer 24 | 25 | `utc_to_local(DateTime, TimeZone) → DateTime | {error, Reason}` 26 | 27 | `local_to_utc(DateTime, TimeZone) → DateTime | {error, Reason}` 28 | 29 | `local_to_local(DateTime, TimeZoneFrom, TimeZoneTo) → DateTime | {error, Reason}` 30 | 31 | `tz_name(DateTime, TimeZone) → ZoneName | {error, Reason}` 32 | 33 | `tz_shift(DateTime, TimeZone) → 0 | ZoneShift | {error, Reason}` 34 | 35 | `tz_shift(DateTime, TimeZoneFrom, TimeZoneTo) → 0 | ZoneShift | {error, Reason}` 36 | 37 | #### Note 38 | 39 | Aabbreviation is just used to find appropriate timezone name. If you want to convert `"MSK"` → `"PDT"`, but source timezone is not in daylight saving, it will be corrected by library and `"MSK"` → `"PST"` conversion will be made. 40 | 41 | ### Examples of usage 42 | 43 | #### Converts UTC time to local one 44 | ```erlang 45 | localtime:utc_to_local({{2010, 7, 22}, {17, 56, 23}}, "Europe/Moscow"). 46 | {{2010,10,10},{21,56,23}} 47 | ``` 48 | 49 | #### Converts local time to UTC one 50 | ```erlang 51 | localtime:local_to_utc({{2010, 10, 10}, {21, 56, 23}}, "Europe/Moscow"). 52 | {{2010,10,10},{17,56,23}} 53 | ``` 54 | 55 | #### Converts time from one local timezone to another local one 56 | ```erlang 57 | localtime:local_to_local({{2010, 10, 10}, {21, 56, 23}}, "Europe/Moscow", "Australia/Sydney"). 58 | {{2010,10,11},{3,56,23}} 59 | ``` 60 | 61 | #### Returns timezone name 62 | ```erlang 63 | localtime:tz_name({{2010, 10, 10}, {21, 56, 23}}, "Europe/Moscow"). 64 | {"MSK","MSK"} 65 | 66 | localtime:tz_name({{2010,10,11},{3,56,23}}, "Australia/Sydney"). 67 | {"EST","EST"} 68 | ``` 69 | 70 | #### Calculates time difference between UTC and local one 71 | ```erlang 72 | localtime:tz_shift({{2013, 01, 22}, {18, 17, 00}}, "Europe/Moscow"). 73 | {'+',4,0} 74 | 75 | localtime:tz_shift({{2013, 01, 22}, {18, 17, 00}}, "America/New York"). 76 | {'-',5,0} 77 | ``` 78 | 79 | #### Calculates time difference between two local timezones 80 | ```erlang 81 | localtime:tz_shift({{2013, 01, 22}, {18, 17, 00}}, "America/New York", "Europe/Moscow"). 82 | {'+',9,0} 83 | ``` 84 | -------------------------------------------------------------------------------- /db/Makefile: -------------------------------------------------------------------------------- 1 | TZDIR=tzdata 2 | TZ_FILES=$(addprefix $(TZDIR)/, africa antarctica asia australasia backward etcetera europe northamerica southamerica) 3 | 4 | tzout: $(TZ_FILES) 5 | TZ_VERSION=`perl -n -e 'm/^VERSION\s*=\s*(\S+)/ and print $$1;' $(TZDIR)/Makefile`; \ 6 | ./tz-erl --version $$TZ_VERSION -o $@ $^ 7 | 8 | $(TZ_FILES): $(TZDIR) 9 | 10 | $(TZDIR): tzdata-latest.tar.gz 11 | mkdir $(TZDIR) && cd $(TZDIR) && tar xzf ../$< 12 | 13 | tzdata-latest.tar.gz: 14 | curl -O "ftp://ftp.iana.org/tz/tzdata-latest.tar.gz" 15 | 16 | 17 | -------------------------------------------------------------------------------- /db/tz-erl: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env perl 2 | 3 | # This script processes time zone definitions from the Olson database 4 | # and transforms them into the format used by the erlang_localtime 5 | # library. 6 | # 7 | # Some helpful URLs: 8 | # https://www.iana.org/time-zones 9 | # https://github.com/dmitryme/erlang_localtime 10 | # http://www.cstdbill.com/tzdb/tz-how-to.html 11 | 12 | # Known bugs (should fix): 13 | # * Discarding past/future Rules considers only year. Better to 14 | # use a window [now, one-year-from-now) so that our output rules 15 | # are valid for at least a year. 16 | # Known bugs (can't fix without upstream changes): 17 | # * Africa/Casablanca: Has more than one DST transition per year. 18 | # * Pacific/Fiji: DST does not start/end on Nth DayOfWeek in month. 19 | # * America/Godthab: Transition time as UTC moves into previous day. 20 | 21 | use strict; 22 | use warnings; 23 | 24 | use Getopt::Long; 25 | use Time::Local qw( timelocal timelocal_nocheck ); 26 | use Data::Dump; 27 | 28 | use constant DPW => 7; # Days per week. 29 | use constant HPD => 24; # Hours per day. 30 | use constant MPH => 60; # Minutes per hour. 31 | use constant SPECIFICITY_MAX => 100; 32 | 33 | use constant { 34 | RULE_DATE => 0, 35 | RULE_SAVED => 1, 36 | RULE_TIME => 2, 37 | RULE_LETTERS => 3, 38 | RULE_SPECIFICITY => 4, 39 | }; 40 | use constant RULE_NULL => [ undef, 0, '0W', '-', 0 ]; 41 | 42 | my $version = undef; 43 | my $output_file; 44 | my $date; 45 | 46 | GetOptions( 47 | 'version=s' => \$version, 48 | 'output=s' => \$output_file, 49 | 'date=s' => \$date, 50 | ) or die; 51 | 52 | my @data = @ARGV; 53 | 54 | my ($current_day, $current_month, $current_year) = do { 55 | if (defined $date) { 56 | $date =~ m/^(\d\d\d\d)-?(\d\d)-?(\d\d)$/ or die "parse date \"$date\" as YYYY-MM-DD failed\n"; 57 | ($3, $2 - 1, $1); 58 | } else { 59 | my @lt = localtime(time); 60 | ($lt[3], $lt[4], $lt[5] + 1900); 61 | } 62 | }; 63 | 64 | my %rule; 65 | my %rule_base; 66 | my %output; 67 | my @problem; 68 | 69 | # Add the null rule. 70 | $rule_base{'-'} = [ 0, RULE_NULL ]; 71 | 72 | # Have to make three passes through the file. 73 | # First pass: process Rule lines. 74 | process_data(\@data, { Rule => \&rule_line }); 75 | # Second pass: process Zone lines. 76 | process_data(\@data, { Zone => \&zone_line }); 77 | # Third pass, process Link lines. 78 | process_data(\@data, { Link => \&link_line }); 79 | 80 | my $ofh; 81 | if (defined $output_file) { 82 | open($ofh, '>', $output_file) or die "open $output_file for write failed: $!\n"; 83 | } else { 84 | $output_file = 'STDOUT'; 85 | open($ofh, '>&STDOUT') or die "dup $output_file failed: $!\n"; 86 | } 87 | 88 | printf $ofh " %%%% Automatically generated from the time zone database%s for %04d-%02d-%02d.\n", 89 | (defined $version ? " version $version" : ''), 90 | $current_year, $current_month + 1, $current_day; 91 | 92 | print $ofh "\n"; 93 | print $ofh " %% Problems:\n"; 94 | print $ofh map(" %% $_\n", @problem); 95 | print $ofh "\n"; 96 | 97 | print $ofh join(",\n", map { 98 | (my $o = $output{$_}) =~ s/#ZONE#/$_/; 99 | " $o"; 100 | } (sort keys %output)), 101 | "\n"; 102 | 103 | close($ofh) or die "close $output_file failed: $!\n"; 104 | 105 | exit(0); 106 | 107 | ######################################################################## 108 | 109 | sub process_data { 110 | my ($data, $handler) = @_; 111 | 112 | foreach my $f (@$data) { 113 | my $fh = $f; 114 | { 115 | # We open the file this way so that die and warn print the filename. 116 | no strict 'refs'; 117 | open($fh, '<', $fh) or die "open $fh for read failed: $!"; 118 | } 119 | 120 | # Read the Olson database. 121 | my ($last_linetype, $last_lineprefix); 122 | while (my $l = <$fh>) { 123 | chomp($l); 124 | $l =~ s/\s*#.*//; # Remove comments. 125 | $l =~ s/\s+$//; # Remove trailing whitespace. 126 | $l eq '' and next; 127 | 128 | my $linetype = do { 129 | if ($l =~ m/^((\S+)\s+\S+)/) { 130 | # Continuation line. 131 | $last_linetype = $2; 132 | $last_lineprefix = $1; 133 | } else { 134 | $l = $last_lineprefix . $l; 135 | } 136 | $last_linetype; 137 | }; 138 | 139 | if (defined(my $h = $handler->{$linetype})) { 140 | $h->($l); 141 | } 142 | } 143 | 144 | close($fh); 145 | } 146 | } 147 | 148 | sub offset_minutes { 149 | my ($off, $adj) = @_; 150 | 151 | my $convert_offset = sub { 152 | my $m = $_[0]; 153 | if ($m =~ m/^([\+\-]?)(?:(\d+):)?(\d+)$/) { 154 | $m = (defined $2 ? $2 : 0) * MPH + $3; 155 | if ($1 eq '-') { $m = -$m; } 156 | } 157 | return $m; 158 | }; 159 | 160 | my $offset = $convert_offset->($off); 161 | if (defined $adj) { 162 | $offset -= $convert_offset->($adj); 163 | } 164 | 165 | return $offset; 166 | } 167 | 168 | 169 | sub rule_line { 170 | my ($l) = @_; 171 | my ($RULE, $name, $from, $to, $type, $in, $on, $at, $save, $letters) = split(m/\s+/, $l); 172 | 173 | # The rule lines in the time zone database describe transitions. 174 | # 175 | # Cases we have to handle: 176 | # 177 | # 1. There are no rules still active. We need to determine the last 178 | # transition and apply it statically. (Example: Ghana.) 179 | # 180 | # 2. There are active rules. We should determine the current rules 181 | # (ignore old rules and future rules) and transfer them to the 182 | # output rules. (Example: Morocco.) 183 | 184 | my $save_minutes = offset_minutes($save); 185 | 186 | # The rules that this function generates has these parts. 187 | # These are accessed using the RULE_* constants defined above. 188 | # 1. A description of the date on which the transition happens, 189 | # or undef if this is a base rule. 190 | # 2. The number of minutes "saved" (the difference from the base 191 | # offset for the zone). 192 | # 3. The time in minutes after midnight at which the transition 193 | # happens. 194 | # 4. The letter for the new state (often 'S' for standard, or 'D' 195 | # for daylight). 196 | # 5. The number of years the rule covers (used to select which rules 197 | # to eliminate when there are more than two rules in a year). 198 | 199 | # Update the base rule. 200 | my $rule_last_active_epoch = last_active_epoch($from, $to, $in, $on); 201 | if (defined $rule_last_active_epoch) { 202 | if (! defined $rule_base{$name} || $rule_base{$name}->[0] < $rule_last_active_epoch) { 203 | $rule_base{$name} = [ $rule_last_active_epoch, [ undef, $save_minutes, 0, $letters, SPECIFICITY_MAX ] ]; 204 | } 205 | } 206 | 207 | my $transform_rule = sub { 208 | my $rule; 209 | if ($on =~ m/^(\w+)>=(\d+)$/) { 210 | # If start day is not a multiple of a week, round it to nearest week. 211 | $rule = [ int(($2-1+int(DPW/2))/DPW) + 1, lc($1), lc($in) ]; # e.g. [ '2', sun', 'nov' ] 212 | if (($2-1) % DPW) { 213 | warn "on $on fuzz for $name -> $rule->[0]"; 214 | push(@problem, "Rounded $in $on to [@$rule] in Rule $name."); 215 | } 216 | } elsif ($on =~ m/^last(\w+)$/) { 217 | $rule = [ 'last', lc($1), lc($in) ]; # e.g. [ 'last', 'sun', 'apr' ] 218 | } else { 219 | warn "no match for $on in rule $l"; 220 | push(@problem, "Ignored $in $on in Rule $name."); 221 | } 222 | my $at_minutes = $at; 223 | if ($at =~ m/^([\+\-]?)(?:(\d+)\:)(\d+)([wsguz]?)/) { 224 | $at_minutes = $2 * MPH + $3; my $z = $4; 225 | if ($1 eq '-') { $at_minutes = -$at_minutes; } 226 | if ($z eq '' or $z eq 'w') { 227 | # Change specified at local (pre-change) wall-clock time. 228 | $at_minutes .= 'W'; 229 | } elsif ($z eq 's') { 230 | # Change specified at local standard time. 231 | $at_minutes .= 'S'; 232 | } elsif ($z eq 'g' or $z eq 'u' or $z eq 'z') { 233 | # Change specified at UTC. 234 | $at_minutes .= 'Z'; 235 | } 236 | } 237 | my $specificity = 238 | $to eq 'only' ? 1 : 239 | $to eq 'max' ? SPECIFICITY_MAX : 240 | $to - $from + 1; 241 | 242 | return [ $rule, $save_minutes, $at_minutes, $letters, $specificity ]; 243 | }; 244 | 245 | # We ignore any rule that has a definite to (end) time. 246 | if (($to eq 'only' && $from == $current_year) || 247 | ($to ne 'only' && ($to eq 'max' || $to >= $current_year) && $from <= $current_year)) { 248 | push(@{$rule{$name}}, $transform_rule->()); 249 | } 250 | } 251 | 252 | # Process a Zone line and updates the %output hash. 253 | sub zone_line { 254 | my ($l) = @_; 255 | my ($ZONE, $name, $gmtoff, $rules, $format, $until) = split(m/\s+/, $l, 6); 256 | # We ignore any zone line that has a definite until (end) time that 257 | # is in the past. 258 | if (defined $until) { 259 | my $until_year = ($until =~ m/^(\d+)/)[0]; 260 | if ($until_year >= $current_year) { 261 | die "until $until not handled"; 262 | } 263 | return; 264 | } 265 | 266 | # Set $name1 and $rule1 for (start of) standard time. If zone has 267 | # DST, set name2 and $rule2 for (start of ) DST, otherwise it is 268 | # equal to standard time. 269 | my ($name1, $name2, $rule1, $rule2); 270 | my @rules = @{$rule{$rules} || []}; 271 | 272 | # If we have more than two rules, discard all except for the two 273 | # most-specific rules. 274 | if (scalar(@rules) > 2) { 275 | print STDERR "discarding excess rules from $rules for $name\n", Data::Dump::dump(\@rules), "\n"; 276 | push(@problem, "Discarded excess rules for Zone $name."); 277 | @rules = sort { $b->[RULE_SPECIFICITY] <=> $a->[RULE_SPECIFICITY] } @rules; 278 | $#rules = 1; 279 | } 280 | 281 | if (scalar(@rules) == 0) { 282 | # No active rules, use base rule. 283 | my $rule0 = $rule_base{$rules}->[1]; 284 | $name1 = zonename($format, $rule0->[RULE_LETTERS], undef); 285 | $name2 = undef; 286 | $rule1 = $rule2 = RULE_NULL; 287 | } elsif (scalar(@rules) == 1) { 288 | # One active rule. This is a year that DST started or stopped 289 | # being observed 290 | print STDERR Data::Dump::dump(\@rules), "\n"; 291 | die "one rule for $name"; 292 | $name1 = zonename($format, $rules[0]->[RULE_LETTERS], undef); 293 | $name2 = undef; 294 | $rule1 = $rule2 = RULE_NULL; 295 | } else { # 2 rules 296 | if ($rules[0]->[RULE_SAVED] != 0) { @rules = reverse(@rules); }; # Standard time first. 297 | $rule1 = $rules[0]; 298 | $rule2 = $rules[1]; 299 | $name1 = zonename($format, $rule1->[RULE_LETTERS], 0); 300 | $name2 = zonename($format, $rule2->[RULE_LETTERS], 1); 301 | } 302 | 303 | my $gmtoff_min = offset_minutes($gmtoff); 304 | 305 | # https://github.com/dmitryme/erlang_localtime/blob/master/include/tz_database.hrl 306 | # Documentation for output format. 307 | # 308 | # {TimeZoneName, {StdAbbr, StdName}, {DstAbbr, DstName}, StdMin, DstMin, DstStartDay, DstStartTime, DstEndDay, DstEndTime} 309 | # TimeZoneName = String(), TimeZone name, MUST be unique. It is a key 310 | # StdName = {String(), String()}, name and abbreviations of timezone before daylight shift 311 | # DstName = {String(), String()}, name and abbreviations of timezone after daylight shift 312 | # StdMin = Integer(), GMT offset in minutes. W/o daylight savings 313 | # DstMin = Integer(), daylight saving. Adjustment for GMT offset, when daylight saving is on 314 | # DstStartDay = {NthWeekday, Weekday, Month}, daylight saving transition rule. Can be undef if no daylight saving rule specified 315 | # NthWeekday = Integer(), 1(first week),2(second week),3(...),4(...),5(...),-1(last week) 316 | # Weekday = atom(), sun,mon,tue,wed,thu,fri,sat 317 | # Month = atom(), jan,deb,mar,apr,may,jun,jul,aug,sep,oct,mov,dec 318 | # DstStartTime = {Hour, Min} - time of daylight saving transition 319 | # Hour = Integer(), [0..23] 320 | # Min = Integer(), [0..59] 321 | # DstEndDay = {NthWeekday, Weekday, Month} - transition back to std. Can be undef if no daylight saving rule specified 322 | # {Hour, Min} - time of transition to std. 323 | # 324 | # Example output. 325 | # {"America/Los Angeles",{"PST","Pacific Standard Time"},{"PDT","Pacific Daylight Time"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 326 | # {"America/Puerto Rico",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 327 | 328 | $output{$name} = build_term( 329 | '#ZONE#', # TimeZoneName 330 | [ $name1, $name1 ], # StdAbbr, StdName 331 | defined $name2 ? [ $name2, $name2 ] : undef, # DstAbbr, DstName 332 | $gmtoff_min, # StdMin 333 | $rule2->[RULE_SAVED], # DstMin 334 | $rule2->[RULE_DATE], # DstStartDay, 335 | rulestart($rule2->[RULE_TIME], $gmtoff_min, 0, $name), # DstStartTime 336 | $rule1->[RULE_DATE], # DstEndDay 337 | rulestart($rule1->[RULE_TIME], $gmtoff_min, $rule2->[RULE_SAVED], $name), # DstEndTime 338 | ); 339 | } 340 | 341 | sub zonename { 342 | my ($format, $letter, $dst) = @_; 343 | if (defined($dst) && $format =~ m,/,) { 344 | my @format = split(m,/,, $format); 345 | return $format[$dst]; 346 | } else { 347 | return sprintf($format, $letter eq '-' ? '' : $letter); 348 | } 349 | } 350 | 351 | # erlang_localtime wants the transition time in the local wallclock 352 | # time before the transition. 353 | sub rulestart { 354 | my ($start, $gmtoff, $save, $name) = @_; 355 | $start =~ m/^(\d+)(\w)$/ or die "no match for $start"; 356 | ($start, my $modified) = ($1, $2); 357 | 358 | if ($modified eq 'W') { 359 | # No adjustment needed. 360 | } elsif ($modified eq 'Z') { 361 | $start += $gmtoff + $save; 362 | 363 | # If adding a (negative) GMT offset puts the time in the previous 364 | # day, move it up to the start of the day. If adding a (positive) 365 | # GMT offset puts the time in the next day, move it back to the 366 | # end of the day. I think that this is wrong, and that actually 367 | # the transition should be moved into the previous or next day, 368 | # but it's not possible to consistently handle these rules with 369 | # "third Sunday in May" logic. (For example, the day before the 370 | # third Sunday in May may be either the second or third Saturday 371 | # in May.) Having the transition off by a few hours every year is 372 | # better than having it be off by a week every seven years or so. 373 | if ($start < 0) { 374 | warn "moving rule to beginning of day for $name"; 375 | push(@problem, "Moving rule to beginning of day for Zone $name."); 376 | $start = 0; 377 | } elsif ($start > HPD * MPH) { 378 | warn "moving rule to end of day for $name"; 379 | push(@problem, "Moving rule to end of day for Zone $name."); 380 | $start = HPD * MPH; 381 | } 382 | } elsif ($modified eq 'S') { 383 | # To handle this properly, we would have to know the prevailing 384 | # wall-clock offset from standard time. In the general case this 385 | # could be different from $save, but in practice all of the 386 | # transitions are from standard time to daylight time or vice 387 | # versa and not between two different offsets from standard time, 388 | # and so this works. 389 | $start += $save; 390 | } 391 | 392 | return [ int($start / MPH), $start % MPH ]; 393 | } 394 | 395 | sub build_term { 396 | my @term; 397 | foreach my $e (@_) { 398 | if (! defined $e) { 399 | push(@term, 'undef'); 400 | } elsif (ref($e) eq 'ARRAY') { 401 | push(@term, build_term(@$e)); 402 | } elsif ($e =~ m/^(\-?\d+|[a-z].*)$/) { 403 | push(@term, $e); # number or term 404 | } else { 405 | push(@term, "\"$e\""); # string 406 | } 407 | } 408 | 409 | return '{' . join(',', @term) . '}'; 410 | } 411 | 412 | sub link_line { 413 | my ($l) = @_; 414 | my ($LINK, $canon_name, $old_name) = split(m/\s+/, $l); 415 | if (! defined $output{$canon_name}) { 416 | print STDERR "no zone $canon_name for link $old_name\n"; 417 | } else { 418 | $output{$old_name} = $output{$canon_name}; 419 | } 420 | } 421 | 422 | my (@mon_to_name, %mon_from_name, @dow_to_name, %dow_from_name); 423 | INIT { 424 | @mon_to_name = qw(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec); 425 | %mon_from_name = map { $mon_to_name[$_] => $_ } (0..$#mon_to_name); 426 | @dow_to_name = qw(Sun Mon Tue Wed Thu Fri Sat); 427 | %dow_from_name= map { $dow_to_name[$_] => $_ } (0..$#dow_to_name); 428 | } 429 | 430 | sub on_to_day_of_month { 431 | my ($on, $year, $month) = @_; 432 | 433 | my $day; 434 | if ($on =~ m/^\d+$/) { 435 | $day = $on; 436 | } else { 437 | my ($desired_dow, $time_base); 438 | if ($on =~ m/^(\w+)>=(\d+)$/) { 439 | $desired_dow = $dow_from_name{$1}; my $desired_day = $2; 440 | $time_base = timelocal(0, 0, 0, $desired_day, $month, $year); 441 | } elsif ($on =~ m/^last(\w+)$/) { 442 | $desired_dow = $dow_from_name{$1}; 443 | # One week before the beginning of the next month. 444 | $time_base = timelocal_nocheck(0, 0, 0, - DPW, $month + 1, $year); 445 | } else { 446 | die "match $on failed"; 447 | } 448 | ($day, my $dow) = (localtime($time_base))[3,6]; 449 | if ($dow != $desired_dow) { $day += (DPW + $desired_dow - $dow) % DPW; } 450 | } 451 | 452 | return $day; 453 | } 454 | 455 | # Returns the epoch that the rule was last active, or undef if the 456 | # rule has never been active (i.e., it begins in the future). 457 | sub last_active_epoch { 458 | my ($from, $to, $in, $on) = @_; 459 | # $from is a year. 460 | # $to is a year, or 'only', or 'max'. 461 | # $in is a month name (e.g., 'Jan'). 462 | # $on is a day-of-month, or a day-of-week>=day-of-month, or 'last'day-of-week. 463 | 464 | my $month = $mon_from_name{$in}; 465 | 466 | # First check the rule's from time; if in the future return undef. 467 | if ($from > $current_year) { return undef; } 468 | if ($from == $current_year && $month > $current_month) { return undef; } 469 | if ($from == $current_year && $month == $current_month) { 470 | my $day = on_to_day_of_month($on, $current_year, $current_month); 471 | if ($day > $current_day) { return undef; } 472 | } 473 | 474 | # Now check the rule's to time. If the rule covers the current 475 | # year, but doesn't fire until later in the year, subtract a year. 476 | my $year = $to eq 'max' ? $current_year : $to eq 'only' ? $from : $to; 477 | event_fires_later_this_year: { 478 | if ($year < $current_year) { last; } 479 | if ($year == $current_year && $month < $current_month) { last; } 480 | my $day = on_to_day_of_month($on, $year, $month); 481 | if ($year == $current_year && $month == $current_month && $day < $current_day) { last; } 482 | # If we get here, this year's rule instance is not active until 483 | # later in the year, so subtract a year. 484 | $year -= 1; 485 | } 486 | 487 | my $day = on_to_day_of_month($on, $year, $month); 488 | return timelocal(0, 0, 0, $day, $month, $year); 489 | } 490 | 491 | -------------------------------------------------------------------------------- /include/tz_database.hrl: -------------------------------------------------------------------------------- 1 | %% @author Dmitry S. Melnikov (dmitryme@gmail.com) 2 | %% @copyright 2010 Dmitry S. Melnikov 3 | 4 | -author("Dmitry Melnikov "). 5 | 6 | % {TimeZoneName, {StdAbbr, StdName}, {DstAbbr, DstName}, StdMin, DstMin, DstStartDay, DstStartTime, DstEndDay, DstEndTime} 7 | % TimeZoneName = String(), TimeZone name, MUST be unique. It is a key 8 | % StdName = {String(), String()}, name and abbreviations of timezone before daylight shift 9 | % DstName = {String(), String()}, name and abbreviations of timezone after daylight shift 10 | % StdMin = Integer(), GMT offset in minutes. W/o daylight savings 11 | % DstMin = Integer(), daylight saving. Adjustment for GMT offset, when daylight saving is on 12 | % DstStartDay = {NthWeekday, Weekday, Month}, daylight saving transition rule. Can be undef if no daylight saving rule specified 13 | % NthWeekday = Integer() | 'last', 1(first week),2(second week),3(...),4(...),5(...),'last'(last week) 14 | % Weekday = atom(), sun,mon,tue,wed,thu,fri,sat 15 | % Month = atom(), jan,deb,mar,apr,may,jun,jul,aug,sep,oct,mov,dec 16 | % DstStartTime = {Hour, Min} - time of daylight saving transition 17 | % Hour = Integer(), [0..23] 18 | % Min = Integer(), [0..59] 19 | % DstEndDay = {NthWeekday, Weekday, Month} - transition back to std. Can be undef if no daylight saving rule specified 20 | % {Hour, Min} - time of transition to std. 21 | % } 22 | 23 | -define(tz_database, 24 | [ 25 | %% Automatically generated from the time zone database version 2013i for 2014-01-09. 26 | 27 | %% Problems: 28 | %% Ignored Jun 29 in Rule Morocco. 29 | %% Ignored Jul 29 in Rule Morocco. 30 | %% Rounded Apr Sun>=23 to [4 sun apr] in Rule ChileAQ. 31 | %% Rounded Sep Sun>=2 to [1 sun sep] in Rule ChileAQ. 32 | %% Ignored Mar 22 in Rule Iran. 33 | %% Ignored Sep 22 in Rule Iran. 34 | %% Rounded Mar Fri>=23 to [4 fri mar] in Rule Zion. 35 | %% Rounded Sep Fri>=21 to [4 fri sep] in Rule Palestine. 36 | %% Rounded Oct Sun>=21 to [4 sun oct] in Rule Fiji. 37 | %% Rounded Jan Sun>=18 to [3 sun jan] in Rule Fiji. 38 | %% Rounded Apr Sun>=23 to [4 sun apr] in Rule Chile. 39 | %% Rounded Sep Sun>=2 to [1 sun sep] in Rule Chile. 40 | %% Discarded excess rules for Zone Africa/Casablanca. 41 | %% Discarded excess rules for Zone Africa/El_Aaiun. 42 | %% Moving rule to beginning of day for Zone America/Godthab. 43 | %% Moving rule to beginning of day for Zone America/Godthab. 44 | %% Moving rule to beginning of day for Zone Pacific/Easter. 45 | %% Moving rule to beginning of day for Zone Pacific/Easter. 46 | 47 | {"Africa/Abidjan",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 48 | {"Africa/Accra",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 49 | {"Africa/Addis_Ababa",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 50 | {"Africa/Algiers",{"CET","CET"},undef,60,0,undef,{0,0},undef,{0,0}}, 51 | {"Africa/Asmara",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 52 | {"Africa/Asmera",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 53 | {"Africa/Bamako",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 54 | {"Africa/Bangui",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 55 | {"Africa/Banjul",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 56 | {"Africa/Bissau",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 57 | {"Africa/Blantyre",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 58 | {"Africa/Brazzaville",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 59 | {"Africa/Bujumbura",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 60 | {"Africa/Cairo",{"EET","EET"},undef,120,0,undef,{0,0},undef,{0,0}}, 61 | {"Africa/Casablanca",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 62 | {"Africa/Ceuta",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 63 | {"Africa/Conakry",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 64 | {"Africa/Dakar",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 65 | {"Africa/Dar_es_Salaam",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 66 | {"Africa/Djibouti",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 67 | {"Africa/Douala",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 68 | {"Africa/El_Aaiun",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 69 | {"Africa/Freetown",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 70 | {"Africa/Gaborone",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 71 | {"Africa/Harare",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 72 | {"Africa/Johannesburg",{"SAST","SAST"},undef,120,0,undef,{0,0},undef,{0,0}}, 73 | {"Africa/Juba",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 74 | {"Africa/Kampala",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 75 | {"Africa/Khartoum",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 76 | {"Africa/Kigali",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 77 | {"Africa/Kinshasa",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 78 | {"Africa/Lagos",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 79 | {"Africa/Libreville",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 80 | {"Africa/Lome",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 81 | {"Africa/Luanda",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 82 | {"Africa/Lubumbashi",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 83 | {"Africa/Lusaka",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 84 | {"Africa/Malabo",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 85 | {"Africa/Maputo",{"CAT","CAT"},undef,120,0,undef,{0,0},undef,{0,0}}, 86 | {"Africa/Maseru",{"SAST","SAST"},undef,120,0,undef,{0,0},undef,{0,0}}, 87 | {"Africa/Mbabane",{"SAST","SAST"},undef,120,0,undef,{0,0},undef,{0,0}}, 88 | {"Africa/Mogadishu",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 89 | {"Africa/Monrovia",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 90 | {"Africa/Nairobi",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 91 | {"Africa/Ndjamena",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 92 | {"Africa/Niamey",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 93 | {"Africa/Nouakchott",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 94 | {"Africa/Ouagadougou",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 95 | {"Africa/Porto-Novo",{"WAT","WAT"},undef,60,0,undef,{0,0},undef,{0,0}}, 96 | {"Africa/Sao_Tome",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 97 | {"Africa/Timbuktu",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 98 | {"Africa/Tripoli",{"EET","EET"},undef,120,0,undef,{0,0},undef,{0,0}}, 99 | {"Africa/Tunis",{"CET","CET"},undef,60,0,undef,{0,0},undef,{0,0}}, 100 | {"Africa/Windhoek",{"WAT","WAT"},{"WAST","WAST"},60,60,{1,sun,sep},{2,0},{1,sun,apr},{2,0}}, 101 | {"America/Adak",{"HAST","HAST"},{"HADT","HADT"},-600,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 102 | {"America/Anchorage",{"AKST","AKST"},{"AKDT","AKDT"},-540,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 103 | {"America/Anguilla",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 104 | {"America/Antigua",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 105 | {"America/Araguaina",{"BRT","BRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 106 | {"America/Argentina/Buenos_Aires",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 107 | {"America/Argentina/Catamarca",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 108 | {"America/Argentina/ComodRivadavia",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 109 | {"America/Argentina/Cordoba",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 110 | {"America/Argentina/Jujuy",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 111 | {"America/Argentina/La_Rioja",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 112 | {"America/Argentina/Mendoza",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 113 | {"America/Argentina/Rio_Gallegos",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 114 | {"America/Argentina/Salta",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 115 | {"America/Argentina/San_Juan",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 116 | {"America/Argentina/San_Luis",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 117 | {"America/Argentina/Tucuman",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 118 | {"America/Argentina/Ushuaia",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 119 | {"America/Aruba",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 120 | {"America/Asuncion",{"PYT","PYT"},{"PYST","PYST"},-240,60,{1,sun,oct},{0,0},{4,sun,mar},{0,0}}, 121 | {"America/Atikokan",{"EST","EST"},undef,-300,0,undef,{0,0},undef,{0,0}}, 122 | {"America/Atka",{"HAST","HAST"},{"HADT","HADT"},-600,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 123 | {"America/Bahia",{"BRT","BRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 124 | {"America/Bahia_Banderas",{"CST","CST"},{"CDT","CDT"},-360,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 125 | {"America/Barbados",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 126 | {"America/Belem",{"BRT","BRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 127 | {"America/Belize",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 128 | {"America/Blanc-Sablon",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 129 | {"America/Boa_Vista",{"AMT","AMT"},undef,-240,0,undef,{0,0},undef,{0,0}}, 130 | {"America/Bogota",{"COT","COT"},undef,-300,0,undef,{0,0},undef,{0,0}}, 131 | {"America/Boise",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 132 | {"America/Buenos_Aires",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 133 | {"America/Cambridge_Bay",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 134 | {"America/Campo_Grande",{"AMT","AMT"},{"AMST","AMST"},-240,60,{3,sun,oct},{0,0},{3,sun,feb},{0,0}}, 135 | {"America/Cancun",{"CST","CST"},{"CDT","CDT"},-360,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 136 | {"America/Caracas",{"VET","VET"},undef,-270,0,undef,{0,0},undef,{0,0}}, 137 | {"America/Catamarca",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 138 | {"America/Cayenne",{"GFT","GFT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 139 | {"America/Cayman",{"EST","EST"},undef,-300,0,undef,{0,0},undef,{0,0}}, 140 | {"America/Chicago",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 141 | {"America/Chihuahua",{"MST","MST"},{"MDT","MDT"},-420,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 142 | {"America/Coral_Harbour",{"EST","EST"},undef,-300,0,undef,{0,0},undef,{0,0}}, 143 | {"America/Cordoba",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 144 | {"America/Costa_Rica",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 145 | {"America/Creston",{"MST","MST"},undef,-420,0,undef,{0,0},undef,{0,0}}, 146 | {"America/Cuiaba",{"AMT","AMT"},{"AMST","AMST"},-240,60,{3,sun,oct},{0,0},{3,sun,feb},{0,0}}, 147 | {"America/Curacao",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 148 | {"America/Danmarkshavn",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 149 | {"America/Dawson",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 150 | {"America/Dawson_Creek",{"MST","MST"},undef,-420,0,undef,{0,0},undef,{0,0}}, 151 | {"America/Denver",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 152 | {"America/Detroit",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 153 | {"America/Dominica",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 154 | {"America/Edmonton",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 155 | {"America/Eirunepe",{"ACT","ACT"},undef,-300,0,undef,{0,0},undef,{0,0}}, 156 | {"America/El_Salvador",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 157 | {"America/Ensenada",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 158 | {"America/Fort_Wayne",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 159 | {"America/Fortaleza",{"BRT","BRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 160 | {"America/Glace_Bay",{"AST","AST"},{"ADT","ADT"},-240,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 161 | {"America/Godthab",{"WGT","WGT"},{"WGST","WGST"},-180,60,{last,sun,mar},{0,0},{last,sun,oct},{0,0}}, 162 | {"America/Goose_Bay",{"AST","AST"},{"ADT","ADT"},-240,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 163 | {"America/Grand_Turk",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 164 | {"America/Grenada",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 165 | {"America/Guadeloupe",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 166 | {"America/Guatemala",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 167 | {"America/Guayaquil",{"ECT","ECT"},undef,-300,0,undef,{0,0},undef,{0,0}}, 168 | {"America/Guyana",{"GYT","GYT"},undef,-240,0,undef,{0,0},undef,{0,0}}, 169 | {"America/Halifax",{"AST","AST"},{"ADT","ADT"},-240,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 170 | {"America/Havana",{"CST","CST"},{"CDT","CDT"},-300,60,{2,sun,mar},{0,0},{1,sun,nov},{1,0}}, 171 | {"America/Hermosillo",{"MST","MST"},undef,-420,0,undef,{0,0},undef,{0,0}}, 172 | {"America/Indiana/Indianapolis",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 173 | {"America/Indiana/Knox",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 174 | {"America/Indiana/Marengo",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 175 | {"America/Indiana/Petersburg",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 176 | {"America/Indiana/Tell_City",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 177 | {"America/Indiana/Vevay",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 178 | {"America/Indiana/Vincennes",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 179 | {"America/Indiana/Winamac",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 180 | {"America/Indianapolis",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 181 | {"America/Inuvik",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 182 | {"America/Iqaluit",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 183 | {"America/Jamaica",{"EST","EST"},undef,-300,0,undef,{0,0},undef,{0,0}}, 184 | {"America/Jujuy",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 185 | {"America/Juneau",{"AKST","AKST"},{"AKDT","AKDT"},-540,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 186 | {"America/Kentucky/Louisville",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 187 | {"America/Kentucky/Monticello",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 188 | {"America/Knox_IN",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 189 | {"America/Kralendijk",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 190 | {"America/La_Paz",{"BOT","BOT"},undef,-240,0,undef,{0,0},undef,{0,0}}, 191 | {"America/Lima",{"PET","PET"},undef,-300,0,undef,{0,0},undef,{0,0}}, 192 | {"America/Los_Angeles",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 193 | {"America/Louisville",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 194 | {"America/Lower_Princes",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 195 | {"America/Maceio",{"BRT","BRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 196 | {"America/Managua",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 197 | {"America/Manaus",{"AMT","AMT"},undef,-240,0,undef,{0,0},undef,{0,0}}, 198 | {"America/Marigot",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 199 | {"America/Martinique",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 200 | {"America/Matamoros",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 201 | {"America/Mazatlan",{"MST","MST"},{"MDT","MDT"},-420,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 202 | {"America/Mendoza",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 203 | {"America/Menominee",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 204 | {"America/Merida",{"CST","CST"},{"CDT","CDT"},-360,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 205 | {"America/Metlakatla",{"MeST","MeST"},undef,-480,0,undef,{0,0},undef,{0,0}}, 206 | {"America/Mexico_City",{"CST","CST"},{"CDT","CDT"},-360,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 207 | {"America/Miquelon",{"PMST","PMST"},{"PMDT","PMDT"},-180,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 208 | {"America/Moncton",{"AST","AST"},{"ADT","ADT"},-240,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 209 | {"America/Monterrey",{"CST","CST"},{"CDT","CDT"},-360,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 210 | {"America/Montevideo",{"UYT","UYT"},{"UYST","UYST"},-180,60,{1,sun,oct},{2,0},{2,sun,mar},{2,0}}, 211 | {"America/Montreal",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 212 | {"America/Montserrat",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 213 | {"America/Nassau",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 214 | {"America/New_York",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 215 | {"America/Nipigon",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 216 | {"America/Nome",{"AKST","AKST"},{"AKDT","AKDT"},-540,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 217 | {"America/Noronha",{"FNT","FNT"},undef,-120,0,undef,{0,0},undef,{0,0}}, 218 | {"America/North_Dakota/Beulah",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 219 | {"America/North_Dakota/Center",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 220 | {"America/North_Dakota/New_Salem",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 221 | {"America/Ojinaga",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 222 | {"America/Panama",{"EST","EST"},undef,-300,0,undef,{0,0},undef,{0,0}}, 223 | {"America/Pangnirtung",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 224 | {"America/Paramaribo",{"SRT","SRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 225 | {"America/Phoenix",{"MST","MST"},undef,-420,0,undef,{0,0},undef,{0,0}}, 226 | {"America/Port-au-Prince",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 227 | {"America/Port_of_Spain",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 228 | {"America/Porto_Acre",{"ACT","ACT"},undef,-300,0,undef,{0,0},undef,{0,0}}, 229 | {"America/Porto_Velho",{"AMT","AMT"},undef,-240,0,undef,{0,0},undef,{0,0}}, 230 | {"America/Puerto_Rico",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 231 | {"America/Rainy_River",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 232 | {"America/Rankin_Inlet",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 233 | {"America/Recife",{"BRT","BRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 234 | {"America/Regina",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 235 | {"America/Resolute",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 236 | {"America/Rio_Branco",{"ACT","ACT"},undef,-300,0,undef,{0,0},undef,{0,0}}, 237 | {"America/Rosario",{"ART","ART"},undef,-180,0,undef,{0,0},undef,{0,0}}, 238 | {"America/Santa_Isabel",{"PST","PST"},{"PDT","PDT"},-480,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 239 | {"America/Santarem",{"BRT","BRT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 240 | {"America/Santiago",{"CLT","CLT"},{"CLST","CLST"},-240,60,{1,sun,sep},{0,0},{4,sun,apr},{0,0}}, 241 | {"America/Santo_Domingo",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 242 | {"America/Sao_Paulo",{"BRT","BRT"},{"BRST","BRST"},-180,60,{3,sun,oct},{0,0},{3,sun,feb},{0,0}}, 243 | {"America/Scoresbysund",{"EGT","EGT"},{"EGST","EGST"},-60,60,{last,sun,mar},{0,0},{last,sun,oct},{1,0}}, 244 | {"America/Shiprock",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 245 | {"America/Sitka",{"AKST","AKST"},{"AKDT","AKDT"},-540,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 246 | {"America/St_Barthelemy",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 247 | {"America/St_Johns",{"NST","NST"},{"NDT","NDT"},-210,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 248 | {"America/St_Kitts",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 249 | {"America/St_Lucia",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 250 | {"America/St_Thomas",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 251 | {"America/St_Vincent",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 252 | {"America/Swift_Current",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 253 | {"America/Tegucigalpa",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 254 | {"America/Thule",{"AST","AST"},{"ADT","ADT"},-240,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 255 | {"America/Thunder_Bay",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 256 | {"America/Tijuana",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 257 | {"America/Toronto",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 258 | {"America/Tortola",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 259 | {"America/Vancouver",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 260 | {"America/Virgin",{"AST","AST"},undef,-240,0,undef,{0,0},undef,{0,0}}, 261 | {"America/Whitehorse",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 262 | {"America/Winnipeg",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 263 | {"America/Yakutat",{"AKST","AKST"},{"AKDT","AKDT"},-540,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 264 | {"America/Yellowknife",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 265 | {"Antarctica/Casey",{"WST","WST"},undef,480,0,undef,{0,0},undef,{0,0}}, 266 | {"Antarctica/Davis",{"DAVT","DAVT"},undef,420,0,undef,{0,0},undef,{0,0}}, 267 | {"Antarctica/DumontDUrville",{"DDUT","DDUT"},undef,600,0,undef,{0,0},undef,{0,0}}, 268 | {"Antarctica/Macquarie",{"MIST","MIST"},undef,660,0,undef,{0,0},undef,{0,0}}, 269 | {"Antarctica/Mawson",{"MAWT","MAWT"},undef,300,0,undef,{0,0},undef,{0,0}}, 270 | {"Antarctica/McMurdo",{"NZST","NZST"},{"NZDT","NZDT"},720,60,{last,sun,sep},{2,0},{1,sun,apr},{3,0}}, 271 | {"Antarctica/Palmer",{"CLT","CLT"},{"CLST","CLST"},-240,60,{1,sun,sep},{0,0},{4,sun,apr},{0,0}}, 272 | {"Antarctica/Rothera",{"ROTT","ROTT"},undef,-180,0,undef,{0,0},undef,{0,0}}, 273 | {"Antarctica/South_Pole",{"NZST","NZST"},{"NZDT","NZDT"},720,60,{last,sun,sep},{2,0},{1,sun,apr},{3,0}}, 274 | {"Antarctica/Syowa",{"SYOT","SYOT"},undef,180,0,undef,{0,0},undef,{0,0}}, 275 | {"Antarctica/Vostok",{"VOST","VOST"},undef,360,0,undef,{0,0},undef,{0,0}}, 276 | {"Arctic/Longyearbyen",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 277 | {"Asia/Aden",{"AST","AST"},undef,180,0,undef,{0,0},undef,{0,0}}, 278 | {"Asia/Almaty",{"ALMT","ALMT"},undef,360,0,undef,{0,0},undef,{0,0}}, 279 | {"Asia/Amman",{"EET","EET"},{"EEST","EEST"},120,60,{last,thu,mar},{24,0},{last,fri,oct},{1,0}}, 280 | {"Asia/Anadyr",{"ANAT","ANAT"},undef,720,0,undef,{0,0},undef,{0,0}}, 281 | {"Asia/Aqtau",{"AQTT","AQTT"},undef,300,0,undef,{0,0},undef,{0,0}}, 282 | {"Asia/Aqtobe",{"AQTT","AQTT"},undef,300,0,undef,{0,0},undef,{0,0}}, 283 | {"Asia/Ashgabat",{"TMT","TMT"},undef,300,0,undef,{0,0},undef,{0,0}}, 284 | {"Asia/Ashkhabad",{"TMT","TMT"},undef,300,0,undef,{0,0},undef,{0,0}}, 285 | {"Asia/Baghdad",{"AST","AST"},undef,180,0,undef,{0,0},undef,{0,0}}, 286 | {"Asia/Bahrain",{"AST","AST"},undef,180,0,undef,{0,0},undef,{0,0}}, 287 | {"Asia/Baku",{"AZT","AZT"},{"AZST","AZST"},240,60,{last,sun,mar},{4,0},{last,sun,oct},{5,0}}, 288 | {"Asia/Bangkok",{"ICT","ICT"},undef,420,0,undef,{0,0},undef,{0,0}}, 289 | {"Asia/Beirut",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{0,0},{last,sun,oct},{0,0}}, 290 | {"Asia/Bishkek",{"KGT","KGT"},undef,360,0,undef,{0,0},undef,{0,0}}, 291 | {"Asia/Brunei",{"BNT","BNT"},undef,480,0,undef,{0,0},undef,{0,0}}, 292 | {"Asia/Calcutta",{"IST","IST"},undef,330,0,undef,{0,0},undef,{0,0}}, 293 | {"Asia/Chita",{"IRKT","IRKT"},undef,480,0,undef,{0,0},undef,{0,0}}, 294 | {"Asia/Choibalsan",{"CHOT","CHOT"},undef,480,0,undef,{0,0},undef,{0,0}}, 295 | {"Asia/Chongqing",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 296 | {"Asia/Chungking",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 297 | {"Asia/Colombo",{"IST","IST"},undef,330,0,undef,{0,0},undef,{0,0}}, 298 | {"Asia/Dacca",{"BDT","BDT"},undef,360,0,undef,{0,0},undef,{0,0}}, 299 | {"Asia/Damascus",{"EET","EET"},{"EEST","EEST"},120,60,{last,fri,mar},{0,0},{last,fri,oct},{0,0}}, 300 | {"Asia/Dhaka",{"BDT","BDT"},undef,360,0,undef,{0,0},undef,{0,0}}, 301 | {"Asia/Dili",{"TLT","TLT"},undef,540,0,undef,{0,0},undef,{0,0}}, 302 | {"Asia/Dubai",{"GST","GST"},undef,240,0,undef,{0,0},undef,{0,0}}, 303 | {"Asia/Dushanbe",{"TJT","TJT"},undef,300,0,undef,{0,0},undef,{0,0}}, 304 | {"Asia/Gaza",{"EET","EET"},{"EEST","EEST"},120,60,{last,thu,mar},{24,0},{4,fri,sep},{0,0}}, 305 | {"Asia/Harbin",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 306 | {"Asia/Hebron",{"EET","EET"},{"EEST","EEST"},120,60,{last,thu,mar},{24,0},{4,fri,sep},{0,0}}, 307 | {"Asia/Ho_Chi_Minh",{"ICT","ICT"},undef,420,0,undef,{0,0},undef,{0,0}}, 308 | {"Asia/Hong_Kong",{"HKT","HKT"},undef,480,0,undef,{0,0},undef,{0,0}}, 309 | {"Asia/Hovd",{"HOVT","HOVT"},undef,420,0,undef,{0,0},undef,{0,0}}, 310 | {"Asia/Irkutsk",{"IRKT","IRKT"},undef,480,0,undef,{0,0},undef,{0,0}}, 311 | {"Asia/Istanbul",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 312 | {"Asia/Jakarta",{"WIB","WIB"},undef,420,0,undef,{0,0},undef,{0,0}}, 313 | {"Asia/Jayapura",{"WIT","WIT"},undef,540,0,undef,{0,0},undef,{0,0}}, 314 | {"Asia/Jerusalem",{"IST","IST"},{"IDT","IDT"},120,60,{4,fri,mar},{2,0},{last,sun,oct},{2,0}}, 315 | {"Asia/Kabul",{"AFT","AFT"},undef,270,0,undef,{0,0},undef,{0,0}}, 316 | {"Asia/Kamchatka",{"PETT","PETT"},undef,720,0,undef,{0,0},undef,{0,0}}, 317 | {"Asia/Karachi",{"PKT","PKT"},undef,300,0,undef,{0,0},undef,{0,0}}, 318 | {"Asia/Kashgar",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 319 | {"Asia/Kathmandu",{"NPT","NPT"},undef,345,0,undef,{0,0},undef,{0,0}}, 320 | {"Asia/Katmandu",{"NPT","NPT"},undef,345,0,undef,{0,0},undef,{0,0}}, 321 | {"Asia/Khandyga",{"YAKT","YAKT"},undef,540,0,undef,{0,0},undef,{0,0}}, 322 | {"Asia/Kolkata",{"IST","IST"},undef,330,0,undef,{0,0},undef,{0,0}}, 323 | {"Asia/Krasnoyarsk",{"KRAT","KRAT"},undef,420,0,undef,{0,0},undef,{0,0}}, 324 | {"Asia/Kuala_Lumpur",{"MYT","MYT"},undef,480,0,undef,{0,0},undef,{0,0}}, 325 | {"Asia/Kuching",{"MYT","MYT"},undef,480,0,undef,{0,0},undef,{0,0}}, 326 | {"Asia/Kuwait",{"AST","AST"},undef,180,0,undef,{0,0},undef,{0,0}}, 327 | {"Asia/Macao",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 328 | {"Asia/Macau",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 329 | {"Asia/Magadan",{"MAGT","MAGT"},undef,600,0,undef,{0,0},undef,{0,0}}, 330 | {"Asia/Makassar",{"WITA","WITA"},undef,480,0,undef,{0,0},undef,{0,0}}, 331 | {"Asia/Manila",{"PHT","PHT"},undef,480,0,undef,{0,0},undef,{0,0}}, 332 | {"Asia/Muscat",{"GST","GST"},undef,240,0,undef,{0,0},undef,{0,0}}, 333 | {"Asia/Nicosia",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 334 | {"Asia/Novokuznetsk",{"KRAT","KRAT"},undef,420,0,undef,{0,0},undef,{0,0}}, 335 | {"Asia/Novosibirsk",{"NOVT","NOVT"},undef,360,0,undef,{0,0},undef,{0,0}}, 336 | {"Asia/Omsk",{"OMST","OMST"},undef,360,0,undef,{0,0},undef,{0,0}}, 337 | {"Asia/Oral",{"ORAT","ORAT"},undef,300,0,undef,{0,0},undef,{0,0}}, 338 | {"Asia/Phnom_Penh",{"ICT","ICT"},undef,420,0,undef,{0,0},undef,{0,0}}, 339 | {"Asia/Pontianak",{"WIB","WIB"},undef,420,0,undef,{0,0},undef,{0,0}}, 340 | {"Asia/Pyongyang",{"KST","KST"},undef,540,0,undef,{0,0},undef,{0,0}}, 341 | {"Asia/Qatar",{"AST","AST"},undef,180,0,undef,{0,0},undef,{0,0}}, 342 | {"Asia/Qyzylorda",{"QYZT","QYZT"},undef,360,0,undef,{0,0},undef,{0,0}}, 343 | {"Asia/Rangoon",{"MMT","MMT"},undef,390,0,undef,{0,0},undef,{0,0}}, 344 | {"Asia/Riyadh",{"AST","AST"},undef,180,0,undef,{0,0},undef,{0,0}}, 345 | {"Asia/Saigon",{"ICT","ICT"},undef,420,0,undef,{0,0},undef,{0,0}}, 346 | {"Asia/Sakhalin",{"SAKT","SAKT"},undef,600,0,undef,{0,0},undef,{0,0}}, 347 | {"Asia/Samarkand",{"UZT","UZT"},undef,300,0,undef,{0,0},undef,{0,0}}, 348 | {"Asia/Seoul",{"KST","KST"},undef,540,0,undef,{0,0},undef,{0,0}}, 349 | {"Asia/Shanghai",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 350 | {"Asia/Singapore",{"SGT","SGT"},undef,480,0,undef,{0,0},undef,{0,0}}, 351 | {"Asia/Srednekolymsk",{"SRET","SRET"},undef,660,0,undef,{0,0},undef,{0,0}}, 352 | {"Asia/Taipei",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 353 | {"Asia/Tashkent",{"UZT","UZT"},undef,300,0,undef,{0,0},undef,{0,0}}, 354 | {"Asia/Tbilisi",{"GET","GET"},undef,240,0,undef,{0,0},undef,{0,0}}, 355 | {"Asia/Tehran",{"IRST","IRST"},{"IRDT","IRDT"},210,60,undef,{0,0},undef,{0,0}}, 356 | {"Asia/Tel_Aviv",{"IST","IST"},{"IDT","IDT"},120,60,{4,fri,mar},{2,0},{last,sun,oct},{2,0}}, 357 | {"Asia/Thimbu",{"BTT","BTT"},undef,360,0,undef,{0,0},undef,{0,0}}, 358 | {"Asia/Thimphu",{"BTT","BTT"},undef,360,0,undef,{0,0},undef,{0,0}}, 359 | {"Asia/Tokyo",{"JST","JST"},undef,540,0,undef,{0,0},undef,{0,0}}, 360 | {"Asia/Ujung_Pandang",{"WITA","WITA"},undef,480,0,undef,{0,0},undef,{0,0}}, 361 | {"Asia/Ulaanbaatar",{"ULAT","ULAT"},undef,480,0,undef,{0,0},undef,{0,0}}, 362 | {"Asia/Ulan_Bator",{"ULAT","ULAT"},undef,480,0,undef,{0,0},undef,{0,0}}, 363 | {"Asia/Urumqi",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 364 | {"Asia/Ust-Nera",{"VLAT","VLAT"},undef,600,0,undef,{0,0},undef,{0,0}}, 365 | {"Asia/Vientiane",{"ICT","ICT"},undef,420,0,undef,{0,0},undef,{0,0}}, 366 | {"Asia/Vladivostok",{"VLAT","VLAT"},undef,600,0,undef,{0,0},undef,{0,0}}, 367 | {"Asia/Yakutsk",{"YAKT","YAKT"},undef,540,0,undef,{0,0},undef,{0,0}}, 368 | {"Asia/Yekaterinburg",{"YEKT","YEKT"},undef,300,0,undef,{0,0},undef,{0,0}}, 369 | {"Asia/Yerevan",{"AMT","AMT"},undef,240,0,undef,{0,0},undef,{0,0}}, 370 | {"Atlantic/Azores",{"AZOT","AZOT"},{"AZOST","AZOST"},-60,60,{last,sun,mar},{0,0},{last,sun,oct},{1,0}}, 371 | {"Atlantic/Bermuda",{"AST","AST"},{"ADT","ADT"},-240,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 372 | {"Atlantic/Canary",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 373 | {"Atlantic/Cape_Verde",{"CVT","CVT"},undef,-60,0,undef,{0,0},undef,{0,0}}, 374 | {"Atlantic/Faeroe",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 375 | {"Atlantic/Faroe",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 376 | {"Atlantic/Jan_Mayen",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 377 | {"Atlantic/Madeira",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 378 | {"Atlantic/Reykjavik",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 379 | {"Atlantic/South_Georgia",{"GST","GST"},undef,-120,0,undef,{0,0},undef,{0,0}}, 380 | {"Atlantic/St_Helena",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 381 | {"Atlantic/Stanley",{"FKST","FKST"},undef,-180,0,undef,{0,0},undef,{0,0}}, 382 | {"Australia/ACT",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 383 | {"Australia/Adelaide",{"CST","CST"},{"CST","CST"},570,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 384 | {"Australia/Brisbane",{"EST","EST"},undef,600,0,undef,{0,0},undef,{0,0}}, 385 | {"Australia/Broken_Hill",{"CST","CST"},{"CST","CST"},570,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 386 | {"Australia/Canberra",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 387 | {"Australia/Currie",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 388 | {"Australia/Darwin",{"CST","CST"},undef,570,0,undef,{0,0},undef,{0,0}}, 389 | {"Australia/Eucla",{"CWST","CWST"},undef,525,0,undef,{0,0},undef,{0,0}}, 390 | {"Australia/Hobart",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 391 | {"Australia/LHI",{"LHST","LHST"},{"LHST","LHST"},630,30,{1,sun,oct},{2,0},{1,sun,apr},{2,0}}, 392 | {"Australia/Lindeman",{"EST","EST"},undef,600,0,undef,{0,0},undef,{0,0}}, 393 | {"Australia/Lord_Howe",{"LHST","LHST"},{"LHST","LHST"},630,30,{1,sun,oct},{2,0},{1,sun,apr},{2,0}}, 394 | {"Australia/Melbourne",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 395 | {"Australia/NSW",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 396 | {"Australia/North",{"CST","CST"},undef,570,0,undef,{0,0},undef,{0,0}}, 397 | {"Australia/Perth",{"WST","WST"},undef,480,0,undef,{0,0},undef,{0,0}}, 398 | {"Australia/Queensland",{"EST","EST"},undef,600,0,undef,{0,0},undef,{0,0}}, 399 | {"Australia/South",{"CST","CST"},{"CST","CST"},570,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 400 | {"Australia/Sydney",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 401 | {"Australia/Tasmania",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 402 | {"Australia/Victoria",{"EST","EST"},{"EST","EST"},600,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 403 | {"Australia/West",{"WST","WST"},undef,480,0,undef,{0,0},undef,{0,0}}, 404 | {"Australia/Yancowinna",{"CST","CST"},{"CST","CST"},570,60,{1,sun,oct},{2,0},{1,sun,apr},{3,0}}, 405 | {"Brazil/Acre",{"ACT","ACT"},undef,-300,0,undef,{0,0},undef,{0,0}}, 406 | {"Brazil/DeNoronha",{"FNT","FNT"},undef,-120,0,undef,{0,0},undef,{0,0}}, 407 | {"Brazil/East",{"BRT","BRT"},{"BRST","BRST"},-180,60,{3,sun,oct},{0,0},{3,sun,feb},{0,0}}, 408 | {"Brazil/West",{"AMT","AMT"},undef,-240,0,undef,{0,0},undef,{0,0}}, 409 | {"CET",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 410 | {"CST6CDT",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 411 | {"Canada/Atlantic",{"AST","AST"},{"ADT","ADT"},-240,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 412 | {"Canada/Central",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 413 | {"Canada/East-Saskatchewan",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 414 | {"Canada/Eastern",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 415 | {"Canada/Mountain",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 416 | {"Canada/Newfoundland",{"NST","NST"},{"NDT","NDT"},-210,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 417 | {"Canada/Pacific",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 418 | {"Canada/Saskatchewan",{"CST","CST"},undef,-360,0,undef,{0,0},undef,{0,0}}, 419 | {"Canada/Yukon",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 420 | {"Chile/Continental",{"CLT","CLT"},{"CLST","CLST"},-240,60,{1,sun,sep},{0,0},{4,sun,apr},{0,0}}, 421 | {"Chile/EasterIsland",{"EAST","EAST"},{"EASST","EASST"},-360,60,{1,sun,sep},{0,0},{4,sun,apr},{0,0}}, 422 | {"Cuba",{"CST","CST"},{"CDT","CDT"},-300,60,{2,sun,mar},{0,0},{1,sun,nov},{1,0}}, 423 | {"EET",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 424 | {"EST",{"EST","EST"},undef,-300,0,undef,{0,0},undef,{0,0}}, 425 | {"EST5EDT",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 426 | {"Egypt",{"EET","EET"},undef,120,0,undef,{0,0},undef,{0,0}}, 427 | {"Eire",{"GMT","GMT"},{"IST","IST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 428 | {"Etc/GMT",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 429 | {"Etc/GMT+0",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 430 | {"Etc/GMT+1",{"GMT+1","GMT+1"},undef,-1,0,undef,{0,0},undef,{0,0}}, 431 | {"Etc/GMT+10",{"GMT+10","GMT+10"},undef,-10,0,undef,{0,0},undef,{0,0}}, 432 | {"Etc/GMT+11",{"GMT+11","GMT+11"},undef,-11,0,undef,{0,0},undef,{0,0}}, 433 | {"Etc/GMT+12",{"GMT+12","GMT+12"},undef,-12,0,undef,{0,0},undef,{0,0}}, 434 | {"Etc/GMT+2",{"GMT+2","GMT+2"},undef,-2,0,undef,{0,0},undef,{0,0}}, 435 | {"Etc/GMT+3",{"GMT+3","GMT+3"},undef,-3,0,undef,{0,0},undef,{0,0}}, 436 | {"Etc/GMT+4",{"GMT+4","GMT+4"},undef,-4,0,undef,{0,0},undef,{0,0}}, 437 | {"Etc/GMT+5",{"GMT+5","GMT+5"},undef,-5,0,undef,{0,0},undef,{0,0}}, 438 | {"Etc/GMT+6",{"GMT+6","GMT+6"},undef,-6,0,undef,{0,0},undef,{0,0}}, 439 | {"Etc/GMT+7",{"GMT+7","GMT+7"},undef,-7,0,undef,{0,0},undef,{0,0}}, 440 | {"Etc/GMT+8",{"GMT+8","GMT+8"},undef,-8,0,undef,{0,0},undef,{0,0}}, 441 | {"Etc/GMT+9",{"GMT+9","GMT+9"},undef,-9,0,undef,{0,0},undef,{0,0}}, 442 | {"Etc/GMT-0",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 443 | {"Etc/GMT-1",{"GMT-1","GMT-1"},undef,1,0,undef,{0,0},undef,{0,0}}, 444 | {"Etc/GMT-10",{"GMT-10","GMT-10"},undef,10,0,undef,{0,0},undef,{0,0}}, 445 | {"Etc/GMT-11",{"GMT-11","GMT-11"},undef,11,0,undef,{0,0},undef,{0,0}}, 446 | {"Etc/GMT-12",{"GMT-12","GMT-12"},undef,12,0,undef,{0,0},undef,{0,0}}, 447 | {"Etc/GMT-13",{"GMT-13","GMT-13"},undef,13,0,undef,{0,0},undef,{0,0}}, 448 | {"Etc/GMT-14",{"GMT-14","GMT-14"},undef,14,0,undef,{0,0},undef,{0,0}}, 449 | {"Etc/GMT-2",{"GMT-2","GMT-2"},undef,2,0,undef,{0,0},undef,{0,0}}, 450 | {"Etc/GMT-3",{"GMT-3","GMT-3"},undef,3,0,undef,{0,0},undef,{0,0}}, 451 | {"Etc/GMT-4",{"GMT-4","GMT-4"},undef,4,0,undef,{0,0},undef,{0,0}}, 452 | {"Etc/GMT-5",{"GMT-5","GMT-5"},undef,5,0,undef,{0,0},undef,{0,0}}, 453 | {"Etc/GMT-6",{"GMT-6","GMT-6"},undef,6,0,undef,{0,0},undef,{0,0}}, 454 | {"Etc/GMT-7",{"GMT-7","GMT-7"},undef,7,0,undef,{0,0},undef,{0,0}}, 455 | {"Etc/GMT-8",{"GMT-8","GMT-8"},undef,8,0,undef,{0,0},undef,{0,0}}, 456 | {"Etc/GMT-9",{"GMT-9","GMT-9"},undef,9,0,undef,{0,0},undef,{0,0}}, 457 | {"Etc/GMT0",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 458 | {"Etc/Greenwich",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 459 | {"Etc/UCT",{"UCT","UCT"},undef,0,0,undef,{0,0},undef,{0,0}}, 460 | {"Etc/UTC",{"UTC","UTC"},undef,0,0,undef,{0,0},undef,{0,0}}, 461 | {"Etc/Universal",{"UTC","UTC"},undef,0,0,undef,{0,0},undef,{0,0}}, 462 | {"Etc/Zulu",{"UTC","UTC"},undef,0,0,undef,{0,0},undef,{0,0}}, 463 | {"Europe/Amsterdam",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 464 | {"Europe/Andorra",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 465 | {"Europe/Athens",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 466 | {"Europe/Belfast",{"GMT","GMT"},{"BST","BST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 467 | {"Europe/Belgrade",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 468 | {"Europe/Berlin",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 469 | {"Europe/Bratislava",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 470 | {"Europe/Brussels",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 471 | {"Europe/Bucharest",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 472 | {"Europe/Budapest",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 473 | {"Europe/Busingen",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 474 | {"Europe/Chisinau",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 475 | {"Europe/Copenhagen",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 476 | {"Europe/Dublin",{"GMT","GMT"},{"IST","IST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 477 | {"Europe/Gibraltar",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 478 | {"Europe/Guernsey",{"GMT","GMT"},{"BST","BST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 479 | {"Europe/Helsinki",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 480 | {"Europe/Isle_of_Man",{"GMT","GMT"},{"BST","BST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 481 | {"Europe/Istanbul",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 482 | {"Europe/Jersey",{"GMT","GMT"},{"BST","BST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 483 | {"Europe/Kaliningrad",{"EET","EET"},undef,120,0,undef,{0,0},undef,{0,0}}, 484 | {"Europe/Kiev",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 485 | {"Europe/Lisbon",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 486 | {"Europe/Ljubljana",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 487 | {"Europe/London",{"GMT","GMT"},{"BST","BST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 488 | {"Europe/Luxembourg",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 489 | {"Europe/Madrid",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 490 | {"Europe/Malta",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 491 | {"Europe/Mariehamn",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 492 | {"Europe/Minsk",{"FET","FET"},undef,180,0,undef,{0,0},undef,{0,0}}, 493 | {"Europe/Monaco",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 494 | {"Europe/Moscow",{"MSK","MSK"},undef,180,0,undef,{0,0},undef,{0,0}}, 495 | {"Europe/Nicosia",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 496 | {"Europe/Oslo",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 497 | {"Europe/Paris",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 498 | {"Europe/Podgorica",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 499 | {"Europe/Prague",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 500 | {"Europe/Riga",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 501 | {"Europe/Rome",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 502 | {"Europe/Samara",{"SAMT","SAMT"},undef,240,0,undef,{0,0},undef,{0,0}}, 503 | {"Europe/San_Marino",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 504 | {"Europe/Sarajevo",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 505 | {"Europe/Simferopol",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 506 | {"Europe/Skopje",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 507 | {"Europe/Sofia",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 508 | {"Europe/Stockholm",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 509 | {"Europe/Tallinn",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 510 | {"Europe/Tirane",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 511 | {"Europe/Tiraspol",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 512 | {"Europe/Uzhgorod",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 513 | {"Europe/Vaduz",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 514 | {"Europe/Vatican",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 515 | {"Europe/Vienna",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 516 | {"Europe/Vilnius",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 517 | {"Europe/Volgograd",{"MSK","MSK"},undef,180,0,undef,{0,0},undef,{0,0}}, 518 | {"Europe/Warsaw",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 519 | {"Europe/Zagreb",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 520 | {"Europe/Zaporozhye",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 521 | {"Europe/Zurich",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 522 | {"GB",{"GMT","GMT"},{"BST","BST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 523 | {"GB-Eire",{"GMT","GMT"},{"BST","BST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 524 | {"GMT",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 525 | {"GMT+0",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 526 | {"GMT-0",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 527 | {"GMT0",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 528 | {"Greenwich",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 529 | {"HST",{"HST","HST"},undef,-600,0,undef,{0,0},undef,{0,0}}, 530 | {"Hongkong",{"HKT","HKT"},undef,480,0,undef,{0,0},undef,{0,0}}, 531 | {"Iceland",{"GMT","GMT"},undef,0,0,undef,{0,0},undef,{0,0}}, 532 | {"Indian/Antananarivo",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 533 | {"Indian/Chagos",{"IOT","IOT"},undef,360,0,undef,{0,0},undef,{0,0}}, 534 | {"Indian/Christmas",{"CXT","CXT"},undef,420,0,undef,{0,0},undef,{0,0}}, 535 | {"Indian/Cocos",{"CCT","CCT"},undef,390,0,undef,{0,0},undef,{0,0}}, 536 | {"Indian/Comoro",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 537 | {"Indian/Kerguelen",{"TFT","TFT"},undef,300,0,undef,{0,0},undef,{0,0}}, 538 | {"Indian/Mahe",{"SCT","SCT"},undef,240,0,undef,{0,0},undef,{0,0}}, 539 | {"Indian/Maldives",{"MVT","MVT"},undef,300,0,undef,{0,0},undef,{0,0}}, 540 | {"Indian/Mauritius",{"MUT","MUT"},undef,240,0,undef,{0,0},undef,{0,0}}, 541 | {"Indian/Mayotte",{"EAT","EAT"},undef,180,0,undef,{0,0},undef,{0,0}}, 542 | {"Indian/Reunion",{"RET","RET"},undef,240,0,undef,{0,0},undef,{0,0}}, 543 | {"Iran",{"IRST","IRST"},{"IRDT","IRDT"},210,60,undef,{0,0},undef,{0,0}}, 544 | {"Israel",{"IST","IST"},{"IDT","IDT"},120,60,{4,fri,mar},{2,0},{last,sun,oct},{2,0}}, 545 | {"Jamaica",{"EST","EST"},undef,-300,0,undef,{0,0},undef,{0,0}}, 546 | {"Japan",{"JST","JST"},undef,540,0,undef,{0,0},undef,{0,0}}, 547 | {"Kwajalein",{"MHT","MHT"},undef,720,0,undef,{0,0},undef,{0,0}}, 548 | {"Libya",{"EET","EET"},undef,120,0,undef,{0,0},undef,{0,0}}, 549 | {"MET",{"MET","MET"},{"MEST","MEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 550 | {"MST",{"MST","MST"},undef,-420,0,undef,{0,0},undef,{0,0}}, 551 | {"MST7MDT",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 552 | {"Mexico/BajaNorte",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 553 | {"Mexico/BajaSur",{"MST","MST"},{"MDT","MDT"},-420,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 554 | {"Mexico/General",{"CST","CST"},{"CDT","CDT"},-360,60,{1,sun,apr},{2,0},{last,sun,oct},{2,0}}, 555 | {"NZ",{"NZST","NZST"},{"NZDT","NZDT"},720,60,{last,sun,sep},{2,0},{1,sun,apr},{3,0}}, 556 | {"NZ-CHAT",{"CHAST","CHAST"},{"CHADT","CHADT"},765,60,{last,sun,sep},{2,45},{1,sun,apr},{3,45}}, 557 | {"Navajo",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 558 | {"PRC",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 559 | {"PST8PDT",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 560 | {"Pacific/Apia",{"WST","WST"},{"WSDT","WSDT"},780,1,{last,sun,sep},{3,0},{1,sun,apr},{4,0}}, 561 | {"Pacific/Auckland",{"NZST","NZST"},{"NZDT","NZDT"},720,60,{last,sun,sep},{2,0},{1,sun,apr},{3,0}}, 562 | {"Pacific/Chatham",{"CHAST","CHAST"},{"CHADT","CHADT"},765,60,{last,sun,sep},{2,45},{1,sun,apr},{3,45}}, 563 | {"Pacific/Chuuk",{"CHUT","CHUT"},undef,600,0,undef,{0,0},undef,{0,0}}, 564 | {"Pacific/Easter",{"EAST","EAST"},{"EASST","EASST"},-360,60,{1,sun,sep},{0,0},{4,sun,apr},{0,0}}, 565 | {"Pacific/Efate",{"VUT","VUT"},undef,660,0,undef,{0,0},undef,{0,0}}, 566 | {"Pacific/Enderbury",{"PHOT","PHOT"},undef,780,0,undef,{0,0},undef,{0,0}}, 567 | {"Pacific/Fakaofo",{"TKT","TKT"},undef,780,0,undef,{0,0},undef,{0,0}}, 568 | {"Pacific/Fiji",{"FJT","FJT"},{"FJST","FJST"},720,60,{4,sun,oct},{2,0},{3,sun,jan},{3,0}}, 569 | {"Pacific/Funafuti",{"TVT","TVT"},undef,720,0,undef,{0,0},undef,{0,0}}, 570 | {"Pacific/Galapagos",{"GALT","GALT"},undef,-360,0,undef,{0,0},undef,{0,0}}, 571 | {"Pacific/Gambier",{"GAMT","GAMT"},undef,-540,0,undef,{0,0},undef,{0,0}}, 572 | {"Pacific/Guadalcanal",{"SBT","SBT"},undef,660,0,undef,{0,0},undef,{0,0}}, 573 | {"Pacific/Guam",{"ChST","ChST"},undef,600,0,undef,{0,0},undef,{0,0}}, 574 | {"Pacific/Honolulu",{"HST","HST"},undef,-600,0,undef,{0,0},undef,{0,0}}, 575 | {"Pacific/Johnston",{"HST","HST"},undef,-600,0,undef,{0,0},undef,{0,0}}, 576 | {"Pacific/Kiritimati",{"LINT","LINT"},undef,840,0,undef,{0,0},undef,{0,0}}, 577 | {"Pacific/Kosrae",{"KOST","KOST"},undef,660,0,undef,{0,0},undef,{0,0}}, 578 | {"Pacific/Kwajalein",{"MHT","MHT"},undef,720,0,undef,{0,0},undef,{0,0}}, 579 | {"Pacific/Majuro",{"MHT","MHT"},undef,720,0,undef,{0,0},undef,{0,0}}, 580 | {"Pacific/Marquesas",{"MART","MART"},undef,-570,0,undef,{0,0},undef,{0,0}}, 581 | {"Pacific/Midway",{"SST","SST"},undef,-660,0,undef,{0,0},undef,{0,0}}, 582 | {"Pacific/Nauru",{"NRT","NRT"},undef,720,0,undef,{0,0},undef,{0,0}}, 583 | {"Pacific/Niue",{"NUT","NUT"},undef,-660,0,undef,{0,0},undef,{0,0}}, 584 | {"Pacific/Norfolk",{"NFT","NFT"},undef,690,0,undef,{0,0},undef,{0,0}}, 585 | {"Pacific/Noumea",{"NCT","NCT"},undef,660,0,undef,{0,0},undef,{0,0}}, 586 | {"Pacific/Pago_Pago",{"SST","SST"},undef,-660,0,undef,{0,0},undef,{0,0}}, 587 | {"Pacific/Palau",{"PWT","PWT"},undef,540,0,undef,{0,0},undef,{0,0}}, 588 | {"Pacific/Pitcairn",{"PST","PST"},undef,-480,0,undef,{0,0},undef,{0,0}}, 589 | {"Pacific/Pohnpei",{"PONT","PONT"},undef,660,0,undef,{0,0},undef,{0,0}}, 590 | {"Pacific/Ponape",{"PONT","PONT"},undef,660,0,undef,{0,0},undef,{0,0}}, 591 | {"Pacific/Port_Moresby",{"PGT","PGT"},undef,600,0,undef,{0,0},undef,{0,0}}, 592 | {"Pacific/Rarotonga",{"CKT","CKT"},undef,-600,0,undef,{0,0},undef,{0,0}}, 593 | {"Pacific/Saipan",{"ChST","ChST"},undef,600,0,undef,{0,0},undef,{0,0}}, 594 | {"Pacific/Samoa",{"SST","SST"},undef,-660,0,undef,{0,0},undef,{0,0}}, 595 | {"Pacific/Tahiti",{"TAHT","TAHT"},undef,-600,0,undef,{0,0},undef,{0,0}}, 596 | {"Pacific/Tarawa",{"GILT","GILT"},undef,720,0,undef,{0,0},undef,{0,0}}, 597 | {"Pacific/Tongatapu",{"TOT","TOT"},undef,780,0,undef,{0,0},undef,{0,0}}, 598 | {"Pacific/Truk",{"CHUT","CHUT"},undef,600,0,undef,{0,0},undef,{0,0}}, 599 | {"Pacific/Wake",{"WAKT","WAKT"},undef,720,0,undef,{0,0},undef,{0,0}}, 600 | {"Pacific/Wallis",{"WFT","WFT"},undef,720,0,undef,{0,0},undef,{0,0}}, 601 | {"Pacific/Yap",{"CHUT","CHUT"},undef,600,0,undef,{0,0},undef,{0,0}}, 602 | {"Poland",{"CET","CET"},{"CEST","CEST"},60,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 603 | {"Portugal",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 604 | {"ROC",{"CST","CST"},undef,480,0,undef,{0,0},undef,{0,0}}, 605 | {"ROK",{"KST","KST"},undef,540,0,undef,{0,0},undef,{0,0}}, 606 | {"Singapore",{"SGT","SGT"},undef,480,0,undef,{0,0},undef,{0,0}}, 607 | {"Turkey",{"EET","EET"},{"EEST","EEST"},120,60,{last,sun,mar},{3,0},{last,sun,oct},{4,0}}, 608 | {"UCT",{"UCT","UCT"},undef,0,0,undef,{0,0},undef,{0,0}}, 609 | {"US/Alaska",{"AKST","AKST"},{"AKDT","AKDT"},-540,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 610 | {"US/Aleutian",{"HAST","HAST"},{"HADT","HADT"},-600,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 611 | {"US/Arizona",{"MST","MST"},undef,-420,0,undef,{0,0},undef,{0,0}}, 612 | {"US/Central",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 613 | {"US/East-Indiana",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 614 | {"US/Eastern",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 615 | {"US/Hawaii",{"HST","HST"},undef,-600,0,undef,{0,0},undef,{0,0}}, 616 | {"US/Indiana-Starke",{"CST","CST"},{"CDT","CDT"},-360,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 617 | {"US/Michigan",{"EST","EST"},{"EDT","EDT"},-300,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 618 | {"US/Mountain",{"MST","MST"},{"MDT","MDT"},-420,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 619 | {"US/Pacific",{"PST","PST"},{"PDT","PDT"},-480,60,{2,sun,mar},{2,0},{1,sun,nov},{2,0}}, 620 | {"US/Samoa",{"SST","SST"},undef,-660,0,undef,{0,0},undef,{0,0}}, 621 | {"UTC",{"UTC","UTC"},undef,0,0,undef,{0,0},undef,{0,0}}, 622 | {"Universal",{"UTC","UTC"},undef,0,0,undef,{0,0},undef,{0,0}}, 623 | {"W-SU",{"MSK","MSK"},undef,240,0,undef,{0,0},undef,{0,0}}, 624 | {"WET",{"WET","WET"},{"WEST","WEST"},0,60,{last,sun,mar},{1,0},{last,sun,oct},{2,0}}, 625 | {"Zulu",{"UTC","UTC"},undef,0,0,undef,{0,0},undef,{0,0}} 626 | ]). 627 | -------------------------------------------------------------------------------- /include/tz_index.hrl: -------------------------------------------------------------------------------- 1 | -define(tz_index, {dict,198,40,64,32,200,120, 2 | {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}, 3 | {{[["WGST","America/Godthab"],["GMT+2","Etc/GMT+2"]], 4 | [["NPT","Asia/Kathmandu","Asia/Katmandu"], 5 | ["CCT","Indian/Cocos"]], 6 | [["DAVT","Antarctica/Davis"], 7 | ["AZT","Asia/Baku"], 8 | ["HKT","Asia/Hong_Kong","Hongkong"]], 9 | [["MST","America/Boise","America/Cambridge_Bay", 10 | "America/Chihuahua","America/Creston", 11 | "America/Dawson_Creek","America/Denver", 12 | "America/Edmonton","America/Hermosillo", 13 | "America/Inuvik","America/Mazatlan", 14 | "America/Ojinaga","America/Phoenix", 15 | "America/Shiprock","America/Yellowknife", 16 | "Canada/Mountain","MST","MST7MDT", 17 | "Mexico/BajaSur","Navajo","US/Arizona", 18 | "US/Mountain"], 19 | ["GMT-7","Etc/GMT-7"]], 20 | [["ROTT","Antarctica/Rothera"], 21 | ["GMT-13","Etc/GMT-13"], 22 | ["GMT-4","Etc/GMT-4"], 23 | ["GAMT","Pacific/Gambier"]], 24 | [["SGT","Asia/Singapore","Singapore"], 25 | ["GMT-1","Etc/GMT-1"], 26 | ["GMT-10","Etc/GMT-10"]], 27 | [["SAKT","Asia/Sakhalin"], 28 | ["LHST","Australia/LHI","Australia/LHI", 29 | "Australia/Lord_Howe","Australia/Lord_Howe"], 30 | ["MSK","Europe/Moscow","W-SU"], 31 | ["PHOT","Pacific/Enderbury"], 32 | ["PWT","Pacific/Palau"]], 33 | [["AST","America/Anguilla","America/Antigua", 34 | "America/Aruba","America/Barbados", 35 | "America/Blanc-Sablon","America/Curacao", 36 | "America/Dominica","America/Glace_Bay", 37 | "America/Goose_Bay","America/Grenada", 38 | "America/Guadeloupe","America/Halifax", 39 | "America/Kralendijk","America/Lower_Princes", 40 | "America/Marigot","America/Martinique", 41 | "America/Moncton","America/Montserrat", 42 | "America/Port_of_Spain","America/Puerto_Rico", 43 | "America/Santo_Domingo","America/St_Barthelemy", 44 | "America/St_Kitts","America/St_Lucia", 45 | "America/St_Thomas","America/St_Vincent", 46 | "America/Thule","America/Tortola", 47 | "America/Virgin","Asia/Aden","Asia/Baghdad", 48 | "Asia/Bahrain","Asia/Kuwait","Asia/Qatar", 49 | "Asia/Riyadh","Atlantic/Bermuda", 50 | "Canada/Atlantic"], 51 | ["EASST","Chile/EasterIsland","Pacific/Easter"]], 52 | [["NST","America/St_Johns","Canada/Newfoundland"], 53 | ["MIST","Antarctica/Macquarie"], 54 | ["WITA","Asia/Makassar","Asia/Ujung_Pandang"], 55 | ["YEKT","Asia/Yekaterinburg"]], 56 | [["BDT","Asia/Dacca","Asia/Dhaka"], 57 | ["GMT+7","Etc/GMT+7"], 58 | ["CKT","Pacific/Rarotonga"]], 59 | [["PKT","Asia/Karachi"], 60 | ["NOVT","Asia/Novokuznetsk","Asia/Novosibirsk"], 61 | ["GMT+4","Etc/GMT+4"], 62 | ["FET","Europe/Kaliningrad","Europe/Minsk"], 63 | ["HST","HST","Pacific/Honolulu","Pacific/Johnston", 64 | "US/Hawaii"], 65 | ["MVT","Indian/Maldives"], 66 | ["VUT","Pacific/Efate"], 67 | ["LINT","Pacific/Kiritimati"]], 68 | [["WAT","Africa/Bangui","Africa/Brazzaville", 69 | "Africa/Douala","Africa/Kinshasa","Africa/Lagos", 70 | "Africa/Libreville","Africa/Luanda", 71 | "Africa/Malabo","Africa/Ndjamena","Africa/Niamey", 72 | "Africa/Porto-Novo","Africa/Windhoek"], 73 | ["ECT","America/Guayaquil"], 74 | ["VOST","Antarctica/Vostok"], 75 | ["BNT","Asia/Brunei"], 76 | ["TLT","Asia/Dili"], 77 | ["GMT+1","Etc/GMT+1"], 78 | ["CHADT","NZ-CHAT","Pacific/Chatham"], 79 | ["FJT","Pacific/Fiji"]], 80 | [["HADT","America/Adak","America/Atka", 81 | "US/Aleutian"], 82 | ["EEST","Asia/Amman","Asia/Beirut","Asia/Damascus", 83 | "Asia/Gaza","Asia/Hebron","Asia/Istanbul", 84 | "Asia/Nicosia","EET","Europe/Athens", 85 | "Europe/Bucharest","Europe/Chisinau", 86 | "Europe/Helsinki","Europe/Istanbul","Europe/Kiev", 87 | "Europe/Mariehamn","Europe/Nicosia","Europe/Riga", 88 | "Europe/Simferopol","Europe/Sofia", 89 | "Europe/Tallinn","Europe/Tiraspol", 90 | "Europe/Uzhgorod","Europe/Vilnius", 91 | "Europe/Zaporozhye","Turkey"], 92 | ["IDT","Asia/Jerusalem","Asia/Tel_Aviv","Israel"], 93 | ["CWST","Australia/Eucla"], 94 | ["BST","Europe/Belfast","Europe/Guernsey", 95 | "Europe/Isle_of_Man","Europe/Jersey", 96 | "Europe/London","GB","GB-Eire"], 97 | ["KOST","Pacific/Kosrae"], 98 | ["WFT","Pacific/Wallis"]], 99 | [["ALMT","Asia/Almaty"], 100 | ["CHOT","Asia/Choibalsan"], 101 | ["AZOT","Atlantic/Azores"], 102 | ["GMT-9","Etc/GMT-9"], 103 | ["MET","MET"], 104 | ["TVT","Pacific/Funafuti"]], 105 | [["SAST","Africa/Johannesburg","Africa/Maseru", 106 | "Africa/Mbabane"], 107 | ["CDT","America/Bahia_Banderas","America/Cancun", 108 | "America/Chicago","America/Havana", 109 | "America/Indiana/Knox", 110 | "America/Indiana/Tell_City","America/Knox_IN", 111 | "America/Matamoros","America/Menominee", 112 | "America/Merida","America/Mexico_City", 113 | "America/Monterrey","America/North_Dakota/Beulah", 114 | "America/North_Dakota/Center", 115 | "America/North_Dakota/New_Salem", 116 | "America/Rainy_River","America/Rankin_Inlet", 117 | "America/Resolute","America/Winnipeg","CST6CDT", 118 | "Canada/Central","Cuba","Mexico/General", 119 | "US/Central","US/Indiana-Starke"], 120 | ["GMT-6","Etc/GMT-6"], 121 | ["CHAST","NZ-CHAT","Pacific/Chatham"]], 122 | [["HAST","America/Adak","America/Atka", 123 | "US/Aleutian"], 124 | ["PYST","America/Asuncion"], 125 | ["PDT","America/Dawson","America/Ensenada", 126 | "America/Los_Angeles","America/Santa_Isabel", 127 | "America/Tijuana","America/Vancouver", 128 | "America/Whitehorse","Canada/Pacific", 129 | "Canada/Yukon","Mexico/BajaNorte","PST8PDT", 130 | "US/Pacific"], 131 | ["IST","Asia/Calcutta","Asia/Colombo", 132 | "Asia/Jerusalem","Asia/Kolkata","Asia/Tel_Aviv", 133 | "Eire","Europe/Dublin","Israel"], 134 | ["GET","Asia/Tbilisi"], 135 | ["GMT-12","Etc/GMT-12"], 136 | ["GMT-3","Etc/GMT-3"]]}, 137 | {[["PMDT","America/Miquelon"], 138 | ["GMT+11","Etc/GMT+11"], 139 | ["VOLT","Europe/Volgograd"]], 140 | [["EAT","Africa/Addis_Ababa","Africa/Asmara", 141 | "Africa/Asmera","Africa/Dar_es_Salaam", 142 | "Africa/Djibouti","Africa/Juba","Africa/Kampala", 143 | "Africa/Khartoum","Africa/Mogadishu", 144 | "Africa/Nairobi","Indian/Antananarivo", 145 | "Indian/Comoro","Indian/Mayotte"], 146 | ["CST","America/Bahia_Banderas","America/Belize", 147 | "America/Cancun","America/Chicago", 148 | "America/Costa_Rica","America/El_Salvador", 149 | "America/Guatemala","America/Havana", 150 | "America/Indiana/Knox", 151 | "America/Indiana/Tell_City","America/Knox_IN", 152 | "America/Managua","America/Matamoros", 153 | "America/Menominee","America/Merida", 154 | "America/Mexico_City","America/Monterrey", 155 | "America/North_Dakota/Beulah", 156 | "America/North_Dakota/Center", 157 | "America/North_Dakota/New_Salem", 158 | "America/Rainy_River","America/Rankin_Inlet", 159 | "America/Regina","America/Resolute", 160 | "America/Swift_Current","America/Tegucigalpa", 161 | "America/Winnipeg","Asia/Chongqing", 162 | "Asia/Chungking","Asia/Harbin","Asia/Kashgar", 163 | "Asia/Macao","Asia/Macau","Asia/Shanghai", 164 | "Asia/Taipei","Asia/Urumqi","Australia/Adelaide", 165 | "Australia/Adelaide","Australia/Broken_Hill", 166 | "Australia/Broken_Hill","Australia/Darwin", 167 | "Australia/North","Australia/South", 168 | "Australia/South","Australia/Yancowinna", 169 | "Australia/Yancowinna","CST6CDT","Canada/Central", 170 | "Canada/East-Saskatchewan","Canada/Saskatchewan", 171 | "Cuba","Mexico/General","PRC","ROC","US/Central", 172 | "US/Indiana-Starke"], 173 | ["TJT","Asia/Dushanbe"], 174 | ["KRAT","Asia/Krasnoyarsk"], 175 | ["MYT","Asia/Kuala_Lumpur","Asia/Kuching"], 176 | ["SCT","Indian/Mahe"]], 177 | [["CEST","Africa/Ceuta","Arctic/Longyearbyen", 178 | "Atlantic/Jan_Mayen","CET","Europe/Amsterdam", 179 | "Europe/Andorra","Europe/Belgrade", 180 | "Europe/Berlin","Europe/Bratislava", 181 | "Europe/Brussels","Europe/Budapest", 182 | "Europe/Busingen","Europe/Copenhagen", 183 | "Europe/Gibraltar","Europe/Ljubljana", 184 | "Europe/Luxembourg","Europe/Madrid", 185 | "Europe/Malta","Europe/Monaco","Europe/Oslo", 186 | "Europe/Paris","Europe/Podgorica","Europe/Prague", 187 | "Europe/Rome","Europe/San_Marino", 188 | "Europe/Sarajevo","Europe/Skopje", 189 | "Europe/Stockholm","Europe/Tirane","Europe/Vaduz", 190 | "Europe/Vatican","Europe/Vienna","Europe/Warsaw", 191 | "Europe/Zagreb","Europe/Zurich","Poland"], 192 | ["PST","America/Dawson","America/Ensenada", 193 | "America/Los_Angeles","America/Santa_Isabel", 194 | "America/Tijuana","America/Vancouver", 195 | "America/Whitehorse","Canada/Pacific", 196 | "Canada/Yukon","Mexico/BajaNorte","PST8PDT", 197 | "Pacific/Pitcairn","US/Pacific"], 198 | ["SYOT","Antarctica/Syowa"], 199 | ["VLAT","Asia/Ust-Nera","Asia/Vladivostok"], 200 | ["CXT","Indian/Christmas"], 201 | ["TOT","Pacific/Tongatapu"]], 202 | [["AKDT","America/Anchorage","America/Juneau", 203 | "America/Nome","America/Sitka","America/Yakutat", 204 | "US/Alaska"], 205 | ["GYT","America/Guyana"], 206 | ["PMST","America/Miquelon"], 207 | ["WIT","Asia/Jayapura"], 208 | ["GMT+9","Etc/GMT+9"], 209 | ["UTC","Etc/UTC","Etc/Universal","Etc/Zulu","UTC", 210 | "Universal","Zulu"], 211 | ["MART","Pacific/Marquesas"]], 212 | [["MeST","America/Metlakatla"], 213 | ["SRT","America/Paramaribo"], 214 | ["MAWT","Antarctica/Mawson"], 215 | ["YAKT","Asia/Khandyga","Asia/Yakutsk"], 216 | ["JST","Asia/Tokyo","Japan"], 217 | ["AZOST","Atlantic/Azores"], 218 | ["GMT+6","Etc/GMT+6"], 219 | ["MHT","Kwajalein","Pacific/Kwajalein", 220 | "Pacific/Majuro"], 221 | ["MEST","MET"]], 222 | [["CLST","America/Santiago","Antarctica/Palmer", 223 | "Chile/Continental"], 224 | ["WST","Antarctica/Casey","Australia/Perth", 225 | "Australia/West","Pacific/Apia"], 226 | ["MMT","Asia/Rangoon"], 227 | ["ULAT","Asia/Ulaanbaatar","Asia/Ulan_Bator"], 228 | ["GMT+3","Etc/GMT+3"]], 229 | [["WEST","Africa/Casablanca","Africa/El_Aaiun", 230 | "Atlantic/Canary","Atlantic/Faeroe", 231 | "Atlantic/Faroe","Atlantic/Madeira", 232 | "Europe/Lisbon","Portugal","WET"], 233 | ["AKST","America/Anchorage","America/Juneau", 234 | "America/Nome","America/Sitka","America/Yakutat", 235 | "US/Alaska"], 236 | ["CLT","America/Santiago","Antarctica/Palmer", 237 | "Chile/Continental"], 238 | ["BRST","America/Sao_Paulo","Brazil/East"], 239 | ["EGST","America/Scoresbysund"], 240 | ["OMST","Asia/Omsk"], 241 | ["PGT","Pacific/Port_Moresby"]], 242 | [["GMT","Africa/Abidjan","Africa/Accra", 243 | "Africa/Bamako","Africa/Banjul","Africa/Bissau", 244 | "Africa/Conakry","Africa/Dakar","Africa/Freetown", 245 | "Africa/Lome","Africa/Monrovia", 246 | "Africa/Nouakchott","Africa/Ouagadougou", 247 | "Africa/Sao_Tome","Africa/Timbuktu", 248 | "America/Danmarkshavn","Atlantic/Reykjavik", 249 | "Atlantic/St_Helena","Eire","Etc/GMT","Etc/GMT+0", 250 | "Etc/GMT-0","Etc/GMT0","Etc/Greenwich", 251 | "Europe/Belfast","Europe/Dublin", 252 | "Europe/Guernsey","Europe/Isle_of_Man", 253 | "Europe/Jersey","Europe/London","GB","GB-Eire", 254 | "GMT","GMT+0","GMT-0","GMT0","Greenwich", 255 | "Iceland"], 256 | ["ACT","America/Eirunepe","America/Porto_Acre", 257 | "America/Rio_Branco","Brazil/Acre"], 258 | ["NZDT","Antarctica/McMurdo", 259 | "Antarctica/South_Pole","NZ","Pacific/Auckland"], 260 | ["GALT","Pacific/Galapagos"]], 261 | [["EDT","America/Detroit","America/Fort_Wayne", 262 | "America/Grand_Turk", 263 | "America/Indiana/Indianapolis", 264 | "America/Indiana/Marengo", 265 | "America/Indiana/Petersburg", 266 | "America/Indiana/Vevay", 267 | "America/Indiana/Vincennes", 268 | "America/Indiana/Winamac","America/Indianapolis", 269 | "America/Iqaluit","America/Kentucky/Louisville", 270 | "America/Kentucky/Monticello", 271 | "America/Louisville","America/Montreal", 272 | "America/Nassau","America/New_York", 273 | "America/Nipigon","America/Pangnirtung", 274 | "America/Port-au-Prince","America/Thunder_Bay", 275 | "America/Toronto","Canada/Eastern","EST5EDT", 276 | "US/East-Indiana","US/Eastern","US/Michigan"], 277 | ["BOT","America/La_Paz"], 278 | ["TMT","Asia/Ashgabat","Asia/Ashkhabad"], 279 | ["PETT","Asia/Kamchatka"], 280 | ["CVT","Atlantic/Cape_Verde"], 281 | ["EAST","Chile/EasterIsland","Pacific/Easter"], 282 | ["GMT-8","Etc/GMT-8"], 283 | ["NCT","Pacific/Noumea"]], 284 | [["AMT","America/Boa_Vista","America/Campo_Grande", 285 | "America/Cuiaba","America/Manaus", 286 | "America/Porto_Velho","Asia/Yerevan", 287 | "Brazil/West"], 288 | ["WGT","America/Godthab"], 289 | ["UYT","America/Montevideo"], 290 | ["IRKT","Asia/Irkutsk"], 291 | ["WIB","Asia/Jakarta","Asia/Pontianak"], 292 | ["KST","Asia/Pyongyang","Asia/Seoul","ROK"], 293 | ["BTT","Asia/Thimbu","Asia/Thimphu"], 294 | ["GMT-14","Etc/GMT-14"], 295 | ["GMT-5","Etc/GMT-5"], 296 | ["WSDT","Pacific/Apia"]], 297 | [["ART","America/Argentina/Buenos_Aires", 298 | "America/Argentina/Catamarca", 299 | "America/Argentina/ComodRivadavia", 300 | "America/Argentina/Cordoba", 301 | "America/Argentina/Jujuy", 302 | "America/Argentina/La_Rioja", 303 | "America/Argentina/Mendoza", 304 | "America/Argentina/Rio_Gallegos", 305 | "America/Argentina/Salta", 306 | "America/Argentina/San_Juan", 307 | "America/Argentina/San_Luis", 308 | "America/Argentina/Tucuman", 309 | "America/Argentina/Ushuaia", 310 | "America/Buenos_Aires","America/Catamarca", 311 | "America/Cordoba","America/Jujuy", 312 | "America/Mendoza","America/Rosario"], 313 | ["VET","America/Caracas"], 314 | ["NZST","Antarctica/McMurdo", 315 | "Antarctica/South_Pole","NZ","Pacific/Auckland"], 316 | ["GMT-11","Etc/GMT-11"], 317 | ["GMT-2","Etc/GMT-2"], 318 | ["WAKT","Pacific/Wake"]], 319 | [["CET","Africa/Algiers","Africa/Ceuta", 320 | "Africa/Tunis","Arctic/Longyearbyen", 321 | "Atlantic/Jan_Mayen","CET","Europe/Amsterdam", 322 | "Europe/Andorra","Europe/Belgrade", 323 | "Europe/Berlin","Europe/Bratislava", 324 | "Europe/Brussels","Europe/Budapest", 325 | "Europe/Busingen","Europe/Copenhagen", 326 | "Europe/Gibraltar","Europe/Ljubljana", 327 | "Europe/Luxembourg","Europe/Madrid", 328 | "Europe/Malta","Europe/Monaco","Europe/Oslo", 329 | "Europe/Paris","Europe/Podgorica","Europe/Prague", 330 | "Europe/Rome","Europe/San_Marino", 331 | "Europe/Sarajevo","Europe/Skopje", 332 | "Europe/Stockholm","Europe/Tirane","Europe/Vaduz", 333 | "Europe/Vatican","Europe/Vienna","Europe/Warsaw", 334 | "Europe/Zagreb","Europe/Zurich","Poland"], 335 | ["EST","America/Atikokan","America/Cayman", 336 | "America/Coral_Harbour","America/Detroit", 337 | "America/Fort_Wayne","America/Grand_Turk", 338 | "America/Indiana/Indianapolis", 339 | "America/Indiana/Marengo", 340 | "America/Indiana/Petersburg", 341 | "America/Indiana/Vevay", 342 | "America/Indiana/Vincennes", 343 | "America/Indiana/Winamac","America/Indianapolis", 344 | "America/Iqaluit","America/Jamaica", 345 | "America/Kentucky/Louisville", 346 | "America/Kentucky/Monticello", 347 | "America/Louisville","America/Montreal", 348 | "America/Nassau","America/New_York", 349 | "America/Nipigon","America/Panama", 350 | "America/Pangnirtung","America/Port-au-Prince", 351 | "America/Thunder_Bay","America/Toronto", 352 | "Australia/ACT","Australia/ACT", 353 | "Australia/Brisbane","Australia/Canberra", 354 | "Australia/Canberra","Australia/Currie", 355 | "Australia/Currie","Australia/Hobart", 356 | "Australia/Hobart","Australia/Lindeman", 357 | "Australia/Melbourne","Australia/Melbourne", 358 | "Australia/NSW","Australia/NSW", 359 | "Australia/Queensland","Australia/Sydney", 360 | "Australia/Sydney","Australia/Tasmania", 361 | "Australia/Tasmania","Australia/Victoria", 362 | "Australia/Victoria","Canada/Eastern","EST", 363 | "EST5EDT","Jamaica","US/East-Indiana", 364 | "US/Eastern","US/Michigan"], 365 | ["ANAT","Asia/Anadyr"], 366 | ["GMT+10","Etc/GMT+10"], 367 | ["UCT","Etc/UCT","UCT"], 368 | ["IOT","Indian/Chagos"], 369 | ["CHUT","Pacific/Chuuk","Pacific/Truk", 370 | "Pacific/Yap"], 371 | ["NRT","Pacific/Nauru"]], 372 | [["GFT","America/Cayenne"], 373 | ["PET","America/Lima"], 374 | ["HOVT","Asia/Hovd"], 375 | ["PONT","Pacific/Pohnpei","Pacific/Ponape"], 376 | ["TAHT","Pacific/Tahiti"]], 377 | [["COT","America/Bogota"], 378 | ["KGT","Asia/Bishkek"], 379 | ["TFT","Indian/Kerguelen"], 380 | ["MUT","Indian/Mauritius"]], 381 | [["AFT","Asia/Kabul"], 382 | ["IRDT","Asia/Tehran","Iran"], 383 | ["GMT+8","Etc/GMT+8"], 384 | ["TKT","Pacific/Fakaofo"]], 385 | [["WET","Africa/Casablanca","Africa/El_Aaiun", 386 | "Atlantic/Canary","Atlantic/Faeroe", 387 | "Atlantic/Faroe","Atlantic/Madeira", 388 | "Europe/Lisbon","Portugal","WET"], 389 | ["BRT","America/Araguaina","America/Bahia", 390 | "America/Belem","America/Fortaleza", 391 | "America/Maceio","America/Recife", 392 | "America/Santarem","America/Sao_Paulo", 393 | "Brazil/East"], 394 | ["FNT","America/Noronha","Brazil/DeNoronha"], 395 | ["EGT","America/Scoresbysund"], 396 | ["ICT","Asia/Bangkok","Asia/Ho_Chi_Minh", 397 | "Asia/Phnom_Penh","Asia/Saigon","Asia/Vientiane"], 398 | ["GMT+5","Etc/GMT+5"], 399 | ["NFT","Pacific/Norfolk"], 400 | ["GILT","Pacific/Tarawa"]]}, 401 | {[["PYT","America/Asuncion"], 402 | ["MDT","America/Boise","America/Cambridge_Bay", 403 | "America/Chihuahua","America/Denver", 404 | "America/Edmonton","America/Inuvik", 405 | "America/Mazatlan","America/Ojinaga", 406 | "America/Shiprock","America/Yellowknife", 407 | "Canada/Mountain","MST7MDT","Mexico/BajaSur", 408 | "Navajo","US/Mountain"], 409 | ["AMST","America/Campo_Grande","America/Cuiaba"], 410 | ["UYST","America/Montevideo"], 411 | ["SAMT","Europe/Samara"]], 412 | [["AQTT","Asia/Aqtau","Asia/Aqtobe"], 413 | ["AZST","Asia/Baku"], 414 | ["IRST","Asia/Tehran","Iran"], 415 | ["ChST","Pacific/Guam","Pacific/Saipan"], 416 | ["SST","Pacific/Midway","Pacific/Pago_Pago", 417 | "Pacific/Samoa","US/Samoa"]], 418 | [["WAST","Africa/Windhoek"], 419 | ["FJST","Pacific/Fiji"], 420 | ["NUT","Pacific/Niue"]], 421 | [["PHT","Asia/Manila"]], 422 | [["ADT","America/Glace_Bay","America/Goose_Bay", 423 | "America/Halifax","America/Moncton", 424 | "America/Thule","Atlantic/Bermuda", 425 | "Canada/Atlantic"], 426 | ["DDUT","Antarctica/DumontDUrville"], 427 | ["MAGT","Asia/Magadan"], 428 | ["SBT","Pacific/Guadalcanal"]], 429 | [["EET","Africa/Cairo","Africa/Tripoli", 430 | "Asia/Amman","Asia/Beirut","Asia/Damascus", 431 | "Asia/Gaza","Asia/Hebron","Asia/Istanbul", 432 | "Asia/Nicosia","EET","Egypt","Europe/Athens", 433 | "Europe/Bucharest","Europe/Chisinau", 434 | "Europe/Helsinki","Europe/Istanbul","Europe/Kiev", 435 | "Europe/Mariehamn","Europe/Nicosia","Europe/Riga", 436 | "Europe/Simferopol","Europe/Sofia", 437 | "Europe/Tallinn","Europe/Tiraspol", 438 | "Europe/Uzhgorod","Europe/Vilnius", 439 | "Europe/Zaporozhye","Libya","Turkey"], 440 | ["NDT","America/St_Johns","Canada/Newfoundland"], 441 | ["GST","Asia/Dubai","Asia/Muscat", 442 | "Atlantic/South_Georgia"], 443 | ["ORAT","Asia/Oral"], 444 | ["GMT+12","Etc/GMT+12"]], 445 | [["UZT","Asia/Samarkand","Asia/Tashkent"], 446 | ["RET","Indian/Reunion"]], 447 | [["CAT","Africa/Blantyre","Africa/Bujumbura", 448 | "Africa/Gaborone","Africa/Harare","Africa/Kigali", 449 | "Africa/Lubumbashi","Africa/Lusaka", 450 | "Africa/Maputo"], 451 | ["QYZT","Asia/Qyzylorda"], 452 | ["FKST","Atlantic/Stanley"]], 453 | [],[],[],[],[],[],[],[]}, 454 | {[],[],[],[],[],[],[],[],[],[],[],[],[],[],[],[]}}}). -------------------------------------------------------------------------------- /rebar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmitryme/erlang_localtime/7855cd3ebb4c2eec1ce8f0db6655df1a3c635c0d/rebar -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [debug_info]}. 2 | -------------------------------------------------------------------------------- /src/erlang_localtime.app.src: -------------------------------------------------------------------------------- 1 | {application, 'erlang_localtime', 2 | [ 3 | {description, ""}, 4 | {applications, [kernel, stdlib]}, 5 | {vsn, "1.0"}, 6 | {registered, []}, 7 | {env, []}, 8 | {applications, []} 9 | ]}. 10 | -------------------------------------------------------------------------------- /src/ibuild.erl: -------------------------------------------------------------------------------- 1 | %% @author Dmitry S. Melnikov (dmitryme@gmail.com) 2 | %% @copyright 2010 Dmitry S. Melnikov 3 | 4 | -module(ibuild). 5 | 6 | -export([build_index/0, main/1]). 7 | 8 | -include("tz_database.hrl"). 9 | 10 | build_tzlist(TzName, Name, Dict) -> 11 | case dict:find(Name, Dict) of 12 | error -> 13 | dict:store(Name, [TzName], Dict); 14 | {ok, TzNames} -> 15 | dict:store(Name, TzNames ++ [TzName], Dict) 16 | end. 17 | 18 | build_index() -> 19 | F = fun({TzName,{Name,_},{DName,_},_,_,_,_,_,_}, Acc) -> 20 | NewDict = build_tzlist(TzName, Name, Acc), 21 | build_tzlist(TzName, DName, NewDict); 22 | ({TzName,{Name,_},undef,_,_,_,_,_,_}, Acc) -> 23 | build_tzlist(TzName, Name, Acc) 24 | end, 25 | I = lists:foldl(F, dict:new(), ?tz_database), 26 | {ok, File} = file:open("tz_index.hrl", [write]), 27 | io:fwrite(File, "-define(tz_index, ~p).", [I]). 28 | 29 | %% So this can be run from escript: 30 | main(_Args) -> 31 | build_index(). 32 | -------------------------------------------------------------------------------- /src/localtime.erl: -------------------------------------------------------------------------------- 1 | %% @author Dmitry S. Melnikov (dmitryme@gmail.com) 2 | %% @copyright 2010 Dmitry S. Melnikov 3 | 4 | -module(localtime). 5 | 6 | -author("Dmitry Melnikov "). 7 | 8 | -include("tz_database.hrl"). 9 | -include("tz_index.hrl"). 10 | 11 | -export( 12 | [ 13 | utc_to_local/2 14 | ,local_to_utc/2 15 | ,local_to_local/3 16 | ,local_to_local_dst/3 17 | ,tz_name/2 18 | ,tz_shift/2 19 | ,tz_shift/3 20 | ,get_timezone/1 21 | ,list_timezones/0 22 | ,adjust_datetime/2 23 | ]). 24 | 25 | % utc_to_local(UtcDateTime, Timezone) -> LocalDateTime | [LocalDateTime, DstLocalDateTime] | {error, ErrDescr} 26 | % UtcDateTime = DateTime() 27 | % Timezone = String() 28 | % LocalDateTime = DateTime() 29 | % DstLocalDateTime = DateTime() 30 | % ErrDescr = atom(), unknown_tz 31 | utc_to_local(UtcDateTime, Timezone) -> 32 | case lists:keyfind(get_timezone(Timezone), 1, ?tz_database) of 33 | false -> 34 | {error, unknown_tz}; 35 | {_Tz, _, _, Shift, _DstShift, undef, _DstStartTime, undef, _DstEndTime} -> 36 | adjust_datetime(UtcDateTime, Shift); 37 | TzRule = {_, _, _, Shift, DstShift, _, _, _, _} -> 38 | LocalDateTime = adjust_datetime(UtcDateTime, Shift), 39 | case localtime_dst:check(LocalDateTime, TzRule) of 40 | Res when (Res == is_in_dst) or (Res == time_not_exists) -> 41 | adjust_datetime(LocalDateTime, DstShift); 42 | is_not_in_dst -> 43 | LocalDateTime; 44 | ambiguous_time -> 45 | [LocalDateTime, adjust_datetime(LocalDateTime, DstShift)] 46 | end 47 | end. 48 | 49 | % local_to_utc(LocalDateTime, Timezone) -> UtcDateTime | [UtcDateTime, DstUtcDateTime] | time_not_exists | {error, ErrDescr} 50 | % LocalDateTime = DateTime() 51 | % Timezone = String() 52 | % UtcDateTime = DateTime() 53 | % DstUtcDateTime = DateTime() 54 | % ErrDescr = atom(), unknown_tz 55 | local_to_utc(LocalDateTime, Timezone) -> 56 | case lists:keyfind(get_timezone(Timezone), 1, ?tz_database) of 57 | false -> 58 | {error, unknown_tz}; 59 | {_Tz, _, _, Shift, _DstShift, undef, _DstStartTime, undef, _DstEndTime} -> 60 | adjust_datetime(LocalDateTime, invert_shift(Shift)); 61 | TzRule = {_, _, _, Shift, DstShift, _, _, _, _} -> 62 | UtcDateTime = adjust_datetime(LocalDateTime, invert_shift(Shift)), 63 | case localtime_dst:check(LocalDateTime, TzRule) of 64 | is_in_dst -> 65 | adjust_datetime(UtcDateTime, invert_shift(DstShift)); 66 | is_not_in_dst -> 67 | UtcDateTime; 68 | ambiguous_time -> 69 | [UtcDateTime, adjust_datetime(UtcDateTime, invert_shift(DstShift))]; 70 | time_not_exists -> 71 | time_not_exists 72 | end 73 | end. 74 | 75 | % local_to_local(LocalDateTime, TimezoneFrom, TimezoneTo) -> LocalDateTime | ambiguous | time_not_exists | {error, ErrDescr} 76 | % LocalDateTime = DateTime() 77 | % TimezoneFrom = String() 78 | % TimezoneTo = String() 79 | % ErrDescr = atom(), unknown_tz 80 | local_to_local(LocalDateTime, TimezoneFrom, TimezoneTo) -> 81 | case local_to_utc(LocalDateTime, TimezoneFrom) of 82 | UtcDateTime = {{_,_,_},{_,_,_}} -> 83 | LocalDateTime2 = utc_to_local(UtcDateTime, TimezoneTo); 84 | [UtcDateTime, {{_,_,_},{_,_,_}}] -> 85 | LocalDateTime2 = utc_to_local(UtcDateTime, TimezoneTo); 86 | Res -> 87 | LocalDateTime2 = Res 88 | end, 89 | case LocalDateTime2 of 90 | [DateTimeToReturn, {{_,_,_},{_,_,_}}] -> 91 | DateTimeToReturn; 92 | Other -> 93 | Other 94 | end. 95 | 96 | % local_to_local_dst(LocalDateTime, TimezoneFrom, TimezoneTo) -> LocalDateTime | ambiguous | time_not_exists | {error, ErrDescr} 97 | % LocalDateTime = DateTime() 98 | % TimezoneFrom = String() 99 | % TimezoneTo = String() 100 | % ErrDescr = atom(), unknown_tz 101 | local_to_local_dst(LocalDateTime, TimezoneFrom, TimezoneTo) -> 102 | case local_to_utc(LocalDateTime, TimezoneFrom) of 103 | UtcDateTime = {{_,_,_},{_,_,_}} -> 104 | LocalDateTime2 = utc_to_local(UtcDateTime, TimezoneTo); 105 | [{{_,_,_},{_,_,_}}, UtcDateTime] -> 106 | LocalDateTime2 = utc_to_local(UtcDateTime, TimezoneTo); 107 | Res -> 108 | LocalDateTime2 = Res 109 | end, 110 | case LocalDateTime2 of 111 | [{{_,_,_},{_,_,_}}, DateTimeToReturn] -> 112 | DateTimeToReturn; 113 | Other -> 114 | Other 115 | end. 116 | 117 | % tz_name(DateTime(), Timezone) -> {Abbr, Name} | {{StdAbbr, StdName}, {DstAbbr, DstName}} | unable_to_detect | {error, ErrDesc} 118 | % Timezone = String() 119 | % Abbr = String() 120 | % Name = String() 121 | % StdAbbr = String() 122 | % StdName = String() 123 | % DstAbbr = String() 124 | % DstName = String() 125 | % ErrDesc = atom(), unknown_tz 126 | tz_name(LocalDateTime, Timezone) -> 127 | case lists:keyfind(get_timezone(Timezone), 1, ?tz_database) of 128 | false -> 129 | {error, unknown_tz}; 130 | {_Tz, StdName, undef, _Shift, _DstShift, undef, _DstStartTime, undef, _DstEndTime} -> 131 | StdName; 132 | TzRule = {_, StdName, DstName, _Shift, _DstShift, _, _, _, _} -> 133 | case localtime_dst:check(LocalDateTime, TzRule) of 134 | is_in_dst -> 135 | DstName; 136 | is_not_in_dst -> 137 | StdName; 138 | ambiguous_time -> 139 | {StdName, DstName}; 140 | time_not_exists -> 141 | unable_to_detect 142 | end 143 | end. 144 | 145 | % tz_shift(LocalDateTime, Timezone) -> Shift | {Shift, DstSift} | unable_to_detect | {error, ErrDesc} 146 | % returns time shift from GMT 147 | % LocalDateTime = DateTime() 148 | % Timezone = String() 149 | % Shift = DstShift = {Sign, Hours, Minutes} 150 | % Sign = term(), '+', '-' 151 | % Hours = Minutes = Integer(), 152 | % {Shift, DstShift} - returns, when shift is ambiguous 153 | % ErrDesc = atom(), unknown_tz 154 | tz_shift(LocalDateTime, Timezone) -> 155 | case lists:keyfind(get_timezone(Timezone), 1, ?tz_database) of 156 | false -> 157 | {error, unknown_tz}; 158 | {_Tz, _StdName, undef, Shift, _DstShift, undef, _DstStartTime, undef, _DstEndTime} -> 159 | fmt_min(Shift); 160 | TzRule = {_, _StdName, _DstName, Shift, DstShift, _, _, _, _} -> 161 | case localtime_dst:check(LocalDateTime, TzRule) of 162 | is_in_dst -> 163 | fmt_min(Shift + DstShift); 164 | is_not_in_dst -> 165 | fmt_min(Shift); 166 | ambiguous_time -> 167 | {fmt_min(Shift), fmt_min(Shift + DstShift)}; 168 | time_not_exists -> 169 | unable_to_detect 170 | end 171 | end. 172 | 173 | % the same as tz_shift/2, but calculates time difference between two local timezones 174 | tz_shift(LocalDateTime, TimezoneFrom, TimezoneTo) -> 175 | F = fun() -> 176 | FromShift = fmt_shift(tz_shift(LocalDateTime, TimezoneFrom)), 177 | DateTimeTo = localtime:local_to_local(LocalDateTime, TimezoneFrom, TimezoneTo), 178 | ToShift = fmt_shift(tz_shift(DateTimeTo, TimezoneTo)), 179 | fmt_min(ToShift-FromShift) 180 | end, 181 | try F() 182 | catch 183 | _:Err -> 184 | Err 185 | end. 186 | 187 | adjust_datetime(DateTime, Minutes) -> 188 | Seconds = calendar:datetime_to_gregorian_seconds(DateTime) + Minutes * 60, 189 | calendar:gregorian_seconds_to_datetime(Seconds). 190 | 191 | get_timezone(TimeZone) -> 192 | get_timezone_inner(TimeZone). 193 | 194 | list_timezones() -> 195 | dict:fetch_keys(?tz_index). 196 | 197 | % ======================================================================= 198 | % privates 199 | % ======================================================================= 200 | 201 | invert_shift(Minutes) -> 202 | -Minutes. 203 | 204 | fmt_min(Shift) when Shift < 0 -> 205 | {'-', abs(Shift) div 60, abs(Shift) rem 60}; 206 | fmt_min(Shift) -> 207 | {'+', Shift div 60, Shift rem 60}. 208 | 209 | fmt_shift({'+', H, M}) -> 210 | H * 60 + M; 211 | fmt_shift({'-', H, M}) -> 212 | -(H * 60 + M); 213 | fmt_shift(Any) -> 214 | throw(Any). 215 | 216 | tr_char(String, From, To) -> 217 | case string:chr(String, From) of 218 | 0 -> String; % Optimize for String does not contain From. 219 | _ -> tr_char(String, From, To, []) 220 | end. 221 | tr_char([], _From, _To, Acc) -> 222 | lists:reverse(Acc); 223 | tr_char([H|T], From, To, Acc) -> 224 | case H of 225 | From -> tr_char(T, From, To, [To|Acc]); 226 | _ -> tr_char(T, From, To, [H|Acc]) 227 | end. 228 | 229 | -define(SPACE_CHAR, 32). 230 | get_timezone_inner(TimeZone) -> 231 | TimeZoneNoSpaces = tr_char(TimeZone, ?SPACE_CHAR, $_), 232 | case dict:find(TimeZoneNoSpaces, ?tz_index) of 233 | error -> 234 | TimeZoneNoSpaces; 235 | {ok, [TZName | _]} -> 236 | TZName 237 | end. 238 | 239 | -ifdef(TEST). 240 | -include_lib("eunit/include/eunit.hrl"). 241 | 242 | tr_char_test() -> 243 | ?assertEqual("ABCDE", tr_char("ABCDE", ?SPACE_CHAR, $_)), 244 | ?assertEqual("AB_DE", tr_char("AB DE", ?SPACE_CHAR, $_)), 245 | ?assertEqual("A_C_E", tr_char("A C E", ?SPACE_CHAR, $_)). 246 | 247 | get_timezone_test() -> 248 | ?assertEqual("America/Los_Angeles", get_timezone("America/Los Angeles")). 249 | 250 | tz_shift_test() -> 251 | ?assertEqual({'+',3,0}, tz_shift({{2014,1,1},{12,0,0}}, "America/Los_Angeles", "America/New_York")). 252 | 253 | -endif. % TEST 254 | -------------------------------------------------------------------------------- /src/localtime_dst.erl: -------------------------------------------------------------------------------- 1 | %% @author Dmitry S. Melnikov (dmitryme@gmail.com) 2 | %% @copyright 2010 Dmitry S. Melnikov 3 | 4 | -module(localtime_dst). 5 | 6 | -author("Dmitry Melnikov "). 7 | 8 | -include("tz_database.hrl"). 9 | -include("tz_index.hrl"). 10 | 11 | -export( 12 | [ 13 | check/2 14 | ]). 15 | 16 | -compile([export_all]). 17 | 18 | 19 | % check(DateTime, TimeZone) -> is_in_dst | is_not_in_dst | ambiguous_time | time_not_exists 20 | % DateTime = DateTime() 21 | % TimeZone = tuple() 22 | check(DateTime, Timezone) when is_list(Timezone) -> 23 | case lists:keyfind(localtime:get_timezone(Timezone), 1, ?tz_database) of 24 | false -> 25 | {error, unknown_tz}; 26 | TZ -> 27 | check(DateTime, TZ) 28 | end; 29 | check({Date = {Year, _, _},Time}, {_, _, _, _Shift, DstShift, DstStartRule, DstStartTime, DstEndRule, DstEndTime}) -> 30 | DstStartDay = get_dst_day_of_year(DstStartRule, Year), 31 | DstEndDay = get_dst_day_of_year(DstEndRule, Year), 32 | CurrDay = get_day_of_year(Date), 33 | case is_dst_date(DstStartDay, DstEndDay, CurrDay) of 34 | equal_to_start -> 35 | is_dst_start_time(time_to_minutes(Time), time_to_minutes(DstStartTime), DstShift); 36 | equal_to_end -> 37 | is_dst_end_time(time_to_minutes(Time), time_to_minutes(DstEndTime), DstShift); 38 | Res -> 39 | Res 40 | end. 41 | 42 | is_dst_start_time(CurrTime, DstStartTime, _DstShift) when CurrTime < DstStartTime -> 43 | is_not_in_dst; 44 | is_dst_start_time(CurrTime, DstStartTime, DstShift) when CurrTime >= (DstStartTime + DstShift) -> 45 | is_in_dst; 46 | is_dst_start_time(_CurrTime, _DstStartTime, _DstShift) -> 47 | time_not_exists. 48 | 49 | is_dst_end_time(CurrTime, DstEndTime, DstShift) when CurrTime < (DstEndTime - DstShift) -> 50 | is_in_dst; 51 | is_dst_end_time(CurrTime, DstEndTime, _DstShift) when CurrTime >= DstEndTime -> 52 | is_not_in_dst; 53 | is_dst_end_time(_CurrTime, _DstStartTime, _DstShift) -> 54 | ambiguous_time. 55 | 56 | is_dst_date(DstStartDay, _DstEndDay, CurrDay) when (CurrDay == DstStartDay) -> equal_to_start; 57 | is_dst_date(_DstStartDay, DstEndDay, CurrDay) when (CurrDay == DstEndDay) -> equal_to_end; 58 | is_dst_date(DstStartDay, DstEndDay, CurrDay) 59 | when (DstStartDay < DstEndDay) andalso ((CurrDay > DstStartDay) and (CurrDay < DstEndDay)) -> 60 | is_in_dst; 61 | is_dst_date(DstStartDay, DstEndDay, CurrDay) 62 | when (DstStartDay < DstEndDay) andalso ((CurrDay < DstStartDay) or (CurrDay > DstEndDay)) -> 63 | is_not_in_dst; 64 | is_dst_date(DstStartDay, DstEndDay, CurrDay) 65 | when (DstStartDay > DstEndDay) andalso ((CurrDay < DstStartDay) and (CurrDay > DstEndDay)) -> 66 | is_not_in_dst; 67 | is_dst_date(DstStartDay, DstEndDay, CurrDay) 68 | when (DstStartDay > DstEndDay) andalso ((CurrDay > DstStartDay) or (CurrDay < DstEndDay)) -> 69 | is_in_dst. 70 | 71 | get_dst_day_of_year({WeekDay,DayOfWeek,Month}, Year) when (WeekDay == last) or (WeekDay == 5) -> 72 | IntMonth = month_to_int(Month), 73 | IntDayOfWeek = day_to_int(DayOfWeek), 74 | get_last_dst(IntDayOfWeek, IntMonth, Year); 75 | get_dst_day_of_year({WeekDay,DayOfWeek,Month}, Year) when (WeekDay > 0) and (WeekDay =< 4) -> 76 | IntMonth = month_to_int(Month), 77 | IntDayOfWeek = day_to_int(DayOfWeek), 78 | DstDays = get_day_of_year({Year, IntMonth, 1}), 79 | DstDayOfWeek = calendar:day_of_the_week({Year, IntMonth, 1}), 80 | case (DstDayOfWeek =:= IntDayOfWeek) and (WeekDay =:= 1) of 81 | true -> 82 | DstDays; 83 | false -> 84 | AdjustedDstDays = 85 | case IntDayOfWeek >= DstDayOfWeek of 86 | true -> 87 | DstDays + (IntDayOfWeek - DstDayOfWeek); 88 | false -> 89 | DstDays + (7 - DstDayOfWeek) + IntDayOfWeek 90 | end, 91 | AdjustedDstDays + (WeekDay - 1) * 7 92 | end; 93 | get_dst_day_of_year(_, _) -> 94 | throw({error, wrong_week_day}). 95 | 96 | get_last_dst(IntDayOfWeek, IntMonth, Year) -> 97 | MonthLastDays = calendar:date_to_gregorian_days(Year, IntMonth, 1) + calendar:last_day_of_the_month(Year, IntMonth), 98 | MonthLastDate = calendar:gregorian_days_to_date(MonthLastDays), 99 | MonthLastDayOfWeek = calendar:day_of_the_week(MonthLastDate), 100 | case MonthLastDayOfWeek > IntDayOfWeek of 101 | true -> 102 | MonthLastDays - (MonthLastDayOfWeek - IntDayOfWeek) - calendar:date_to_gregorian_days({Year - 1, 12, 31}); 103 | false -> 104 | MonthLastDays - MonthLastDayOfWeek - (7 - IntDayOfWeek) - calendar:date_to_gregorian_days({Year - 1, 12, 31}) 105 | end. 106 | 107 | get_day_of_year(Date = {Year, _Month, _Day}) -> 108 | calendar:date_to_gregorian_days(Date) - calendar:date_to_gregorian_days({Year - 1, 12, 31}). 109 | 110 | month_to_int(jan) -> 1; 111 | month_to_int(feb) -> 2; 112 | month_to_int(mar) -> 3; 113 | month_to_int(apr) -> 4; 114 | month_to_int(may) -> 5; 115 | month_to_int(jun) -> 6; 116 | month_to_int(jul) -> 7; 117 | month_to_int(aug) -> 8; 118 | month_to_int(sep) -> 9; 119 | month_to_int(oct) -> 10; 120 | month_to_int(nov) -> 11; 121 | month_to_int(dec) -> 12. 122 | 123 | day_to_int(mon) -> 1; 124 | day_to_int(tue) -> 2; 125 | day_to_int(wed) -> 3; 126 | day_to_int(thu) -> 4; 127 | day_to_int(fri) -> 5; 128 | day_to_int(sat) -> 6; 129 | day_to_int(sun) -> 7. 130 | 131 | time_to_minutes({Hours, Minutes}) -> 132 | Hours * 60 + Minutes; 133 | time_to_minutes({Hours, Minutes, _Seconds}) -> 134 | Hours * 60 + Minutes. 135 | 136 | -ifdef(TEST). 137 | -include_lib("eunit/include/eunit.hrl"). 138 | 139 | get_day_of_year_test() -> 140 | ?assertEqual(62, get_dst_day_of_year({1,wed,mar}, 2010)). 141 | 142 | check_test() -> 143 | Tz = {"Europe/Moscow",{"MSK","MSK"},{"MSD","MSD"},180,60,{last,sun,mar},{2,0},{last,sun,oct},{3,0}}, 144 | ?assertEqual(is_not_in_dst, localtime_dst:check({{2010, 1, 1}, {10, 10, 0}}, Tz)), 145 | ?assertEqual(is_in_dst, check({{2010, 7, 8}, {10, 10, 0}}, Tz)), 146 | ?assertEqual(is_not_in_dst, check({{2010, 3, 28}, {1, 59, 0}}, Tz)), 147 | ?assertEqual(time_not_exists, check({{2010, 3, 28}, {2, 00, 0}}, Tz)), 148 | ?assertEqual(time_not_exists, check({{2010, 3, 28}, {2, 15, 0}}, Tz)), 149 | ?assertEqual(time_not_exists, check({{2010, 3, 28}, {2, 30, 0}}, Tz)), 150 | ?assertEqual(time_not_exists, check({{2010, 3, 28}, {2, 59, 0}}, Tz)), 151 | ?assertEqual(is_in_dst, check({{2010, 3, 28}, {3, 00, 0}}, Tz)), 152 | 153 | ?assertEqual(is_in_dst, check({{2010, 10, 31}, {1, 59, 0}}, Tz)), 154 | ?assertEqual(ambiguous_time, check({{2010, 10, 31}, {2, 00, 0}}, Tz)), 155 | ?assertEqual(ambiguous_time, check({{2010, 10, 31}, {2, 10, 0}}, Tz)), 156 | ?assertEqual(ambiguous_time, check({{2010, 10, 31}, {2, 30, 0}}, Tz)), 157 | ?assertEqual(ambiguous_time, check({{2010, 10, 31}, {2, 59, 0}}, Tz)), 158 | ?assertEqual(is_not_in_dst, check({{2010, 10, 31}, {3, 00, 0}}, Tz)), 159 | 160 | %% DST starts at hour 24; DST ends at hour 0: 161 | TzGaza = {"Asia/Gaza",{"EET","EET"},{"EEST","EEST"},120,60,{last,thu,mar},{24,0},{4,fri,sep},{0,0}}, 162 | ?assertEqual(is_not_in_dst, check({{2014, 3, 27}, {23, 59, 59}}, TzGaza)), 163 | %% Currently ST->DT transitions in the last hour of the day are not handled correctly. 164 | %?assertEqual(time_not_exists, check({{2014, 3, 28}, { 0, 00, 00}}, TzGaza)), 165 | %?assertEqual(time_not_exists, check({{2014, 3, 28}, { 0, 59, 59}}, TzGaza)), 166 | ?assertEqual(is_in_dst, check({{2014, 3, 28}, { 0, 59, 59}}, TzGaza)), % WRONG 167 | ?assertEqual(is_in_dst, check({{2014, 3, 28}, { 1, 00, 00}}, TzGaza)), 168 | ?assertEqual(is_in_dst, check({{2014, 9, 25}, {22, 59, 59}}, TzGaza)), 169 | %% Currently DT->ST transitions in the first hour of the day are not handled correctly. 170 | %?assertEqual(ambiguous_time, check({{2014, 9, 25}, {23, 00, 00}}, TzGaza)), 171 | %?assertEqual(ambiguous_time, check({{2014, 9, 25}, {23, 59, 59}}, TzGaza)), 172 | ?assertEqual(is_in_dst, check({{2014, 9, 25}, {23, 59, 59}}, TzGaza)), % WRONG 173 | ?assertEqual(is_not_in_dst, check({{2014, 9, 26}, { 0, 00, 00}}, TzGaza)), 174 | 175 | %% DST starts at hour 0; DST ends at hour 0. 176 | TzDamascus = {"Asia/Damascus",{"EET","EET"},{"EEST","EEST"},120,60,{last,fri,mar},{0,0},{last,fri,oct},{0,0}}, 177 | ?assertEqual(is_not_in_dst, check({{2014, 3, 27}, {23, 59, 59}}, TzDamascus)), 178 | ?assertEqual(time_not_exists, check({{2014, 3, 28}, { 0, 00, 00}}, TzDamascus)), 179 | ?assertEqual(time_not_exists, check({{2014, 3, 28}, { 0, 59, 59}}, TzDamascus)), 180 | ?assertEqual(is_in_dst, check({{2014, 3, 28}, { 1, 00, 00}}, TzDamascus)), 181 | ?assertEqual(is_in_dst, check({{2014, 10, 30}, {22, 59, 59}}, TzDamascus)), 182 | %% Currently DT->ST transitions in the first hour of the day are not handled correctly. 183 | %?assertEqual(ambiguous_time, check({{2014, 10, 30}, {23, 00, 00}}, TzDamascus)), 184 | %?assertEqual(ambiguous_time, check({{2014, 10, 30}, {23, 59, 59}}, TzDamascus)), 185 | ?assertEqual(is_not_in_dst, check({{2014, 10, 31}, { 0, 00, 00}}, TzDamascus)), 186 | 187 | %% DST ends before starts (southern hemisphere): 188 | TzMontevideo = {"America/Montevideo",{"UYT","UYT"},{"UYST","UYST"},-180,60,{1,sun,oct},{2,0},{2,sun,mar},{2,0}}, 189 | ?assertEqual(is_in_dst, check({{2014, 3, 09}, { 0, 59, 59}}, TzMontevideo)), 190 | ?assertEqual(ambiguous_time, check({{2014, 3, 09}, { 1, 00, 00}}, TzMontevideo)), 191 | ?assertEqual(ambiguous_time, check({{2014, 3, 09}, { 1, 59, 59}}, TzMontevideo)), 192 | ?assertEqual(is_not_in_dst, check({{2014, 3, 09}, { 2, 00, 00}}, TzMontevideo)), 193 | ?assertEqual(is_not_in_dst, check({{2014, 10, 05}, { 1, 59, 59}}, TzMontevideo)), 194 | ?assertEqual(time_not_exists, check({{2014, 10, 05}, { 2, 00, 00}}, TzMontevideo)), 195 | ?assertEqual(time_not_exists, check({{2014, 10, 05}, { 2, 59, 59}}, TzMontevideo)), 196 | ?assertEqual(is_in_dst, check({{2014, 10, 05}, { 3, 00, 00}}, TzMontevideo)), 197 | 198 | true. 199 | 200 | -endif. 201 | --------------------------------------------------------------------------------