1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
| /* Copyright (C) 2023-2024 Johannes Krude
|
| This file is part of Gadgetbridge.
|
| Gadgetbridge is free software: you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation, either version 3 of the License, or
| (at your option) any later version.
|
| Gadgetbridge is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU Affero General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
| package nodomain.freeyourgadget.gadgetbridge.service.devices.casio;
|
| import java.util.Set;
| import java.util.HashSet;
| import java.util.Map;
| import java.util.Arrays;
| import java.nio.charset.StandardCharsets;
| import java.time.DayOfWeek;
| import java.time.Instant;
| import java.time.LocalTime;
| import java.time.Month;
| import java.time.ZoneId;
| import java.time.ZoneOffset;
| import java.time.zone.ZoneOffsetTransition;
| import java.time.zone.ZoneOffsetTransitionRule;
| import java.time.zone.ZoneRules;
|
|
| public class CasioTimeZone {
|
| /*
| There are six clocks on the Casio GW-B5600 / S100
| 0 is the main clock
| 1-5 are the world clocks
|
| 0x1d 00 01 DST0 DST1 TZ0A TZ0B TZ1A TZ1B ff ff ff ff ff
| 0x1d 02 03 DST2 DST3 TZ2A TZ2B TZ3A TZ3B ff ff ff ff ff
| 0x1d 04 05 DST4 DST5 TZ4A TZ4B TZ5A TZ5B ff ff ff ff ff
| DST: bitwise flags; bit0: DST on, bit1: DST auto
|
| 0x1e 0-5 TZ_A TZ_B TZ_OFF TZ_DSTOFF TZ_DSTRULES
| A/B seem to be ignored by the watch
| OFF & DSTOFF in 15 minute intervals
|
| 0x1f 0-5 (18 bytes ASCII TZ name)
|
| Timezones selectable on the watch:
| A B OFF DSTOFF DSTRULES
| BAKER ISLAND 39 01 D0 04 00
| PAGO PAGO D7 00 D4 04 00
| HONOLULU 7B 00 D8 04 00
| MARQUESAS ISLANDS 3A 01 DA 04 00
| ANCHORAGE 0C 00 DC 04 01
| LOS ANGELES A1 00 E0 04 01
| DENVER 54 00 E4 04 01
| CHICAGO 42 00 E8 04 01
| NEW YORK CA 00 EC 04 01
| HALIFAX 71 00 F0 04 01
| ST.JOHN'S 0C 01 F2 04 01
| RIO DE JANEIRO F1 00 F4 04 00
| F.DE NORONHA 62 00 F8 04 00
| PRAIA E9 00 FC 04 00
| UTC 00 00 00 00 00
| LONDON A0 00 00 04 02
| PARIS DC 00 04 04 02
| ATHENS 13 00 08 04 02
| JEDDAH 85 00 0C 04 00
| TEHRAN 16 01 0E 04 2B
| DUBAI 5B 00 10 04 00
| KABUL 88 00 12 04 00
| KARACHI 8B 00 14 04 00
| DELHI 52 00 16 04 00
| KATHMANDU 8C 00 17 04 00
| DHAKA 56 00 18 04 00
| YANGON 2F 01 1A 04 00
| BANGKOK 1C 00 1C 04 00
| HONG KONG 7A 00 20 04 00
| PYONGYANG EA 00 24 04 00
| EUCLA 36 01 23 04 00
| TOKYO 19 01 24 04 00
| ADELAIDE 05 00 26 04 04
| SYDNEY 0F 01 28 04 04
| LORD HOWE ISLAND 37 01 2A 02 12
| NOUMEA CD 00 2C 04 00
| WELLINGTON 2B 01 30 04 05
| CHATHAM ISLANDS 3F 00 33 04 17
| NUKUALOFA D0 00 34 04 00
| KIRITIMATI 93 00 38 04 00
|
| Timezones NOT selectable on the watch:
| A B OFF DSTOFF DSTRULES
| CASABLANCA 3A 00 00 04 0F
| BEIRUT 22 00 08 04 0C
| JERUSALEM 86 00 08 04 2A
| NORFOLK ISLAND 38 01 2C 04 04
| EASTER ISLAND 5E 00 E8 04 1C
| HAVANA 75 00 EC 04 15
| SANTIAGO 02 01 F0 04 1B
| ASUNCION 12 00 F0 04 09
| PONTA DELGADA E4 00 FC 04 02
|
| */
|
| private byte[] name;
| private byte[] number;
| private byte offset;
| private byte dstOffset;
| private byte dstRules;
| private byte dstSetting;
|
| // bitwise flags
| final static byte DST_SETTING_ON = 1;
| final static byte DST_SETTING_AUTO = 2;
|
| private CasioTimeZone(byte[] name, byte[] number, byte offset, byte dstOffset, byte dstRules, byte dstSetting) {
| this.name = name;
| this.number = number;
| this.offset = offset;
| this.dstOffset = dstOffset;
| this.dstRules = dstRules;
| this.dstSetting = dstSetting;
| }
|
| static public Set<Casio2C2DSupport.FeatureRequest> requests(int slot) {
| HashSet<Casio2C2DSupport.FeatureRequest> requests = new HashSet();
| requests.add(new Casio2C2DSupport.FeatureRequest(Casio2C2DSupport.FEATURE_DST_WATCH_STATE, (byte) (slot/2*2)));
| requests.add(new Casio2C2DSupport.FeatureRequest(Casio2C2DSupport.FEATURE_DST_SETTING, (byte) slot));
| requests.add(new Casio2C2DSupport.FeatureRequest(Casio2C2DSupport.FEATURE_WORLD_CITY, (byte) slot));
| return requests;
| }
|
| static public byte[] dstWatchStateBytes(int slotA, CasioTimeZone zoneA, int slotB, CasioTimeZone zoneB) {
| return new byte[] {
| Casio2C2DSupport.FEATURE_DST_WATCH_STATE,
| (byte) slotA,
| (byte) slotB,
| zoneA.dstSetting,
| zoneB.dstSetting,
| zoneA.number[0],
| zoneA.number[1],
| zoneB.number[0],
| zoneB.number[1],
| (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff};
| }
|
| public byte[] dstSettingBytes(int slot) {
| return new byte[] {
| Casio2C2DSupport.FEATURE_DST_SETTING,
| (byte) slot,
| number[0],
| number[1],
| offset,
| dstOffset,
| dstRules};
| }
|
| public byte[] worldCityBytes(int slot) {
| byte[] bytes = {
| Casio2C2DSupport.FEATURE_WORLD_CITY,
| (byte) slot,
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
| System.arraycopy(name, 0, bytes, 2, Math.min(name.length, 18));
| return bytes;
| }
|
| public static CasioTimeZone fromWatchResponses(Map<Casio2C2DSupport.FeatureRequest, byte[]> responses, int slot) {
| byte[] name = "unknown".getBytes(StandardCharsets.US_ASCII);
| byte[] number = {0,0};
| byte offset = 0;
| byte dstOffset = 0;
| byte dstRules = 0;
| byte dstSetting = 0;
|
| for (byte[] response: responses.values()) {
| if (response[0] == Casio2C2DSupport.FEATURE_DST_WATCH_STATE && response.length >= 9) {
| if (response[1] == slot) {
| dstSetting = response[3];
| number = new byte[] {response[5], response[6]};
| }
| if (response[2] == slot) {
| dstSetting = response[4];
| number = new byte[] {response[7], response[8]};
| }
| } else if (response[0] == Casio2C2DSupport.FEATURE_DST_SETTING && response.length >= 7 && response[1] == slot) {
| number = new byte[] {response[2], response[3]};
| offset = response[4];
| dstOffset = response[5];
| dstRules = response[6];
| } else if (response[0] == Casio2C2DSupport.FEATURE_WORLD_CITY && response.length >= 2 && response[1] == slot) {
| int size;
| for (size = 0; size < response.length-2; size++) {
| if (response[2+size] == 0) {
| break;
| }
| }
| name = Arrays.copyOfRange(response, 2, 2+size);
| }
| }
|
| return new CasioTimeZone(name, number, offset, dstOffset, dstRules, dstSetting);
| }
|
| public static CasioTimeZone fromZoneId(ZoneId zone, Instant time, String zoneName) {
| ZoneRules rules = zone.getRules();
|
| byte[] name = zoneName.getBytes(StandardCharsets.US_ASCII);
| byte[] number = {0,0};
| byte offset = (byte) (rules.getStandardOffset(time).getTotalSeconds() / 60 / 15);
| byte dstOffset = 0; // can be set only later once we now the next transition
| byte dstRules = 0;
| byte dstSetting = 0;
|
| ZoneOffsetTransition next = rules.nextTransition(time);
| int nextYear = next.getInstant().atZone(zone).getYear();
| ZoneOffsetTransition next2 = (next == null ? null: rules.nextTransition(next.getInstant()));
| int next2Year = (next2 == null ? 0 : next2.getInstant().atZone(zone).getYear());
|
| if (next == null) {
| // no DST is easy
| dstSetting = DST_SETTING_AUTO;
| } else {
| // we need an Instant with DST on to get the dstOffset
| if (rules.isDaylightSavings(time)) {
| dstOffset = (byte) (rules.getDaylightSavings(time).getSeconds() / 60 / 15);
| } else {
| dstOffset = (byte) (rules.getDaylightSavings(next.getInstant().plusSeconds(1)).getSeconds() / 60 / 15);
| }
| // find Watch DST rules
| dstRules = findWatchDstRules(offset, dstOffset, next, nextYear, next2, next2Year);
| if (dstRules != 0) {
| // DST AUTO if the watch knows at least the next transition
| // otherwise will result in incorrect time between actual DST change and next sync
| dstSetting |= DST_SETTING_AUTO;
| }
| // if DST bit is incorrect, the watch will substract or add time
| if (rules.isDaylightSavings(time)) {
| dstSetting |= DST_SETTING_ON;
| }
| }
|
| return new CasioTimeZone(name, number, offset, dstOffset, dstRules, dstSetting);
| }
|
| // We are searching for watch DST rules which match the next two transitions.
| // In case only the next transition matches a rule, the rule is still used
| static byte findWatchDstRules(byte offset, byte dstOffset, ZoneOffsetTransition next, int nextYear, ZoneOffsetTransition next2, int next2Year) {
| WatchDstRules candidate = null;
| for (WatchDstRules r: watchDstRules) {
| int match = r.matches(offset, dstOffset, next, nextYear, next2, next2Year);
| if (match == 2)
| return r.dstRules;
| if (match == 1 && candidate == null)
| candidate = r;
| }
| if (candidate != null)
| return candidate.dstRules;
| return (byte) 0;
| }
|
| static class WatchDstRules {
| final byte offset;
| final byte dstOffset;
| final byte dstRules;
| final ZoneOffsetTransitionRule ruleA;
| final ZoneOffsetTransitionRule ruleB;
|
| WatchDstRules(int offset, int dstOffset, int dstRules, ZoneOffsetTransitionRule ruleA, ZoneOffsetTransitionRule ruleB) {
| this.offset = (byte) offset;
| this.dstOffset = (byte) dstOffset;
| this.dstRules = (byte) dstRules;
| this.ruleA = ruleA;
| this.ruleB = ruleB;
| }
|
| // returns how many of the next transitions match the rules
| int matches(byte offset, byte dstOffset, ZoneOffsetTransition next, int nextYear, ZoneOffsetTransition next2, int next2Year) {
| if (offset != this.offset || dstOffset != this.dstOffset)
| return -1;
| if (this.ruleA.createTransition(nextYear).equals(next)) {
| if (this.ruleB.createTransition(next2Year).equals(next2))
| return 2;
| return 1;
| }
| if (this.ruleB.createTransition(nextYear).equals(next)) {
| if (this.ruleA.createTransition(next2Year).equals(next2))
| return 2;
| return 1;
| }
| return 0;
| }
| }
|
| // All known Watch DST Rules
| // Possibly incomplete and incorrect
| //
| // When adding new WatchDstRules, test them:
| // 1. Apply the following changes to CasioGWB5600InitOperation
| // + static int nextNext = 0;
| // private void setClocks(TransactionBuilder builder) {
| // ZoneId tz = ZoneId.systemDefault();
| // Instant now = Instant.now().plusSeconds(2);
| // + now = tz.getRules().nextTransition(now).getInstant();
| // + if (nextNext != 0)
| // + now = tz.getRules().nextTransition(now).getInstant();
| // + nextNext ^= 1;
| // + now = now.minusSeconds(10);
| // 2. Sync the time on the watch and observe a DST change
| // 3. Repeat the time sync to obseve a second DST change
| static final WatchDstRules[] watchDstRules = {
| // Europe/London
| new WatchDstRules(0x00, 0x04, 0x02,
| ZoneOffsetTransitionRule.of(Month.MARCH, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(0), ZoneOffset.ofTotalSeconds(0), ZoneOffset.ofTotalSeconds(3600)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(0), ZoneOffset.ofTotalSeconds(3600), ZoneOffset.ofTotalSeconds(0))),
| // Europe/Paris
| new WatchDstRules(0x04, 0x04, 0x02,
| ZoneOffsetTransitionRule.of(Month.MARCH, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(3600), ZoneOffset.ofTotalSeconds(3600), ZoneOffset.ofTotalSeconds(7200)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(3600), ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(3600))),
| // Europe/Athen
| new WatchDstRules(0x08, 0x04, 0x02,
| ZoneOffsetTransitionRule.of(Month.MARCH, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(10800)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(10800), ZoneOffset.ofTotalSeconds(7200))),
| // Asia/Beirut
| new WatchDstRules(0x08, 0x04, 0x0C,
| ZoneOffsetTransitionRule.of(Month.MARCH, 25, DayOfWeek.SUNDAY, LocalTime.of(0, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(10800)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 25, DayOfWeek.SUNDAY, LocalTime.of(0, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(10800), ZoneOffset.ofTotalSeconds(7200))),
| // Asia/Jerusalem
| new WatchDstRules(0x08, 0x04, 0x2A,
| ZoneOffsetTransitionRule.of(Month.MARCH, 23, DayOfWeek.FRIDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(10800)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 25, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(7200), ZoneOffset.ofTotalSeconds(10800), ZoneOffset.ofTotalSeconds(7200))),
| // Australia/Adelaide
| new WatchDstRules(0x26, 0x04, 0x04,
| ZoneOffsetTransitionRule.of(Month.APRIL, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(34200), ZoneOffset.ofTotalSeconds(37800), ZoneOffset.ofTotalSeconds(34200)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(34200), ZoneOffset.ofTotalSeconds(34200), ZoneOffset.ofTotalSeconds(37800))),
| // Australia/Sydney
| new WatchDstRules(0x28, 0x04, 0x04,
| ZoneOffsetTransitionRule.of(Month.APRIL, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(36000), ZoneOffset.ofTotalSeconds(39600), ZoneOffset.ofTotalSeconds(36000)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(36000), ZoneOffset.ofTotalSeconds(36000), ZoneOffset.ofTotalSeconds(39600))),
| // Australia/Lord_Howe
| new WatchDstRules(0x2A, 0x02, 0x12,
| ZoneOffsetTransitionRule.of(Month.APRIL, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(37800), ZoneOffset.ofTotalSeconds(39600), ZoneOffset.ofTotalSeconds(37800)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(37800), ZoneOffset.ofTotalSeconds(37800), ZoneOffset.ofTotalSeconds(39600))),
| // Pacific/Norfolk
| new WatchDstRules(0x2C, 0x04, 0x04,
| ZoneOffsetTransitionRule.of(Month.APRIL, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(39600), ZoneOffset.ofTotalSeconds(43200), ZoneOffset.ofTotalSeconds(39600)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(39600), ZoneOffset.ofTotalSeconds(39600), ZoneOffset.ofTotalSeconds(43200))),
| // Pacific/Auckland
| new WatchDstRules(0x30, 0x04, 0x05,
| ZoneOffsetTransitionRule.of(Month.APRIL, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(43200), ZoneOffset.ofTotalSeconds(46800), ZoneOffset.ofTotalSeconds(43200)),
| ZoneOffsetTransitionRule.of(Month.SEPTEMBER, 24, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(43200), ZoneOffset.ofTotalSeconds(43200), ZoneOffset.ofTotalSeconds(46800))),
| // Pacific/Chatham
| new WatchDstRules(0x33, 0x04, 0x17,
| ZoneOffsetTransitionRule.of(Month.APRIL, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 45), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(45900), ZoneOffset.ofTotalSeconds(49500), ZoneOffset.ofTotalSeconds(45900)),
| ZoneOffsetTransitionRule.of(Month.SEPTEMBER, 24, DayOfWeek.SUNDAY, LocalTime.of(2, 45), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(45900), ZoneOffset.ofTotalSeconds(45900), ZoneOffset.ofTotalSeconds(49500))),
| // America/Anchorage
| new WatchDstRules(0xDC, 0x04, 0x01,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-32400), ZoneOffset.ofTotalSeconds(-32400), ZoneOffset.ofTotalSeconds(-28800)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-32400), ZoneOffset.ofTotalSeconds(-28800), ZoneOffset.ofTotalSeconds(-32400))),
| // America/Los_Angeles
| new WatchDstRules(0xE0, 0x04, 0x01,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-28800), ZoneOffset.ofTotalSeconds(-28800), ZoneOffset.ofTotalSeconds(-25200)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-28800), ZoneOffset.ofTotalSeconds(-25200), ZoneOffset.ofTotalSeconds(-28800))),
| // America/Denver
| new WatchDstRules(0xE4, 0x04, 0x01,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-25200), ZoneOffset.ofTotalSeconds(-25200), ZoneOffset.ofTotalSeconds(-21600)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-25200), ZoneOffset.ofTotalSeconds(-21600), ZoneOffset.ofTotalSeconds(-25200))),
| // America/Chicago
| new WatchDstRules(0xE8, 0x04, 0x01,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-21600), ZoneOffset.ofTotalSeconds(-21600), ZoneOffset.ofTotalSeconds(-18000)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-21600), ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-21600))),
| // Chile/EasterIsland
| new WatchDstRules(0xE8, 0x04, 0x1C,
| ZoneOffsetTransitionRule.of(Month.APRIL, 2, DayOfWeek.SUNDAY, LocalTime.of(3, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(-21600), ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-21600)),
| ZoneOffsetTransitionRule.of(Month.SEPTEMBER, 2, DayOfWeek.SUNDAY, LocalTime.of(4, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(-21600), ZoneOffset.ofTotalSeconds(-21600), ZoneOffset.ofTotalSeconds(-18000))),
| // America/New_York
| new WatchDstRules(0xEC, 0x04, 0x01,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-14400)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-18000))),
| // America/Havana
| new WatchDstRules(0xEC, 0x04, 0x15,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(0, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-14400)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(0, 0), false, ZoneOffsetTransitionRule.TimeDefinition.STANDARD, ZoneOffset.ofTotalSeconds(-18000), ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-18000))),
| // America/Santiago
| new WatchDstRules(0xF0, 0x04, 0x1B,
| ZoneOffsetTransitionRule.of(Month.APRIL, 2, DayOfWeek.SUNDAY, LocalTime.of(3, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-10800), ZoneOffset.ofTotalSeconds(-14400)),
| ZoneOffsetTransitionRule.of(Month.SEPTEMBER, 2, DayOfWeek.SUNDAY, LocalTime.of(4, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-10800))),
| // America/Halifax
| new WatchDstRules(0xF0, 0x04, 0x01,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-10800)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-10800), ZoneOffset.ofTotalSeconds(-14400))),
| // America/Asuncion
| new WatchDstRules(0xF0, 0x04, 0x09,
| ZoneOffsetTransitionRule.of(Month.MARCH, 22, DayOfWeek.SUNDAY, LocalTime.of(0, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-10800), ZoneOffset.ofTotalSeconds(-14400)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 1, DayOfWeek.SUNDAY, LocalTime.of(0, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-14400), ZoneOffset.ofTotalSeconds(-10800))),
| // America/St_Johns
| new WatchDstRules(0xF2, 0x04, 0x01,
| ZoneOffsetTransitionRule.of(Month.MARCH, 8, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-12600), ZoneOffset.ofTotalSeconds(-12600), ZoneOffset.ofTotalSeconds(-9000)),
| ZoneOffsetTransitionRule.of(Month.NOVEMBER, 1, DayOfWeek.SUNDAY, LocalTime.of(2, 0), false, ZoneOffsetTransitionRule.TimeDefinition.WALL, ZoneOffset.ofTotalSeconds(-12600), ZoneOffset.ofTotalSeconds(-9000), ZoneOffset.ofTotalSeconds(-12600))),
| // Atlantic/Azores
| new WatchDstRules(0xFC, 0x04, 0x02,
| ZoneOffsetTransitionRule.of(Month.MARCH, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(-3600), ZoneOffset.ofTotalSeconds(-3600), ZoneOffset.ofTotalSeconds(0)),
| ZoneOffsetTransitionRule.of(Month.OCTOBER, 25, DayOfWeek.SUNDAY, LocalTime.of(1, 0), false, ZoneOffsetTransitionRule.TimeDefinition.UTC, ZoneOffset.ofTotalSeconds(-3600), ZoneOffset.ofTotalSeconds(0), ZoneOffset.ofTotalSeconds(-3600))),
| };
| }
|
|