@@ -47,11 +47,95 @@ struct TzRule {
47
47
48
48
#[ derive( Debug ) ]
49
49
struct TzRuleDate {
50
- month : i8 ,
51
50
day : i8 ,
52
51
day_of_week : i8 ,
53
- seconds_of_day : i32 ,
54
- time_mode : i8 ,
52
+ month : u8 ,
53
+ millis_of_day : u32 ,
54
+ time_mode : TimeMode ,
55
+ mode : RuleMode ,
56
+ }
57
+
58
+ #[ derive( Debug ) ]
59
+ enum TimeMode {
60
+ Wall = 0 ,
61
+ Standard = 1 ,
62
+ Utc = 2 ,
63
+ }
64
+
65
+ #[ derive( Debug , PartialEq ) ]
66
+ #[ allow( non_camel_case_types) ]
67
+ enum RuleMode {
68
+ DOW_IN_MONTH ,
69
+ DOM ,
70
+ DOW_GE_DOM ,
71
+ DOW_LE_DOM ,
72
+ }
73
+
74
+ impl TzRuleDate {
75
+ fn new (
76
+ mut day : i8 ,
77
+ mut day_of_week : i8 ,
78
+ month : u8 ,
79
+ millis_of_day : u32 ,
80
+ time_mode : i8 ,
81
+ ) -> Option < Self > {
82
+ const GREGORIAN_MONTHS : [ i8 ; 12 ] = [ 31 , 29 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 ] ;
83
+
84
+ if day == 0 {
85
+ return None ;
86
+ }
87
+ if month > 11 {
88
+ return None ;
89
+ }
90
+ if millis_of_day > 24 * 60 * 60 * 1000 {
91
+ return None ;
92
+ }
93
+
94
+ let time_mode = match time_mode {
95
+ 0 => TimeMode :: Wall ,
96
+ 1 => TimeMode :: Standard ,
97
+ 2 => TimeMode :: Utc ,
98
+ _ => return None ,
99
+ } ;
100
+
101
+ let mode;
102
+
103
+ if day_of_week == 0 {
104
+ mode = RuleMode :: DOM ;
105
+ } else {
106
+ if day_of_week > 0 {
107
+ mode = RuleMode :: DOW_IN_MONTH
108
+ } else {
109
+ day_of_week = -day_of_week;
110
+ if day > 0 {
111
+ mode = RuleMode :: DOW_GE_DOM ;
112
+ } else {
113
+ day = -day;
114
+ mode = RuleMode :: DOW_LE_DOM ;
115
+ }
116
+ }
117
+ if day_of_week > 7 {
118
+ return None ;
119
+ }
120
+ }
121
+
122
+ if mode == RuleMode :: DOW_IN_MONTH {
123
+ if !( -5 ..=5 ) . contains ( & day) {
124
+ return None ;
125
+ }
126
+ } else if day < 1 || day > GREGORIAN_MONTHS [ month as usize ] {
127
+ return None ;
128
+ }
129
+
130
+ Some ( Self {
131
+ day,
132
+ day_of_week,
133
+ month,
134
+ millis_of_day,
135
+ time_mode,
136
+ mode,
137
+ } )
138
+ }
55
139
}
56
140
57
141
impl < ' de > Deserialize < ' de > for ZoneInfo64 < ' de > {
@@ -191,20 +275,22 @@ impl<'de> Deserialize<'de> for ZoneInfo64<'de> {
191
275
key,
192
276
TzRule {
193
277
additional_offset_secs : value[ 10 ] ,
194
- start : TzRuleDate {
195
- month : value[ 0 ] as i8 ,
196
- day : value[ 1 ] as i8 ,
197
- day_of_week : value[ 2 ] as i8 ,
198
- seconds_of_day : value[ 3 ] ,
199
- time_mode : value[ 4 ] as i8 ,
200
- } ,
201
- end : TzRuleDate {
202
- month : value[ 5 ] as i8 ,
203
- day : value[ 6 ] as i8 ,
204
- day_of_week : value[ 7 ] as i8 ,
205
- seconds_of_day : value[ 8 ] ,
206
- time_mode : value[ 9 ] as i8 ,
207
- } ,
278
+ start : TzRuleDate :: new (
279
+ value[ 1 ] as i8 ,
280
+ value[ 2 ] as i8 ,
281
+ value[ 0 ] as u8 ,
282
+ value[ 3 ] as u32 ,
283
+ value[ 4 ] as i8 ,
284
+ )
285
+ . unwrap ( ) ,
286
+ end : TzRuleDate :: new (
287
+ value[ 6 ] as i8 ,
288
+ value[ 7 ] as i8 ,
289
+ value[ 5 ] as u8 ,
290
+ value[ 8 ] as u32 ,
291
+ value[ 9 ] as i8 ,
292
+ )
293
+ . unwrap ( ) ,
208
294
} ,
209
295
) ) ;
210
296
}
@@ -445,14 +531,16 @@ impl Rule<'_> {
445
531
let _ = self . inner . start . month ;
446
532
let _ = self . inner . start . day ;
447
533
let _ = self . inner . start . day_of_week ;
448
- let _ = self . inner . start . seconds_of_day ;
534
+ let _ = self . inner . start . millis_of_day ;
449
535
let _ = self . inner . start . time_mode ;
536
+ let _ = self . inner . start . mode ;
450
537
451
538
let _ = self . inner . end . month ;
452
539
let _ = self . inner . end . day ;
453
540
let _ = self . inner . end . day_of_week ;
454
- let _ = self . inner . end . seconds_of_day ;
541
+ let _ = self . inner . end . millis_of_day ;
455
542
let _ = self . inner . end . time_mode ;
543
+ let _ = self . inner . end . mode ;
456
544
457
545
Transition {
458
546
transition,
0 commit comments