File Coverage

DateTime.xs
Criterion Covered Total %
statement 103 107 96.2
branch 83 134 61.9
condition n/a
subroutine n/a
pod n/a
total 186 241 77.1


line stmt bran cond sub pod time code
1             #include "EXTERN.h"
2             #include "perl.h"
3             #include "XSUB.h"
4             #include "ppport.h"
5              
6             #include <stdlib.h>
7              
8             /* This file is generated by tools/leap_seconds_header.pl */
9             #include "leap_seconds.h"
10              
11             /* It seems that on Windows before Perl 5.20, the Perl_isfinite macro exists,
12             but it tries to call Perl_isinf and Perl_isnan, which don't exist. */
13             #if defined (Perl_isfinite) && defined (Perl_isinf) && defined (Perl_isnan)
14             # define dt_isfinite Perl_isfinite
15             #else
16             # include <math.h>
17             # ifdef isfinite
18             # define dt_isfinite isfinite
19             # else
20             # ifdef finite
21             # define dt_isfinite finite
22             # endif
23             # endif
24             #endif
25              
26             #define DAYS_PER_400_YEARS 146097
27             #define DAYS_PER_4_YEARS 1461
28             #define MARCH_1 306
29              
30             #define SECONDS_PER_DAY 86400
31              
32             const int PREVIOUS_MONTH_DOY[12] = { 0,
33             31,
34             59,
35             90,
36             120,
37             151,
38             181,
39             212,
40             243,
41             273,
42             304,
43             334 };
44              
45             const int PREVIOUS_MONTH_DOLY[12] = { 0,
46             31,
47             60,
48             91,
49             121,
50             152,
51             182,
52             213,
53             244,
54             274,
55             305,
56             335 };
57              
58              
59             IV
60 97841           _real_is_leap_year(IV y) {
61             /* See http://www.perlmonks.org/?node_id=274247 for where this silliness
62             comes from */
63 97841 100         return (y % 4) ? 0 : (y % 100) ? 1 : (y % 400) ? 0 : 1;
    100          
    100          
64             }
65              
66              
67             MODULE = DateTime PACKAGE = DateTime
68              
69             PROTOTYPES: ENABLE
70              
71             void
72             _rd2ymd(self, d, extra = 0)
73             IV d;
74             IV extra;
75              
76             PREINIT:
77             IV y, m;
78             IV c;
79             IV quarter;
80 320633           IV yadj = 0;
81             IV dow, doy, doq;
82             IV rd_days;
83              
84             PPCODE:
85 320633           rd_days = d;
86              
87 320633           d += MARCH_1;
88              
89 320633 100         if (d <= 0) {
90 115721           yadj = -1 * (((-1 * d) / DAYS_PER_400_YEARS) + 1);
91 115721           d -= yadj * DAYS_PER_400_YEARS;
92             }
93              
94             /* c is century */
95 320633           c = ((d * 4) - 1) / DAYS_PER_400_YEARS;
96 320633           d -= c * DAYS_PER_400_YEARS / 4;
97 320633           y = ((d * 4) - 1) / DAYS_PER_4_YEARS;
98 320633           d -= y * DAYS_PER_4_YEARS / 4;
99 320633           m = ((d * 12) + 1093) / 367;
100 320633           d -= ((m * 367) - 1094) / 12;
101 320633           y += (c * 100) + (yadj * 400);
102              
103 320633 100         if (m > 12) {
104 39717           ++y;
105 39717           m -= 12;
106             }
107              
108 320633 100         EXTEND(SP, extra ? 7 : 3);
    50          
    0          
109 320633           mPUSHi(y);
110 320633           mPUSHi(m);
111 320633           mPUSHi(d);
112              
113 320633 100         if (extra) {
114 57707           quarter = ( ( 1.0 / 3.1 ) * m ) + 1;
115              
116 57707           dow = rd_days % 7;
117 57707 100         if ( dow <= 0 ) {
118 25451           dow += 7;
119             }
120              
121 57707           mPUSHi(dow);
122              
123 57707 100         if (_real_is_leap_year(y)) {
124 14195           doy = PREVIOUS_MONTH_DOLY[m - 1] + d;
125 14195           doq = doy - PREVIOUS_MONTH_DOLY[ (3 * quarter) - 3 ];
126             } else {
127 43512           doy = PREVIOUS_MONTH_DOY[m - 1] + d;
128 43512           doq = doy - PREVIOUS_MONTH_DOY[ (3 * quarter ) - 3 ];
129             }
130              
131 57707           mPUSHi(doy);
132 57707           mPUSHi(quarter);
133 57707           mPUSHi(doq);
134             }
135              
136             void
137             _ymd2rd(self, y, m, d)
138             IV y;
139             IV m;
140             IV d;
141              
142             PREINIT:
143             IV adj;
144              
145             PPCODE:
146 288602 100         if (m <= 2) {
147 39394           adj = (14 - m) / 12;
148 39394           y -= adj;
149 39394           m += 12 * adj;
150 249208 100         } else if (m > 14) {
151 409           adj = (m - 3) / 12;
152 409           y += adj;
153 409           m -= 12 * adj;
154             }
155              
156 288602 100         if (y < 0) {
157 115724           adj = (399 - y) / 400;
158 115724           d -= DAYS_PER_400_YEARS * adj;
159 115724           y += 400 * adj;
160             }
161              
162 577204           d += (m * 367 - 1094) /
163 288602           12 + y % 100 * DAYS_PER_4_YEARS /
164 288602           4 + (y / 100 * 36524 + y / 400) - MARCH_1;
165              
166 288602 50         EXTEND(SP, 1);
167 288602           mPUSHi(d);
168              
169             void
170             _seconds_as_components(self, secs, utc_secs = 0, secs_modifier = 0)
171             IV secs;
172             IV utc_secs;
173             IV secs_modifier;
174              
175             PREINIT:
176             IV h, m, s;
177              
178             PPCODE:
179 89652           secs -= secs_modifier;
180              
181 89652           h = secs / 3600;
182 89652           secs -= h * 3600;
183              
184 89652           m = secs / 60;
185              
186 89652           s = secs - (m * 60);
187              
188 89652 100         if (utc_secs >= SECONDS_PER_DAY) {
189 53 50         if (utc_secs >= SECONDS_PER_DAY + 1) {
190             /* If we just use %d and the IV, we get a warning that IV is
191             not an int. */
192 0 0         croak("Invalid UTC RD seconds value: %s", SvPV_nolen(newSViv(utc_secs)));
193             }
194              
195 53           s += (utc_secs - SECONDS_PER_DAY) + 60;
196 53           m = 59;
197 53           h--;
198              
199 53 100         if (h < 0) {
200 1           h = 23;
201             }
202             }
203              
204 89652 50         EXTEND(SP, 3);
205 89652           mPUSHi(h);
206 89652           mPUSHi(m);
207 89652           mPUSHi(s);
208              
209             #ifdef dt_isfinite
210             void
211             _normalize_tai_seconds(self, days, secs)
212             SV* days;
213             SV* secs;
214              
215             PPCODE:
216 113544 100         if (dt_isfinite(SvNV(days)) && dt_isfinite(SvNV(secs))) {
    100          
    50          
    50          
217 113448 50         IV d = SvIV(days);
218 113448 50         IV s = SvIV(secs);
219             IV adj;
220              
221 113448 100         if (s < 0) {
222 56           adj = (s - (SECONDS_PER_DAY - 1)) / SECONDS_PER_DAY;
223             } else {
224 113392           adj = s / SECONDS_PER_DAY;
225             }
226              
227 113448           d += adj;
228 113448           s -= adj * SECONDS_PER_DAY;
229              
230 113448           sv_setiv(days, (IV) d);
231 113448           sv_setiv(secs, (IV) s);
232             }
233              
234             void
235             _normalize_leap_seconds(self, days, secs)
236             SV* days;
237             SV* secs;
238              
239             PPCODE:
240 75 50         if (dt_isfinite(SvNV(days)) && dt_isfinite(SvNV(secs))) {
    50          
    50          
    50          
241 75 50         IV d = SvIV(days);
242 75 50         IV s = SvIV(secs);
243             IV day_length;
244              
245 499 100         while (s < 0) {
246 424           SET_DAY_LENGTH(d - 1, day_length);
247              
248 424           s += day_length;
249 424           d--;
250             }
251              
252 75           SET_DAY_LENGTH(d, day_length);
253              
254 584457 100         while (s > day_length - 1) {
255 584382           s -= day_length;
256 584382           d++;
257 584382           SET_DAY_LENGTH(d, day_length);
258             }
259              
260 75           sv_setiv(days, (IV) d);
261 75           sv_setiv(secs, (IV) s);
262             }
263              
264             #endif /* ifdef dt_isfinite */
265              
266             void
267             _time_as_seconds(self, h, m, s)
268             IV h;
269             IV m;
270             IV s;
271              
272             PPCODE:
273 57554 50         EXTEND(SP, 1);
274 57554           mPUSHi(h * 3600 + m * 60 + s);
275              
276             void
277             _is_leap_year(self, y)
278             IV y;
279              
280             PPCODE:
281 40134 50         EXTEND(SP, 1);
282 40134           mPUSHi(_real_is_leap_year(y));
283              
284             void
285             _day_length(self, utc_rd)
286             IV utc_rd;
287              
288             PPCODE:
289             IV day_length;
290 151           SET_DAY_LENGTH(utc_rd, day_length);
291              
292 151 50         EXTEND(SP, 1);
293 151           mPUSHi(day_length);
294              
295             void
296             _day_has_leap_second(self, utc_rd)
297             IV utc_rd;
298              
299             PPCODE:
300             IV day_length;
301 0           SET_DAY_LENGTH(utc_rd, day_length);
302              
303 0 0         EXTEND(SP, 1);
304 0 0         mPUSHi(day_length > 86400 ? 1 : 0);
305              
306             void
307             _accumulated_leap_seconds(self, utc_rd)
308             IV utc_rd;
309              
310             PPCODE:
311             IV leap_seconds;
312 14 50         SET_LEAP_SECONDS(utc_rd, leap_seconds);
    50          
    50          
    50          
    50          
    100          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
    50          
313              
314 14 50         EXTEND(SP, 1);
315 14           mPUSHi(leap_seconds);