File Coverage

src/moment.c
Criterion Covered Total %
statement 518 660 78.4
branch 118 238 49.5
condition n/a
subroutine n/a
pod n/a
total 636 898 70.8


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