File Coverage

src/moment.c
Criterion Covered Total %
statement 581 717 81.0
branch 121 240 50.4
condition n/a
subroutine n/a
pod n/a
total 702 957 73.3


line stmt bran cond sub pod time code
1             #include "moment.h"
2             #include "dt_core.h"
3             #include "dt_accessor.h"
4             #include "dt_arithmetic.h"
5             #include "dt_util.h"
6             #include "dt_length.h"
7             #include "dt_easter.h"
8              
9             static const int32_t kPow10[10] = {
10             1,
11             10,
12             100,
13             1000,
14             10000,
15             100000,
16             1000000,
17             10000000,
18             100000000,
19             1000000000,
20             };
21              
22             static void
23 23903           THX_moment_check_self(pTHX_ const moment_t *mt) {
24 23903 50         if (mt->sec < MIN_RANGE || mt->sec > MAX_RANGE)
    50          
25 0           croak("Time::Moment is out of range");
26 23903           }
27              
28             static moment_t
29 21805           THX_moment_from_local(pTHX_ int64_t sec, IV nsec, IV offset) {
30             moment_t r;
31              
32 21805           r.sec = sec;
33 21805           r.nsec = (int32_t)nsec;
34 21805           r.offset = (int32_t)offset;
35 21805           THX_moment_check_self(aTHX_ &r);
36 21805           return r;
37             }
38              
39             static moment_t
40 2098           THX_moment_from_instant(pTHX_ int64_t sec, IV nsec, IV offset) {
41             moment_t r;
42              
43 2098           r.sec = sec + offset * 60;
44 2098           r.nsec = (int32_t)nsec;
45 2098           r.offset = (int32_t)offset;
46 2098           THX_moment_check_self(aTHX_ &r);
47 2098           return r;
48             }
49              
50             int64_t
51 2503           moment_instant_rd_seconds(const moment_t *mt) {
52 2503           return mt->sec - mt->offset * 60;
53             }
54              
55             int
56 0           moment_instant_rd(const moment_t *mt) {
57 0           return (int)(moment_instant_rd_seconds(mt) / SECS_PER_DAY);
58             }
59              
60             void
61 2           moment_to_instant_rd_values(const moment_t *mt, IV *rdn, IV *sod, IV *nos) {
62 2           const int64_t sec = moment_instant_rd_seconds(mt);
63 2           *rdn = (IV)(sec / SECS_PER_DAY);
64 2           *sod = (IV)(sec % SECS_PER_DAY);
65 2           *nos = (IV)mt->nsec;
66 2           }
67              
68             int64_t
69 204916           moment_local_rd_seconds(const moment_t *mt) {
70 204916           return mt->sec;
71             }
72              
73             int
74 85318           moment_local_rd(const moment_t *mt) {
75 85318           return (int)(moment_local_rd_seconds(mt) / SECS_PER_DAY);
76             }
77              
78             dt_t
79 85318           moment_local_dt(const moment_t *mt) {
80 85318           return dt_from_rdn(moment_local_rd(mt));
81             }
82              
83             void
84 0           moment_to_local_rd_values(const moment_t *mt, IV *rdn, IV *sod, IV *nos) {
85 0           const int64_t sec = moment_local_rd_seconds(mt);
86 0           *rdn = (IV)(sec / SECS_PER_DAY);
87 0           *sod = (IV)(sec % SECS_PER_DAY);
88 0           *nos = (IV)mt->nsec;
89 0           }
90              
91             static void
92 1119           THX_check_year(pTHX_ int64_t v) {
93 1119 50         if (v < 1 || v > 9999)
    50          
94 0           croak("Parameter 'year' is out of the range [1, 9999]");
95 1119           }
96              
97             static void
98 4           THX_check_quarter(pTHX_ int64_t v) {
99 4 50         if (v < 1 || v > 4)
    50          
100 0           croak("Parameter 'quarter' is out of the range [1, 4]");
101 4           }
102              
103             static void
104 734           THX_check_month(pTHX_ int64_t v) {
105 734 50         if (v < 1 || v > 12)
    50          
106 0           croak("Parameter 'month' is out of the range [1, 12]");
107 734           }
108              
109             static void
110 0           THX_check_week(pTHX_ int64_t v) {
111 0 0         if (v < 1 || v > 53)
    0          
112 0           croak("Parameter 'week' is out of the range [1, 53]");
113 0           }
114              
115             static void
116 368           THX_check_day_of_year(pTHX_ int64_t v) {
117 368 50         if (v < 1 || v > 366)
    50          
118 0           croak("Parameter 'day' is out of the range [1, 366]");
119 368           }
120              
121             static void
122 100           THX_check_day_of_quarter(pTHX_ int64_t v) {
123 100 50         if (v < 1 || v > 92)
    50          
124 0           croak("Parameter 'day' is out of the range [1, 92]");
125 100           }
126              
127             static void
128 3567           THX_check_day_of_month(pTHX_ int64_t v) {
129 3567 50         if (v < 1 || v > 31)
    50          
130 0           croak("Parameter 'day' is out of the range [1, 31]");
131 3567           }
132              
133             static void
134 0           THX_check_day_of_week(pTHX_ int64_t v) {
135 0 0         if (v < 1 || v > 7)
    0          
136 0           croak("Parameter 'day' is out of the range [1, 7]");
137 0           }
138              
139             static void
140 662           THX_check_hour(pTHX_ int64_t v) {
141 662 50         if (v < 0 || v > 23)
    50          
142 0           croak("Parameter 'hour' is out of the range [1, 23]");
143 662           }
144              
145             static void
146 734           THX_check_minute(pTHX_ int64_t v) {
147 734 50         if (v < 0 || v > 59)
    50          
148 0           croak("Parameter 'minute' is out of the range [1, 59]");
149 734           }
150              
151             static void
152 9           THX_check_minute_of_day(pTHX_ int64_t v) {
153 9 50         if (v < 0 || v > 1439)
    50          
154 0           croak("Parameter 'minute' is out of the range [1, 1439]");
155 9           }
156              
157             static void
158 734           THX_check_second(pTHX_ int64_t v) {
159 734 50         if (v < 0 || v > 59)
    50          
160 0           croak("Parameter 'second' is out of the range [1, 59]");
161 734           }
162              
163             static void
164 36           THX_check_second_of_day(pTHX_ int64_t v) {
165 36 50         if (v < 0 || v > 86399)
    50          
166 0           croak("Parameter 'second' is out of the range [0, 86_399]");
167 36           }
168              
169             static void
170 4           THX_check_millisecond(pTHX_ int64_t v) {
171 4 50         if (v < 0 || v > 999)
    50          
172 0           croak("Parameter 'millisecond' is out of the range [0, 999]");
173 4           }
174              
175             static void
176 5           THX_check_microsecond(pTHX_ int64_t v) {
177 5 50         if (v < 0 || v > 999999)
    50          
178 0           croak("Parameter 'microsecond' is out of the range [0, 999_999]");
179 5           }
180              
181             static void
182 1756           THX_check_nanosecond(pTHX_ int64_t v) {
183 1756 50         if (v < 0 || v > 999999999)
    50          
184 0           croak("Parameter 'nanosecond' is out of the range [0, 999_999_999]");
185 1756           }
186              
187             static void
188 2021           THX_check_offset(pTHX_ int64_t v) {
189 2021 50         if (v < -1080 || v > 1080)
    50          
190 0           croak("Parameter 'offset' is out of the range [-1080, 1080]");
191 2021           }
192              
193             static void
194 1136           THX_check_epoch_seconds(pTHX_ int64_t v) {
195 1136 50         if (!VALID_EPOCH_SEC(v))
    50          
196 0           croak("Parameter 'seconds' is out of range");
197 1136           }
198              
199             static void
200 500           THX_check_rata_die_day(pTHX_ int64_t v) {
201 500 50         if (v < MIN_RATA_DIE_DAY || v > MAX_RATA_DIE_DAY)
    50          
202 0           croak("Parameter 'rdn' is out of range");
203 500           }
204              
205             static void
206 40           THX_check_unit_years(pTHX_ int64_t v) {
207 40 50         if (v < MIN_UNIT_YEARS || v > MAX_UNIT_YEARS)
    50          
208 0           croak("Parameter 'years' is out of range");
209 40           }
210              
211             static void
212 120           THX_check_unit_months(pTHX_ int64_t v) {
213 120 50         if (v < MIN_UNIT_MONTHS || v > MAX_UNIT_MONTHS)
    50          
214 0           croak("Parameter 'months' is out of range");
215 120           }
216              
217             static void
218 40           THX_check_unit_weeks(pTHX_ int64_t v) {
219 40 50         if (v < MIN_UNIT_WEEKS || v > MAX_UNIT_WEEKS)
    50          
220 0           croak("Parameter 'weeks' is out of range");
221 40           }
222              
223             static void
224 24728           THX_check_unit_days(pTHX_ int64_t v) {
225 24728 50         if (v < MIN_UNIT_DAYS || v > MAX_UNIT_DAYS)
    50          
226 0           croak("Parameter 'days' is out of range");
227 24728           }
228              
229             static void
230 80           THX_check_unit_hours(pTHX_ int64_t v) {
231 80 50         if (v < MIN_UNIT_HOURS || v > MAX_UNIT_HOURS)
    50          
232 0           croak("Parameter 'hours' is out of range");
233 80           }
234              
235             static void
236 80           THX_check_unit_minutes(pTHX_ int64_t v) {
237 80 50         if (v < MIN_UNIT_MINUTES || v > MAX_UNIT_MINUTES)
    50          
238 0           croak("Parameter 'minutes' is out of range");
239 80           }
240              
241             static void
242 330           THX_check_unit_seconds(pTHX_ int64_t v) {
243 330 50         if (v < MIN_UNIT_SECONDS || v > MAX_UNIT_SECONDS)
    50          
244 0           croak("Parameter 'seconds' is out of range");
245 330           }
246              
247             static void
248 80           THX_check_unit_milliseconds(pTHX_ int64_t v) {
249 80 50         if (v < MIN_UNIT_MILLIS || v > MAX_UNIT_MILLIS)
    50          
250 0           croak("Parameter 'milliseconds' is out of range");
251 80           }
252              
253             static void
254 81           THX_check_unit_microseconds(pTHX_ int64_t v) {
255 81 50         if (v < MIN_UNIT_MICROS || v > MAX_UNIT_MICROS)
    50          
256 0           croak("Parameter 'microseconds' is out of range");
257 81           }
258              
259             moment_t
260 1136           THX_moment_from_epoch(pTHX_ int64_t sec, IV nsec, IV offset) {
261              
262 1136           THX_check_epoch_seconds(aTHX_ sec);
263 1136           THX_check_nanosecond(aTHX_ nsec);
264 1136           THX_check_offset(aTHX_ offset);
265              
266 1136           sec += UNIX_EPOCH;
267 1136           return THX_moment_from_instant(aTHX_ sec, nsec, offset);
268             }
269              
270             moment_t
271 394           THX_moment_from_epoch_nv(pTHX_ NV sec, IV precision) {
272             static const NV SEC_MIN = -62135596801.0; /* 0000-12-31T23:59:59Z */
273             static const NV SEC_MAX = 253402300800.0; /* 10000-01-01T00:00:00Z */
274             NV s, f, n, denom;
275             IV nsec;
276             int64_t isec;
277              
278 394 50         if (precision < 0 || precision > 9)
    50          
279 0           croak("Parameter 'precision' is out of the range [0, 9]");
280              
281 394 50         if (!(sec > SEC_MIN && sec < SEC_MAX))
    50          
282 0           croak("Parameter 'seconds' is out of range");
283              
284 394           f = n = Perl_fmod(sec, 1.0);
285 394           s = Perl_floor(sec - f);
286 394 100         if (n < 0)
287 191           n += 1.0;
288 394           s = s + Perl_floor(f - n);
289 394           denom = Perl_pow(10.0, (NV)precision);
290 394           n = (Perl_floor(n * denom + 0.5) / denom) * 1E9;
291              
292 394           isec = (int64_t)s;
293 394           nsec = (IV)(n + 0.5);
294              
295 394 50         if (nsec >= NANOS_PER_SEC) {
296 0           nsec -= NANOS_PER_SEC;
297 0           isec += 1;
298             }
299 394           return THX_moment_from_epoch(aTHX_ isec, nsec, 0);
300             }
301              
302             static int
303 672           THX_moment_from_sd(pTHX_ NV sd, NV epoch, IV precision, int64_t *sec, int32_t *nsec) {
304             static const NV SD_MIN = -146097 * 50;
305             static const NV SD_MAX = 146097 * 50;
306             NV d1, d2, f1, f2, f, d, s, denom;
307              
308 672 50         if (precision < 0 || precision > 9)
    50          
309 0           croak("Parameter 'precision' is out of the range [0, 9]");
310              
311 672 50         if (!(sd > SD_MIN && sd < SD_MAX))
    50          
312 0           return -1;
313              
314 672 50         if (!(epoch > SD_MIN && epoch < SD_MAX))
    50          
315 0           croak("Parameter 'epoch' is out of range");
316              
317 672 100         if (sd >= epoch) {
318 548           d1 = sd;
319 548           d2 = epoch;
320             }
321             else {
322 124           d1 = epoch;
323 124           d2 = sd;
324             }
325              
326 672           f1 = Perl_fmod(d1, 1.0);
327 672           f2 = Perl_fmod(d2, 1.0);
328 672           d1 = Perl_floor(d1 - f1);
329 672           d2 = Perl_floor(d2 - f2);
330              
331 672           f = Perl_fmod(f1 + f2, 1.0);
332 672 100         if (f < 0.0)
333 140           f += 1.0;
334              
335 672           d = d1 + d2 + Perl_floor(f1 + f2 - f);
336 672           f *= 86400;
337 672           s = Perl_floor(f);
338              
339 672 50         if (d < 1 || d > 3652059)
    50          
340 0           return -2;
341              
342 672           denom = Perl_pow(10.0, (NV)precision);
343 672           f = (Perl_floor((f - s) * denom + 0.5) / denom) * 1E9;
344              
345 672           *sec = (int64_t)d * 86400 + (int32_t)s;
346 672           *nsec = (int32_t)(f + 0.5);
347              
348 672 100         if (*nsec >= NANOS_PER_SEC) {
349 5           *nsec -= NANOS_PER_SEC;
350 5           *sec += 1;
351             }
352 672           return 0;
353             }
354              
355             moment_t
356 225           THX_moment_from_rd(pTHX_ NV jd, NV epoch, IV precision, IV offset) {
357             int64_t sec;
358             int32_t nsec;
359             int r;
360              
361 225           THX_check_offset(aTHX_ offset);
362              
363 225           r = THX_moment_from_sd(aTHX_ jd, epoch, precision, &sec, &nsec);
364 225 50         if (r < 0) {
365 0 0         if (r == -1)
366 0           croak("Parameter 'rd' is out of range");
367             else
368 0           croak("Rata Die is out of range");
369             }
370 225           return THX_moment_from_local(aTHX_ sec, nsec, offset);
371             }
372              
373             moment_t
374 223           THX_moment_from_jd(pTHX_ NV jd, NV epoch, IV precision) {
375             int64_t sec;
376             int32_t nsec;
377             int r;
378              
379 223           r = THX_moment_from_sd(aTHX_ jd, epoch, precision, &sec, &nsec);
380 223 50         if (r < 0) {
381 0 0         if (r == -1)
382 0           croak("Parameter 'jd' is out of range");
383             else
384 0           croak("Julian date is out of range");
385             }
386              
387 223           return THX_moment_from_instant(aTHX_ sec, nsec, 0);
388             }
389              
390             moment_t
391 224           THX_moment_from_mjd(pTHX_ NV jd, NV epoch, IV precision) {
392             int64_t sec;
393             int32_t nsec;
394             int r;
395              
396 224           r = THX_moment_from_sd(aTHX_ jd, epoch, precision, &sec, &nsec);
397 224 50         if (r < 0) {
398 0 0         if (r == -1)
399 0           croak("Parameter 'mjd' is out of range");
400             else
401 0           croak("Modified Julian date is out of range");
402             }
403              
404 224           return THX_moment_from_instant(aTHX_ sec, nsec, 0);
405             }
406              
407             moment_t
408 614           THX_moment_new(pTHX_ IV Y, IV M, IV D, IV h, IV m, IV s, IV nsec, IV offset) {
409             int64_t rdn, sec;
410              
411 614           THX_check_year(aTHX_ Y);
412 614           THX_check_month(aTHX_ M);
413 614           THX_check_day_of_month(aTHX_ D);
414 614 50         if (D > 28) {
415 0           int dim = dt_days_in_month((int)Y, (int)M);
416 0 0         if (D > dim)
417 0           croak("Parameter 'day' is out of the range [1, %d]", dim);
418             }
419 614           THX_check_hour(aTHX_ h);
420 614           THX_check_minute(aTHX_ m);
421 614           THX_check_second(aTHX_ s);
422 614           THX_check_nanosecond(aTHX_ nsec);
423 614           THX_check_offset(aTHX_ offset);
424              
425 614           rdn = dt_rdn(dt_from_ymd((int)Y, (int)M, (int)D));
426 614           sec = ((rdn * 24 + h) * 60 + m) * 60 + s;
427 614           return THX_moment_from_local(aTHX_ sec, nsec, offset);
428             }
429              
430             static moment_t
431 7071           THX_moment_with_local_dt(pTHX_ const moment_t *mt, const dt_t dt) {
432             int64_t sec;
433              
434 7071           sec = (int64_t)dt_rdn(dt) * 86400 + moment_second_of_day(mt);
435 7071           return THX_moment_from_local(aTHX_ sec, mt->nsec, mt->offset);
436             }
437              
438             static moment_t
439 129           THX_moment_with_ymd(pTHX_ const moment_t *mt, int y, int m, int d) {
440              
441 129 50         if (d > 28) {
442 0           int dim = dt_days_in_month(y, m);
443 0 0         if (d > dim)
444 0           d = dim;
445             }
446 129           return THX_moment_with_local_dt(aTHX_ mt, dt_from_ymd(y, m, d));
447             }
448              
449             static moment_t
450 5           THX_moment_with_year(pTHX_ const moment_t *mt, int64_t v) {
451             int m, d;
452              
453 5           THX_check_year(aTHX_ v);
454 5           dt_to_ymd(moment_local_dt(mt), NULL, &m, &d);
455 5           return THX_moment_with_ymd(aTHX_ mt, (int)v, m, d);
456             }
457              
458             static moment_t
459 4           THX_moment_with_quarter(pTHX_ const moment_t *mt, int64_t v) {
460             int y, m, d;
461              
462 4           THX_check_quarter(aTHX_ v);
463 4           dt_to_ymd(moment_local_dt(mt), &y, &m, &d);
464 4           m = 1 + 3 * ((int)v - 1) + (m - 1) % 3;
465 4           return THX_moment_with_ymd(aTHX_ mt, y, m, d);
466             }
467              
468             static moment_t
469 120           THX_moment_with_month(pTHX_ const moment_t *mt, int64_t v) {
470             int y, d;
471              
472 120           THX_check_month(aTHX_ v);
473 120           dt_to_ymd(moment_local_dt(mt), &y, NULL, &d);
474 120           return THX_moment_with_ymd(aTHX_ mt, y, (int)v, d);
475             }
476              
477             static moment_t
478 0           THX_moment_with_week(pTHX_ const moment_t *mt, int64_t v) {
479             int y, w, d;
480              
481 0           THX_check_week(aTHX_ v);
482 0           dt_to_ywd(moment_local_dt(mt), &y, NULL, &d);
483 0           w = (int)v;
484 0 0         if (w > 52) {
485 0           int wiy = dt_weeks_in_year(y);
486 0 0         if (w > wiy)
487 0           croak("Parameter 'week' is out of the range [1, %d]", wiy);
488             }
489 0           return THX_moment_with_local_dt(aTHX_ mt, dt_from_ywd(y, w, d));
490             }
491              
492             static moment_t
493 2953           THX_moment_with_day_of_month(pTHX_ const moment_t *mt, int64_t v) {
494             int y, m, d;
495              
496 2953           THX_check_day_of_month(aTHX_ v);
497 2953           dt_to_ymd(moment_local_dt(mt), &y, &m, NULL);
498 2953           d = (int)v;
499 2953 100         if (d > 28) {
500 26           int dim = dt_days_in_month(y, m);
501 26 50         if (d > dim)
502 0           croak("Parameter 'day' is out of the range [1, %d]", dim);
503             }
504 2953           return THX_moment_with_local_dt(aTHX_ mt, dt_from_ymd(y, m, d));
505             }
506              
507             static moment_t
508 100           THX_moment_with_day_of_quarter(pTHX_ const moment_t *mt, int64_t v) {
509             int y, q, d;
510              
511 100           THX_check_day_of_quarter(aTHX_ v);
512 100           dt_to_yqd(moment_local_dt(mt), &y, &q, NULL);
513 100           d = (int)v;
514 100 100         if (d > 90) {
515 9           int diq = dt_days_in_quarter(y, q);
516 9 50         if (d > diq)
517 0           croak("Parameter 'day' is out of the range [1, %d]", diq);
518             }
519 100           return THX_moment_with_local_dt(aTHX_ mt, dt_from_yqd(y, q, d));
520             }
521              
522             static moment_t
523 368           THX_moment_with_day_of_year(pTHX_ const moment_t *mt, int64_t v) {
524             int y, d;
525              
526 368           THX_check_day_of_year(aTHX_ v);
527 368           dt_to_yd(moment_local_dt(mt), &y, NULL);
528 368           d = (int)v;
529 368 100         if (d > 365) {
530 2           int diy = dt_days_in_year(y);
531 2 50         if (v > diy)
532 0           croak("Parameter 'day' is out of the range [1, %d]", diy);
533             }
534 368           return THX_moment_with_local_dt(aTHX_ mt, dt_from_yd(y, d));
535             }
536              
537             static moment_t
538 0           THX_moment_with_day_of_week(pTHX_ const moment_t *mt, int64_t v) {
539             dt_t dt;
540              
541 0           THX_check_day_of_week(aTHX_ v);
542 0           dt = moment_local_dt(mt);
543 0           return THX_moment_with_local_dt(aTHX_ mt, dt - (dt_dow(dt) - v));
544             }
545              
546             static moment_t
547 500           THX_moment_with_rata_die_day(pTHX_ const moment_t *mt, int64_t v) {
548             dt_t dt;
549              
550 500           THX_check_rata_die_day(aTHX_ v);
551 500           dt = dt_from_rdn((int)v);
552 500           return THX_moment_with_local_dt(aTHX_ mt, dt);
553             }
554              
555             static moment_t
556 48           THX_moment_with_hour(pTHX_ const moment_t *mt, int64_t v) {
557             int64_t sec;
558              
559 48           THX_check_hour(aTHX_ v);
560 48           sec = moment_local_rd_seconds(mt) + (v - moment_hour(mt)) * 3600;
561 48           return THX_moment_from_local(aTHX_ sec, mt->nsec, mt->offset);
562             }
563              
564             static moment_t
565 120           THX_moment_with_minute(pTHX_ const moment_t *mt, int64_t v) {
566             int64_t sec;
567              
568 120           THX_check_minute(aTHX_ v);
569 120           sec = moment_local_rd_seconds(mt) + (v - moment_minute(mt)) * 60;
570 120           return THX_moment_from_local(aTHX_ sec, mt->nsec, mt->offset);
571             }
572              
573             static moment_t
574 9           THX_moment_with_minute_of_day(pTHX_ const moment_t *mt, int64_t v) {
575             int64_t sec;
576              
577 9           THX_check_minute_of_day(aTHX_ v);
578 9           sec = moment_local_rd_seconds(mt) + (v - moment_minute_of_day(mt)) * 60;
579 9           return THX_moment_from_local(aTHX_ sec, mt->nsec, mt->offset);
580             }
581              
582             static moment_t
583 120           THX_moment_with_second(pTHX_ const moment_t *mt, int64_t v) {
584             int64_t sec;
585              
586 120           THX_check_second(aTHX_ v);
587 120           sec = moment_local_rd_seconds(mt) + (v - moment_second(mt));
588 120           return THX_moment_from_local(aTHX_ sec, mt->nsec, mt->offset);
589             }
590              
591             static moment_t
592 36           THX_moment_with_second_of_day(pTHX_ const moment_t *mt, int64_t v) {
593             int64_t sec;
594              
595 36           THX_check_second_of_day(aTHX_ v);
596 36           sec = moment_local_rd_seconds(mt) + (v - moment_second_of_day(mt));
597 36           return THX_moment_from_local(aTHX_ sec, mt->nsec, mt->offset);
598             }
599              
600             static moment_t
601 4           THX_moment_with_millisecond(pTHX_ const moment_t *mt, int64_t v) {
602             int64_t sec;
603              
604 4           THX_check_millisecond(aTHX_ v);
605 4           sec = moment_local_rd_seconds(mt);
606 4           return THX_moment_from_local(aTHX_ sec, v * 1000000, mt->offset);
607             }
608              
609             static moment_t
610 5           THX_moment_with_microsecond(pTHX_ const moment_t *mt, int64_t v) {
611             int64_t sec;
612              
613 5           THX_check_microsecond(aTHX_ v);
614 5           sec = moment_local_rd_seconds(mt);
615 5           return THX_moment_from_local(aTHX_ sec, v * 1000, mt->offset);
616             }
617              
618             static moment_t
619 6           THX_moment_with_nanosecond(pTHX_ const moment_t *mt, int64_t v) {
620             int64_t sec;
621              
622 6           THX_check_nanosecond(aTHX_ v);
623 6           sec = moment_local_rd_seconds(mt);
624 6           return THX_moment_from_local(aTHX_ sec, v, mt->offset);
625             }
626              
627             static moment_t
628 445           THX_moment_with_nanosecond_of_day(pTHX_ const moment_t *mt, int64_t v) {
629             int64_t sec;
630             int32_t nsec;
631              
632 445 50         if (v < 0 || v > INT64_C(86400000000000))
    50          
633 0           croak("Paramteter 'nanosecond' is out of the range [0, 86_400_000_000_000]");
634              
635 445           sec = moment_local_rd_seconds(mt) + v / NANOS_PER_SEC - moment_second_of_day(mt);
636 445           nsec = v % NANOS_PER_SEC;
637 445           return THX_moment_from_local(aTHX_ sec, nsec, mt->offset);
638             }
639              
640             static moment_t
641 144           THX_moment_with_microsecond_of_day(pTHX_ const moment_t *mt, int64_t v) {
642 144 50         if (v < 0 || v > INT64_C(86400000000))
    50          
643 0           croak("Paramteter 'microsecond' is out of the range [0, 86_400_000_000]");
644 144           return THX_moment_with_nanosecond_of_day(aTHX_ mt, v * 1000);
645             }
646              
647             static moment_t
648 157           THX_moment_with_millisecond_of_day(pTHX_ const moment_t *mt, int64_t v) {
649 157 50         if (v < 0 || v > INT64_C(86400000))
    50          
650 0           croak("Paramteter 'millisecond' is out of the range [0, 86_400_000]");
651 157           return THX_moment_with_nanosecond_of_day(aTHX_ mt, v * 1000000);
652             }
653              
654             moment_t
655 4876           THX_moment_with_field(pTHX_ const moment_t *mt, moment_component_t c, int64_t v) {
656 4876           switch (c) {
657 5           case MOMENT_FIELD_YEAR:
658 5           return THX_moment_with_year(aTHX_ mt, v);
659 4           case MOMENT_FIELD_QUARTER_OF_YEAR:
660 4           return THX_moment_with_quarter(aTHX_ mt, v);
661 120           case MOMENT_FIELD_MONTH_OF_YEAR:
662 120           return THX_moment_with_month(aTHX_ mt, v);
663 0           case MOMENT_FIELD_WEEK_OF_YEAR:
664 0           return THX_moment_with_week(aTHX_ mt, v);
665 2953           case MOMENT_FIELD_DAY_OF_MONTH:
666 2953           return THX_moment_with_day_of_month(aTHX_ mt, v);
667 100           case MOMENT_FIELD_DAY_OF_QUARTER:
668 100           return THX_moment_with_day_of_quarter(aTHX_ mt, v);
669 368           case MOMENT_FIELD_DAY_OF_YEAR:
670 368           return THX_moment_with_day_of_year(aTHX_ mt, v);
671 0           case MOMENT_FIELD_DAY_OF_WEEK:
672 0           return THX_moment_with_day_of_week(aTHX_ mt, v);
673 48           case MOMENT_FIELD_HOUR_OF_DAY:
674 48           return THX_moment_with_hour(aTHX_ mt, v);
675 120           case MOMENT_FIELD_MINUTE_OF_HOUR:
676 120           return THX_moment_with_minute(aTHX_ mt, v);
677 9           case MOMENT_FIELD_MINUTE_OF_DAY:
678 9           return THX_moment_with_minute_of_day(aTHX_ mt, v);
679 120           case MOMENT_FIELD_SECOND_OF_MINUTE:
680 120           return THX_moment_with_second(aTHX_ mt, v);
681 36           case MOMENT_FIELD_SECOND_OF_DAY:
682 36           return THX_moment_with_second_of_day(aTHX_ mt, v);
683 4           case MOMENT_FIELD_MILLI_OF_SECOND:
684 4           return THX_moment_with_millisecond(aTHX_ mt, v);
685 151           case MOMENT_FIELD_MILLI_OF_DAY:
686 151           return THX_moment_with_millisecond_of_day(aTHX_ mt, v);
687 5           case MOMENT_FIELD_MICRO_OF_SECOND:
688 5           return THX_moment_with_microsecond(aTHX_ mt, v);
689 144           case MOMENT_FIELD_MICRO_OF_DAY:
690 144           return THX_moment_with_microsecond_of_day(aTHX_ mt, v);
691 6           case MOMENT_FIELD_NANO_OF_SECOND:
692 6           return THX_moment_with_nanosecond(aTHX_ mt, v);
693 144           case MOMENT_FIELD_NANO_OF_DAY:
694 144           return THX_moment_with_nanosecond_of_day(aTHX_ mt, v);
695 39           case MOMENT_FIELD_PRECISION:
696 39           return THX_moment_with_precision(aTHX_ mt, v);
697 500           case MOMENT_FIELD_RATA_DIE_DAY:
698 500           return THX_moment_with_rata_die_day(aTHX_ mt, v);
699             }
700 0           croak("panic: THX_moment_with_component() called with unknown component (%d)", (int)c);
701             }
702              
703             static moment_t
704 80           THX_moment_plus_months(pTHX_ const moment_t *mt, int64_t v) {
705             dt_t dt;
706              
707 80           THX_check_unit_months(aTHX_ v);
708 80           dt = dt_add_months(moment_local_dt(mt), (int)v, DT_LIMIT);
709 80           return THX_moment_with_local_dt(aTHX_ mt, dt);
710             }
711              
712             static moment_t
713 12384           THX_moment_plus_days(pTHX_ const moment_t *mt, int64_t v) {
714             int64_t sec;
715              
716 12384           THX_check_unit_days(aTHX_ v);
717 12384           sec = moment_local_rd_seconds(mt) + v * 86400;
718 12384           return THX_moment_from_local(aTHX_ sec, mt->nsec, mt->offset);
719             }
720              
721             static moment_t
722 245           THX_moment_plus_seconds(pTHX_ const moment_t *mt, int64_t v) {
723             int64_t sec;
724              
725 245           THX_check_unit_seconds(aTHX_ v);
726 245           sec = moment_instant_rd_seconds(mt) + v;
727 245           return THX_moment_from_instant(aTHX_ sec, mt->nsec, mt->offset);
728             }
729              
730             static moment_t
731 242           THX_moment_plus_time(pTHX_ const moment_t *mt, int64_t sec, int64_t nsec, int sign) {
732              
733 242           sec = sec + (nsec / NANOS_PER_SEC);
734 242           nsec = nsec % NANOS_PER_SEC;
735              
736 242           sec = moment_instant_rd_seconds(mt) + sec * sign;
737 242           nsec = mt->nsec + nsec * sign;
738              
739 242 100         if (nsec < 0) {
740 42           nsec += NANOS_PER_SEC;
741 42           sec--;
742             }
743 200 100         else if (nsec >= NANOS_PER_SEC) {
744 2           nsec -= NANOS_PER_SEC;
745 2           sec++;
746             }
747 242           return THX_moment_from_instant(aTHX_ sec, (IV)nsec, mt->offset);
748             }
749              
750             moment_t
751 7187           THX_moment_plus_unit(pTHX_ const moment_t *mt, moment_unit_t u, int64_t v) {
752 7187           switch (u) {
753 20           case MOMENT_UNIT_YEARS:
754 20           THX_check_unit_years(aTHX_ v);
755 20           return THX_moment_plus_months(aTHX_ mt, v * 12);
756 20           case MOMENT_UNIT_MONTHS:
757 20           THX_check_unit_months(aTHX_ v);
758 20           return THX_moment_plus_months(aTHX_ mt, v);
759 20           case MOMENT_UNIT_WEEKS:
760 20           THX_check_unit_weeks(aTHX_ v);
761 20           return THX_moment_plus_days(aTHX_ mt, v * 7);
762 6880           case MOMENT_UNIT_DAYS:
763 6880           THX_check_unit_days(aTHX_ v);
764 6880           return THX_moment_plus_days(aTHX_ mt, v);
765 40           case MOMENT_UNIT_HOURS:
766 40           THX_check_unit_hours(aTHX_ v);
767 40           return THX_moment_plus_seconds(aTHX_ mt, v * 3600);
768 40           case MOMENT_UNIT_MINUTES:
769 40           THX_check_unit_minutes(aTHX_ v);
770 40           return THX_moment_plus_seconds(aTHX_ mt, v * 60);
771 45           case MOMENT_UNIT_SECONDS:
772 45           THX_check_unit_seconds(aTHX_ v);
773 45           return THX_moment_plus_seconds(aTHX_ mt, v);
774 40           case MOMENT_UNIT_MILLIS:
775 40           THX_check_unit_milliseconds(aTHX_ v);
776 40           return THX_moment_plus_time(aTHX_ mt, v / 1000, (v % 1000) * 1000000, 1);
777 41           case MOMENT_UNIT_MICROS:
778 41           THX_check_unit_microseconds(aTHX_ v);
779 41           return THX_moment_plus_time(aTHX_ mt, v / 1000000, (v % 1000000) * 1000, 1);
780 41           case MOMENT_UNIT_NANOS:
781 41           return THX_moment_plus_time(aTHX_ mt, 0, v, 1);
782             }
783 0           croak("panic: THX_moment_plus_unit() called with unknown unit (%d)", (int)u);
784             }
785              
786             moment_t
787 5764           THX_moment_minus_unit(pTHX_ const moment_t *mt, moment_unit_t u, int64_t v) {
788 5764           switch (u) {
789 20           case MOMENT_UNIT_YEARS:
790 20           THX_check_unit_years(aTHX_ v);
791 20           return THX_moment_plus_months(aTHX_ mt, -v * 12);
792 20           case MOMENT_UNIT_MONTHS:
793 20           THX_check_unit_months(aTHX_ v);
794 20           return THX_moment_plus_months(aTHX_ mt, -v);
795 20           case MOMENT_UNIT_WEEKS:
796 20           THX_check_unit_weeks(aTHX_ v);
797 20           return THX_moment_plus_days(aTHX_ mt, -v * 7);
798 5464           case MOMENT_UNIT_DAYS:
799 5464           THX_check_unit_days(aTHX_ v);
800 5464           return THX_moment_plus_days(aTHX_ mt, -v);
801 40           case MOMENT_UNIT_HOURS:
802 40           THX_check_unit_hours(aTHX_ v);
803 40           return THX_moment_plus_seconds(aTHX_ mt, -v * 3600);
804 40           case MOMENT_UNIT_MINUTES:
805 40           THX_check_unit_minutes(aTHX_ v);
806 40           return THX_moment_plus_seconds(aTHX_ mt, -v * 60);
807 40           case MOMENT_UNIT_SECONDS:
808 40           THX_check_unit_seconds(aTHX_ v);
809 40           return THX_moment_plus_seconds(aTHX_ mt, -v);
810 40           case MOMENT_UNIT_MILLIS:
811 40           THX_check_unit_milliseconds(aTHX_ v);
812 40           return THX_moment_plus_time(aTHX_ mt, v / 1000, (v % 1000) * 1000000, -1);
813 40           case MOMENT_UNIT_MICROS:
814 40           THX_check_unit_microseconds(aTHX_ v);
815 40           return THX_moment_plus_time(aTHX_ mt, v / 1000000, (v % 1000000) * 1000, -1);
816 40           case MOMENT_UNIT_NANOS:
817 40           return THX_moment_plus_time(aTHX_ mt, 0, v, -1);
818             }
819 0           croak("panic: THX_moment_minus_unit() called with unknown unit (%d)", (int)u);
820             }
821              
822             moment_t
823 28           THX_moment_with_offset_same_instant(pTHX_ const moment_t *mt, IV offset) {
824             int64_t sec;
825              
826 28           THX_check_offset(aTHX_ offset);
827 28           sec = moment_instant_rd_seconds(mt);
828 28           return THX_moment_from_instant(aTHX_ sec, mt->nsec, offset);
829             }
830              
831             moment_t
832 18           THX_moment_with_offset_same_local(pTHX_ const moment_t *mt, IV offset) {
833             int64_t sec;
834              
835 18           THX_check_offset(aTHX_ offset);
836 18           sec = moment_local_rd_seconds(mt);
837 18           return THX_moment_from_local(aTHX_ sec, mt->nsec, offset);
838             }
839              
840             moment_t
841 700           THX_moment_with_precision(pTHX_ const moment_t *mt, int64_t precision) {
842             int64_t sec;
843             int32_t nsec;
844              
845 700 50         if (precision < -3 || precision > 9)
    50          
846 0           croak("Parameter 'precision' is out of the range [-3, 9]");
847              
848 700           sec = moment_local_rd_seconds(mt);
849 700           nsec = mt->nsec;
850 700 100         if (precision <= 0) {
851 12           nsec = 0;
852 12           switch (precision) {
853 3           case -1: sec -= sec % 60; break;
854 3           case -2: sec -= sec % 3600; break;
855 3           case -3: sec -= sec % 86400; break;
856             }
857             }
858             else {
859 688           nsec -= nsec % kPow10[9 - precision];
860             }
861 700           return THX_moment_from_local(aTHX_ sec, nsec, mt->offset);
862             }
863              
864             moment_duration_t
865 612           moment_subtract_moment(const moment_t *mt1, const moment_t *mt2) {
866 612           const int64_t s1 = moment_instant_rd_seconds(mt1);
867 612           const int64_t s2 = moment_instant_rd_seconds(mt2);
868             moment_duration_t d;
869              
870 612           d.sec = s2 - s1;
871 612           d.nsec = mt2->nsec - mt1->nsec;
872 612 100         if (d.nsec < 0) {
873 76           d.sec -= 1;
874 76           d.nsec += NANOS_PER_SEC;
875             }
876 612           return d;
877             }
878              
879             static int
880 85           moment_delta_days(const moment_t *mt1, const moment_t *mt2) {
881 85           const dt_t dt1 = moment_local_dt(mt1);
882 85           const dt_t dt2 = moment_local_dt(mt2);
883 85           return dt2 - dt1;
884             }
885              
886             static int
887 42           moment_delta_weeks(const moment_t *mt1, const moment_t *mt2) {
888 42           return moment_delta_days(mt1, mt2) / 7;
889             }
890              
891             static int
892 86           moment_delta_months(const moment_t *mt1, const moment_t *mt2) {
893 86           const dt_t dt1 = moment_local_dt(mt1);
894 86           const dt_t dt2 = moment_local_dt(mt2);
895 86           return dt_delta_months(dt1, dt2, true);
896             }
897              
898             static int
899 42           moment_delta_years(const moment_t *mt1, const moment_t *mt2) {
900 42           return moment_delta_months(mt1, mt2) / 12;
901             }
902              
903             static int64_t
904 102           THX_moment_delta_hours(pTHX_ const moment_t *mt1, const moment_t *mt2) {
905             moment_duration_t d;
906 102           d = moment_subtract_moment(mt1, mt2);
907 102           return (d.sec / 3600);
908             }
909              
910             static int64_t
911 102           THX_moment_delta_minutes(pTHX_ const moment_t *mt1, const moment_t *mt2) {
912             moment_duration_t d;
913 102           d = moment_subtract_moment(mt1, mt2);
914 102           return (d.sec / 60);
915             }
916              
917             static int64_t
918 102           THX_moment_delta_seconds(pTHX_ const moment_t *mt1, const moment_t *mt2) {
919             moment_duration_t d;
920 102           d = moment_subtract_moment(mt1, mt2);
921 102           return d.sec;
922             }
923              
924             static int64_t
925 102           THX_moment_delta_milliseconds(pTHX_ const moment_t *mt1, const moment_t *mt2) {
926             moment_duration_t d;
927 102           d = moment_subtract_moment(mt1, mt2);
928 102           return d.sec * 1000 + (d.nsec / 1000000);
929             }
930              
931             static int64_t
932 102           THX_moment_delta_microseconds(pTHX_ const moment_t *mt1, const moment_t *mt2) {
933             moment_duration_t d;
934 102           d = moment_subtract_moment(mt1, mt2);
935 102           return d.sec * 1000000 + (d.nsec / 1000);
936             }
937              
938             static int64_t
939 102           THX_moment_delta_nanoseconds(pTHX_ const moment_t *mt1, const moment_t *mt2) {
940             static const int64_t kMaxSec = INT64_C(9223372035);
941             moment_duration_t d;
942              
943 102           d = moment_subtract_moment(mt1, mt2);
944 102 50         if (d.sec > kMaxSec || d.sec < -kMaxSec)
    50          
945 0           croak("Nanosecond duration is too large to be represented in a 64-bit integer");
946 102           return d.sec * 1000000000 + d.nsec;
947             }
948              
949             int64_t
950 783           THX_moment_delta_unit(pTHX_ const moment_t *mt1, const moment_t *mt2, moment_unit_t u) {
951 783           switch (u) {
952 42           case MOMENT_UNIT_YEARS:
953 42           return moment_delta_years(mt1, mt2);
954 44           case MOMENT_UNIT_MONTHS:
955 44           return moment_delta_months(mt1, mt2);
956 42           case MOMENT_UNIT_WEEKS:
957 42           return moment_delta_weeks(mt1, mt2);
958 43           case MOMENT_UNIT_DAYS:
959 43           return moment_delta_days(mt1, mt2);
960 102           case MOMENT_UNIT_HOURS:
961 102           return THX_moment_delta_hours(aTHX_ mt1, mt2);
962 102           case MOMENT_UNIT_MINUTES:
963 102           return THX_moment_delta_minutes(aTHX_ mt1, mt2);
964 102           case MOMENT_UNIT_SECONDS:
965 102           return THX_moment_delta_seconds(aTHX_ mt1, mt2);
966 102           case MOMENT_UNIT_MILLIS:
967 102           return THX_moment_delta_milliseconds(aTHX_ mt1, mt2);
968 102           case MOMENT_UNIT_MICROS:
969 102           return THX_moment_delta_microseconds(aTHX_ mt1, mt2);
970 102           case MOMENT_UNIT_NANOS:
971 102           return THX_moment_delta_nanoseconds(aTHX_ mt1, mt2);
972 0           default:
973 0           croak("panic: THX_moment_delta_unit() called with unknown unit (%d)", (int)u);
974             }
975             }
976              
977             moment_t
978 3           THX_moment_at_utc(pTHX_ const moment_t *mt) {
979 3           return THX_moment_with_offset_same_instant(aTHX_ mt, 0);
980             }
981              
982             moment_t
983 3           THX_moment_at_midnight(pTHX_ const moment_t *mt) {
984 3           return THX_moment_with_millisecond_of_day(aTHX_ mt, 0);
985             }
986              
987             moment_t
988 3           THX_moment_at_noon(pTHX_ const moment_t *mt) {
989 3           return THX_moment_with_millisecond_of_day(aTHX_ mt, 12*60*60*1000);
990             }
991              
992             moment_t
993 5           THX_moment_at_last_day_of_year(pTHX_ const moment_t *mt) {
994             int y;
995              
996 5           dt_to_yd(moment_local_dt(mt), &y, NULL);
997 5           return THX_moment_with_local_dt(aTHX_ mt, dt_from_yd(y + 1, 0));
998             }
999              
1000             moment_t
1001 11           THX_moment_at_last_day_of_quarter(pTHX_ const moment_t *mt) {
1002             int y, q;
1003              
1004 11           dt_to_yqd(moment_local_dt(mt), &y, &q, NULL);
1005 11           return THX_moment_with_local_dt(aTHX_ mt, dt_from_yqd(y, q + 1, 0));
1006             }
1007              
1008             moment_t
1009 2925           THX_moment_at_last_day_of_month(pTHX_ const moment_t *mt) {
1010             int y, m;
1011              
1012 2925           dt_to_ymd(moment_local_dt(mt), &y, &m, NULL);
1013 2925           return THX_moment_with_local_dt(aTHX_ mt, dt_from_ymd(y, m + 1, 0));
1014             }
1015              
1016             int
1017 20           moment_compare_instant(const moment_t *m1, const moment_t *m2) {
1018 20           const int64_t s1 = moment_instant_rd_seconds(m1);
1019 20           const int64_t s2 = moment_instant_rd_seconds(m2);
1020             int r;
1021              
1022 20           r = (s1 > s2) - (s1 < s2);
1023 20 100         if (r == 0)
1024 6           r = (m1->nsec > m2->nsec) - (m1->nsec < m2->nsec);
1025 20           return r;
1026             }
1027              
1028             int
1029 0           moment_compare_local(const moment_t *m1, const moment_t *m2) {
1030 0           const int64_t s1 = moment_local_rd_seconds(m1);
1031 0           const int64_t s2 = moment_local_rd_seconds(m2);
1032             int r;
1033              
1034 0           r = (s1 > s2) - (s1 < s2);
1035 0 0         if (r == 0)
1036 0           r = (m1->nsec > m2->nsec) - (m1->nsec < m2->nsec);
1037 0           return r;
1038             }
1039              
1040             int
1041 0           THX_moment_compare_precision(pTHX_ const moment_t *m1, const moment_t *m2, IV precision) {
1042             int64_t n1, n2;
1043             int r;
1044              
1045 0 0         if (precision < -3 || precision > 9)
    0          
1046 0           croak("Parameter 'precision' is out of the range [-3, 9]");
1047              
1048 0 0         if (precision < 0) {
1049             int32_t n;
1050              
1051 0           n = 0;
1052 0           switch (precision) {
1053 0           case -1: n = 60; break;
1054 0           case -2: n = 3600; break;
1055 0           case -3: n = 86400; break;
1056             }
1057 0           n1 = moment_local_rd_seconds(m1);
1058 0           n2 = moment_local_rd_seconds(m2);
1059 0           n1 -= n1 % n;
1060 0           n2 -= n2 % n;
1061 0           n1 -= m1->offset * 60;
1062 0           n2 -= m2->offset * 60;
1063 0           r = (n1 > n2) - (n1 < n2);
1064             }
1065             else {
1066 0           n1 = moment_instant_rd_seconds(m1);
1067 0           n2 = moment_instant_rd_seconds(m2);
1068 0           r = (n1 > n2) - (n1 < n2);
1069 0 0         if (r == 0 && precision != 0) {
    0          
1070 0           n1 = m1->nsec - m1->nsec % kPow10[9 - precision];
1071 0           n2 = m2->nsec - m2->nsec % kPow10[9 - precision];
1072 0           r = (n1 > n2) - (n1 < n2);
1073             }
1074             }
1075 0           return r;
1076             }
1077              
1078             bool
1079 7869           moment_equals(const moment_t *m1, const moment_t *m2) {
1080 7869           return memcmp(m1, m2, sizeof(moment_t)) == 0;
1081             }
1082              
1083             int64_t
1084 252           moment_epoch(const moment_t *mt) {
1085 252           return (moment_instant_rd_seconds(mt) - UNIX_EPOCH);
1086             }
1087              
1088             int
1089 3777           moment_year(const moment_t *mt) {
1090 3777           return dt_year(moment_local_dt(mt));
1091             }
1092              
1093             int
1094 29827           moment_month(const moment_t *mt) {
1095 29827           return dt_month(moment_local_dt(mt));
1096             }
1097              
1098             int
1099 7           moment_quarter(const moment_t *mt) {
1100 7           return dt_quarter(moment_local_dt(mt));
1101             }
1102              
1103             int
1104 3           moment_week(const moment_t *mt) {
1105 3           return dt_woy(moment_local_dt(mt));
1106             }
1107              
1108             int
1109 371           moment_day_of_year(const moment_t *mt) {
1110 371           return dt_doy(moment_local_dt(mt));
1111             }
1112              
1113             int
1114 95           moment_day_of_quarter(const moment_t *mt) {
1115 95           return dt_doq(moment_local_dt(mt));
1116             }
1117              
1118             int
1119 851           moment_day_of_month(const moment_t *mt) {
1120 851           return dt_dom(moment_local_dt(mt));
1121             }
1122              
1123             int
1124 11809           moment_day_of_week(const moment_t *mt) {
1125 11809           return dt_dow(moment_local_dt(mt));
1126             }
1127              
1128             int
1129 32448           moment_hour(const moment_t *mt) {
1130 32448           return (int)((moment_local_rd_seconds(mt) / 3600) % 24);
1131             }
1132              
1133             int
1134 32480           moment_minute(const moment_t *mt) {
1135 32480           return (int)((moment_local_rd_seconds(mt) / 60) % 60);
1136             }
1137              
1138             int
1139 18           moment_minute_of_day(const moment_t *mt) {
1140 18           return (int)((moment_local_rd_seconds(mt) / 60) % 1440);
1141             }
1142              
1143             int
1144 32469           moment_second(const moment_t *mt) {
1145 32469           return (int)(moment_local_rd_seconds(mt) % 60);
1146             }
1147              
1148             int
1149 7751           moment_second_of_day(const moment_t *mt) {
1150 7751           return (int)(moment_local_rd_seconds(mt) % 86400);
1151             }
1152              
1153             int
1154 1470           moment_millisecond(const moment_t *mt) {
1155 1470           return (mt->nsec / 1000000);
1156             }
1157              
1158             int
1159 151           moment_millisecond_of_day(const moment_t *mt) {
1160 151           return moment_second_of_day(mt) * 1000 + moment_millisecond(mt);
1161             }
1162              
1163             int
1164 1319           moment_microsecond(const moment_t *mt) {
1165 1319           return (mt->nsec / 1000);
1166             }
1167              
1168             int64_t
1169 144           moment_microsecond_of_day(const moment_t *mt) {
1170 144           const int64_t sod = moment_local_rd_seconds(mt) % 86400;
1171 144           return sod * 1000000 + (mt->nsec / 1000);
1172             }
1173              
1174             int
1175 32445           moment_nanosecond(const moment_t *mt) {
1176 32445           return mt->nsec;
1177             }
1178              
1179             int64_t
1180 144           moment_nanosecond_of_day(const moment_t *mt) {
1181 144           const int64_t sod = moment_local_rd_seconds(mt) % 86400;
1182 144           return sod * 1000000000 + mt->nsec;
1183             }
1184              
1185             NV
1186 220           moment_jd(const moment_t *mt) {
1187 220           return moment_mjd(mt) + 2400000.5;
1188             }
1189              
1190             NV
1191 441           moment_mjd(const moment_t *mt) {
1192 441           const int64_t s = moment_instant_rd_seconds(mt);
1193 441           const int64_t d = (s / SECS_PER_DAY) - 678576;
1194 441           const int64_t n = (s % SECS_PER_DAY) * NANOS_PER_SEC + mt->nsec;
1195 441           return (NV)d + (NV)n * (1E-9/60/60/24);
1196             }
1197              
1198             NV
1199 220           moment_rd(const moment_t *mt) {
1200 220           const int64_t s = moment_local_rd_seconds(mt);
1201 220           const int64_t d = (s / SECS_PER_DAY);
1202 220           const int64_t n = (s % SECS_PER_DAY) * NANOS_PER_SEC + mt->nsec;
1203 220           return (NV)d + (NV)n * (1E-9/60/60/24);
1204             }
1205              
1206             int
1207 0           moment_rata_die_day(const moment_t *mt) {
1208 0           return dt_rdn(moment_local_dt(mt));
1209             }
1210              
1211             int
1212 32141           moment_offset(const moment_t *mt) {
1213 32141           return mt->offset;
1214             }
1215              
1216             int
1217 39           moment_precision(const moment_t *mt) {
1218             int v, i;
1219              
1220 39           v = mt->nsec;
1221 39 100         if (v != 0) {
1222 135 100         for (i = 8; i > 0; i--) {
1223 132 100         if ((v % kPow10[i]) == 0)
1224 24           break;
1225             }
1226 27           return 9 - i;
1227             }
1228 12           v = moment_second_of_day(mt);
1229 12 100         if (v != 0) {
1230 9 100         if ((v % 3600) == 0) return -2;
1231 6 100         else if ((v % 60) == 0) return -1;
1232 3           else return 0;
1233             }
1234 3           return -3;
1235             }
1236              
1237             int
1238 2           moment_length_of_year(const moment_t *mt) {
1239 2           return dt_length_of_year(moment_local_dt(mt));
1240             }
1241              
1242             int
1243 8           moment_length_of_quarter(const moment_t *mt) {
1244 8           return dt_length_of_quarter(moment_local_dt(mt));
1245             }
1246              
1247             int
1248 24           moment_length_of_month(const moment_t *mt) {
1249 24           return dt_length_of_month(moment_local_dt(mt));
1250             }
1251              
1252             int
1253 0           moment_length_of_week_year(const moment_t *mt) {
1254 0           return dt_length_of_week_year(moment_local_dt(mt));
1255             }
1256              
1257             bool
1258 0           moment_is_leap_year(const moment_t *mt) {
1259 0           return dt_leap_year(moment_year(mt));
1260             }
1261              
1262             int
1263 500           THX_moment_internal_western_easter(pTHX_ int64_t y) {
1264 500           THX_check_year(aTHX_ y);
1265 500           return dt_rdn(dt_from_easter((int)y, DT_WESTERN));
1266             }
1267              
1268             int
1269 0           THX_moment_internal_orthodox_easter(pTHX_ int64_t y) {
1270 0           THX_check_year(aTHX_ y);
1271 0           return dt_rdn(dt_from_easter((int)y, DT_ORTHODOX));
1272             }
1273