@@ -30,8 +30,9 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two)
30
30
{
31
31
timelib_rel_time * rt ;
32
32
timelib_time * swp ;
33
- timelib_sll dst_corr = 0 ,dst_h_corr = 0 , dst_m_corr = 0 ;
34
- timelib_time one_backup , two_backup ;
33
+ timelib_sll dst_corr = 0 , dst_h_corr = 0 , dst_m_corr = 0 ;
34
+ timelib_time_offset * trans = NULL ;
35
+
35
36
36
37
rt = timelib_rel_time_ctor ();
37
38
rt -> invert = 0 ;
@@ -45,23 +46,10 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two)
45
46
rt -> invert = 1 ;
46
47
}
47
48
48
- /* Calculate correction for DST change over, but only if the TZ type is ID
49
- * and it's the same */
50
- if (one -> zone_type == 3 && two -> zone_type == 3
51
- && (strcmp (one -> tz_info -> name , two -> tz_info -> name ) == 0 )
52
- && (one -> z != two -> z ))
53
- {
54
- dst_corr = two -> z - one -> z ;
55
- dst_h_corr = dst_corr / 3600 ;
56
- dst_m_corr = (dst_corr % 3600 ) / 60 ;
57
- }
58
-
59
- /* Save old TZ info */
60
- memcpy (& one_backup , one , sizeof (one_backup ));
61
- memcpy (& two_backup , two , sizeof (two_backup ));
62
-
63
- timelib_apply_localtime (one , 0 );
64
- timelib_apply_localtime (two , 0 );
49
+ /* Calculate correction for UTC offset changes between first and second SSE */
50
+ dst_corr = two -> z - one -> z ;
51
+ dst_h_corr = dst_corr / 3600 ;
52
+ dst_m_corr = (dst_corr % 3600 ) / 60 ;
65
53
66
54
rt -> y = two -> y - one -> y ;
67
55
rt -> m = two -> m - one -> m ;
@@ -70,29 +58,87 @@ timelib_rel_time *timelib_diff(timelib_time *one, timelib_time *two)
70
58
rt -> i = two -> i - one -> i ;
71
59
rt -> s = two -> s - one -> s ;
72
60
rt -> us = two -> us - one -> us ;
73
- if (one_backup .dst == 0 && two_backup .dst == 1 && two -> sse >= one -> sse + 86400 - dst_corr ) {
74
- rt -> h += dst_h_corr ;
75
- rt -> i += dst_m_corr ;
76
- }
77
61
78
62
rt -> days = fabs (floor ((one -> sse - two -> sse - (dst_h_corr * 3600 ) - (dst_m_corr * 60 )) / 86400 ));
79
63
64
+ /* Fall Back: Cater for transition period, where rt->invert is 0, but there are negative numbers */
65
+ if (one -> dst == 1 && two -> dst == 0 ) {
66
+ /* First for two "Type 3" times */
67
+ if (one -> zone_type == 3 && two -> zone_type == 3 ) {
68
+ trans = timelib_get_time_zone_info (two -> sse , two -> tz_info );
69
+ if (trans ) {
70
+ if (one -> sse >= trans -> transition_time + dst_corr && one -> sse < trans -> transition_time ) {
71
+ timelib_sll flipped = SECS_PER_HOUR + (rt -> i * 60 ) + (rt -> s );
72
+ rt -> h = flipped / SECS_PER_HOUR ;
73
+ rt -> i = (flipped - rt -> h * SECS_PER_HOUR ) / 60 ;
74
+ rt -> s = flipped % 60 ;
75
+ }
76
+ timelib_time_offset_dtor (trans );
77
+ trans = NULL ;
78
+ }
79
+ } else if (rt -> h == 0 && (rt -> i < 0 || rt -> s < 0 )) {
80
+ /* Then for all the others */
81
+ timelib_sll flipped = SECS_PER_HOUR + (rt -> i * 60 ) + (rt -> s );
82
+ rt -> h = flipped / SECS_PER_HOUR ;
83
+ rt -> i = (flipped - rt -> h * SECS_PER_HOUR ) / 60 ;
84
+ rt -> s = flipped % 60 ;
85
+ dst_corr += SECS_PER_HOUR ;
86
+ dst_h_corr ++ ;
87
+ }
88
+ }
89
+
80
90
timelib_do_rel_normalize (rt -> invert ? one : two , rt );
81
91
82
- /* We need to do this after normalisation otherwise we can't get "24H" */
83
- if (one_backup .dst == 1 && two_backup .dst == 0 && two -> sse >= one -> sse + 86400 ) {
84
- if (two -> sse < one -> sse + 86400 - dst_corr ) {
85
- rt -> d -- ;
86
- rt -> h = 24 ;
87
- } else {
88
- rt -> h += dst_h_corr ;
89
- rt -> i += dst_m_corr ;
92
+ /* Do corrections for "Type 3" times */
93
+ if (one -> zone_type == 3 && two -> zone_type == 3 ) {
94
+ if (one -> dst == 1 && two -> dst == 0 ) { /* Fall Back */
95
+ if (two -> tz_info ) {
96
+ trans = timelib_get_time_zone_info (two -> sse , two -> tz_info );
97
+
98
+ if (
99
+ trans &&
100
+ two -> sse >= trans -> transition_time &&
101
+ ((two -> sse - one -> sse + dst_corr ) % SECS_PER_DAY ) > (two -> sse - trans -> transition_time )
102
+ ) {
103
+ rt -> h -= dst_h_corr ;
104
+ rt -> i -= dst_m_corr ;
105
+ }
106
+ }
107
+ } else if (one -> dst == 0 && two -> dst == 1 ) { /* Spring Forward */
108
+ if (two -> tz_info ) {
109
+ trans = timelib_get_time_zone_info (two -> sse , two -> tz_info );
110
+
111
+ if (
112
+ trans &&
113
+ !((one -> sse + SECS_PER_DAY > trans -> transition_time ) && (one -> sse + SECS_PER_DAY <= (trans -> transition_time + dst_corr ))) &&
114
+ two -> sse >= trans -> transition_time &&
115
+ ((two -> sse - one -> sse + dst_corr ) % SECS_PER_DAY ) > (two -> sse - trans -> transition_time )
116
+ ) {
117
+ rt -> h -= dst_h_corr ;
118
+ rt -> i -= dst_m_corr ;
119
+ }
120
+ }
121
+ } else if (two -> sse - one -> sse >= SECS_PER_DAY ) {
122
+ /* Check whether we're in the period to the next transition time */
123
+ trans = timelib_get_time_zone_info (two -> sse - two -> z , two -> tz_info );
124
+ dst_corr = one -> z - trans -> offset ;
125
+
126
+ if (two -> sse >= trans -> transition_time - dst_corr && two -> sse < trans -> transition_time ) {
127
+ rt -> d -- ;
128
+ rt -> h = 24 ;
129
+ }
90
130
}
131
+ } else {
132
+ /* Then for all the others */
133
+ rt -> h -= dst_h_corr + (two -> dst - one -> dst );
134
+ rt -> i -= dst_m_corr ;
135
+
136
+ timelib_do_rel_normalize (rt -> invert ? one : two , rt );
91
137
}
92
138
93
- /* Restore old TZ info */
94
- memcpy ( one , & one_backup , sizeof ( one_backup ) );
95
- memcpy ( two , & two_backup , sizeof ( two_backup ));
139
+ if ( trans ) {
140
+ timelib_time_offset_dtor ( trans );
141
+ }
96
142
97
143
return rt ;
98
144
}
@@ -122,13 +168,6 @@ timelib_time *timelib_add(timelib_time *old_time, timelib_rel_time *interval)
122
168
123
169
timelib_update_ts (t , NULL );
124
170
125
- // printf("%lld %lld %d\n", old_time->dst, t->dst, (t->sse - old_time->sse));
126
- /* Adjust for backwards DST changeover */
127
- if (old_time -> dst == 1 && t -> dst == 0 && !interval -> y && !interval -> m && !interval -> d ) {
128
- t -> sse -= old_time -> z ;
129
- t -> sse += t -> z ;
130
- }
131
-
132
171
timelib_update_from_sse (t );
133
172
t -> have_relative = 0 ;
134
173
@@ -157,19 +196,86 @@ timelib_time *timelib_sub(timelib_time *old_time, timelib_rel_time *interval)
157
196
158
197
timelib_update_ts (t , NULL );
159
198
160
- /* Adjust for backwards DST changeover */
161
- if (old_time -> dst == 1 && t -> dst == 0 && !interval -> y && !interval -> m && !interval -> d ) {
162
- t -> sse -= old_time -> z ;
163
- t -> sse += t -> z ;
164
- }
165
- /* Adjust for forwards DST changeover */
166
- if (old_time -> dst == 0 && t -> dst == 1 && !interval -> y && !interval -> m && !interval -> d ) {
167
- t -> sse -= old_time -> z ;
168
- t -> sse += t -> z ;
199
+ timelib_update_from_sse (t );
200
+
201
+ t -> have_relative = 0 ;
202
+
203
+ return t ;
204
+ }
205
+
206
+ timelib_time * timelib_add_wall (timelib_time * old_time , timelib_rel_time * interval )
207
+ {
208
+ int bias = 1 ;
209
+ timelib_time * t = timelib_time_clone (old_time );
210
+
211
+ t -> have_relative = 1 ;
212
+ t -> sse_uptodate = 0 ;
213
+
214
+ if (interval -> have_weekday_relative || interval -> have_special_relative ) {
215
+ memcpy (& t -> relative , interval , sizeof (timelib_rel_time ));
216
+
217
+ timelib_update_ts (t , NULL );
218
+ } else {
219
+ if (interval -> invert ) {
220
+ bias = -1 ;
221
+ }
222
+ memset (& t -> relative , 0 , sizeof (timelib_rel_time ));
223
+ t -> relative .y = interval -> y * bias ;
224
+ t -> relative .m = interval -> m * bias ;
225
+ t -> relative .d = interval -> d * bias ;
226
+
227
+ if (t -> relative .y || t -> relative .m || t -> relative .d ) {
228
+ timelib_update_ts (t , NULL );
229
+ }
230
+
231
+ t -> sse += bias * timelib_hms_to_seconds (interval -> h , interval -> i , interval -> s );
232
+ t -> us += interval -> us * bias ;
233
+ timelib_do_normalize (t );
169
234
}
170
235
171
236
timelib_update_from_sse (t );
237
+ if (t -> zone_type == TIMELIB_ZONETYPE_ID ) {
238
+ timelib_set_timezone (t , t -> tz_info );
239
+ }
240
+ t -> have_relative = 0 ;
241
+
242
+ return t ;
243
+ }
244
+
245
+ timelib_time * timelib_sub_wall (timelib_time * old_time , timelib_rel_time * interval )
246
+ {
247
+ int bias = 1 ;
248
+ timelib_time * t = timelib_time_clone (old_time );
172
249
250
+ t -> have_relative = 1 ;
251
+ t -> sse_uptodate = 0 ;
252
+
253
+ if (interval -> have_weekday_relative || interval -> have_special_relative ) {
254
+ memcpy (& t -> relative , interval , sizeof (timelib_rel_time ));
255
+
256
+ timelib_update_ts (t , NULL );
257
+ } else {
258
+ if (interval -> invert ) {
259
+ bias = -1 ;
260
+ }
261
+ memset (& t -> relative , 0 , sizeof (timelib_rel_time ));
262
+ t -> relative .y = 0 - (interval -> y * bias );
263
+ t -> relative .m = 0 - (interval -> m * bias );
264
+ t -> relative .d = 0 - (interval -> d * bias );
265
+
266
+ if (t -> relative .y || t -> relative .m || t -> relative .d ) {
267
+ timelib_update_ts (t , NULL );
268
+ }
269
+
270
+ t -> sse -= bias * timelib_hms_to_seconds (interval -> h , interval -> i , interval -> s );
271
+ t -> us -= interval -> us * bias ;
272
+ timelib_do_normalize (t );
273
+ }
274
+
275
+ timelib_update_from_sse (t );
276
+ if (t -> zone_type == TIMELIB_ZONETYPE_ID ) {
277
+ timelib_set_timezone (t , t -> tz_info );
278
+ }
173
279
t -> have_relative = 0 ;
174
280
175
281
return t ;
0 commit comments