File Coverage

Moment.xs
Criterion Covered Total %
statement 334 420 79.5
branch 134 232 57.7
condition n/a
subroutine n/a
pod n/a
total 468 652 71.7


line stmt bran cond sub pod time code
1             #define PERL_NO_GET_CONTEXT
2             #include "EXTERN.h"
3             #include "perl.h"
4             #include "XSUB.h"
5             #include "ppport.h"
6             #include "moment.h"
7             #include "moment_fmt.h"
8             #include "moment_parse.h"
9              
10             typedef enum {
11             MOMENT_PARAM_UNKNOWN=0,
12             MOMENT_PARAM_YEAR,
13             MOMENT_PARAM_MONTH,
14             MOMENT_PARAM_DAY,
15             MOMENT_PARAM_HOUR,
16             MOMENT_PARAM_MINUTE,
17             MOMENT_PARAM_SECOND,
18             MOMENT_PARAM_NANOSECOND,
19             MOMENT_PARAM_OFFSET,
20             MOMENT_PARAM_LENIENT,
21             MOMENT_PARAM_REDUCED,
22             MOMENT_PARAM_EPOCH,
23             MOMENT_PARAM_PRECISION,
24             } moment_param_t;
25              
26             typedef int64_t I64V;
27              
28             #if IVSIZE >= 8
29             # define SvI64V(sv) (I64V)SvIV(sv)
30             # define newSVi64v(i64) newSViv((IV)i64)
31             # define XSRETURN_I64V(i64) XSRETURN_IV((IV)i64)
32             #else
33             # define SvI64V(sv) (I64V)SvNV(sv)
34             # define newSVi64v(i64) newSVnv((NV)i64)
35             # define XSRETURN_I64V(i64) XSRETURN_NV((NV)i64)
36             #endif
37              
38             #ifndef STR_WITH_LEN
39             #define STR_WITH_LEN(s) ("" s ""), (sizeof(s)-1)
40             #endif
41              
42             #ifndef gv_stashpvs
43             #define gv_stashpvs(s, flags) gv_stashpvn(STR_WITH_LEN(s), flags)
44             #endif
45              
46             #ifndef XSRETURN_BOOL
47             #define XSRETURN_BOOL(v) STMT_START { ST(0) = boolSV(v); XSRETURN(1); } STMT_END
48             #endif
49              
50             #ifndef XSRETURN_SV
51             #define XSRETURN_SV(sv) STMT_START { ST(0) = sv; XSRETURN(1); } STMT_END
52             #endif
53              
54             #ifndef cBOOL
55             #define cBOOL(cbool) ((cbool) ? (bool)1 : (bool)0)
56             #endif
57              
58             #ifndef PERL_UNUSED_VAR
59             # define PERL_UNUSED_VAR(x) ((void)x)
60             #endif
61              
62             #define MY_CXT_KEY "Time::Moment::_guts" XS_VERSION
63             typedef struct {
64             HV *stash;
65             } my_cxt_t;
66              
67             START_MY_CXT
68              
69             static void
70 24           setup_my_cxt(pTHX_ pMY_CXT) {
71 24           MY_CXT.stash = gv_stashpvs("Time::Moment", GV_ADD);
72 24           }
73              
74             static moment_param_t
75 1038           moment_param(const char *s, const STRLEN len) {
76 1038           switch (len) {
77 19           case 3:
78 19 50         if (memEQ(s, "day", 3))
79 19           return MOMENT_PARAM_DAY;
80 0           break;
81 614           case 4:
82 614 50         if (memEQ(s, "year", 4))
83 614           return MOMENT_PARAM_YEAR;
84 0 0         if (memEQ(s, "hour", 4))
85 0           return MOMENT_PARAM_HOUR;
86 0           break;
87 28           case 5:
88 28 100         if (memEQ(s, "month", 5))
89 19           return MOMENT_PARAM_MONTH;
90 9 50         if (memEQ(s, "epoch", 5))
91 9           return MOMENT_PARAM_EPOCH;
92 0           break;
93 87           case 6:
94 87 50         if (memEQ(s, "minute", 6))
95 0           return MOMENT_PARAM_MINUTE;
96 87 50         if (memEQ(s, "second", 6))
97 0           return MOMENT_PARAM_SECOND;
98 87 50         if (memEQ(s, "offset", 6))
99 87           return MOMENT_PARAM_OFFSET;
100 0           break;
101 69           case 7:
102 69 100         if (memEQ(s, "lenient", 7))
103 66           return MOMENT_PARAM_LENIENT;
104 3 50         if (memEQ(s, "reduced", 7))
105 3           return MOMENT_PARAM_REDUCED;
106 0           break;
107 212           case 9:
108 212 50         if (memEQ(s, "precision", 9))
109 212           return MOMENT_PARAM_PRECISION;
110 0           break;
111 9           case 10:
112 9 50         if (memEQ(s, "nanosecond", 10))
113 9           return MOMENT_PARAM_NANOSECOND;
114 0           break;
115             }
116 0           return MOMENT_PARAM_UNKNOWN;
117             }
118              
119             static moment_param_t
120 1038           THX_sv_moment_param(pTHX_ SV *sv) {
121             const char *str;
122             STRLEN len;
123              
124 1038           str = SvPV_const(sv, len);
125 1038           return moment_param(str, len);
126             }
127              
128             static SV *
129 5           THX_sv_as_object(pTHX_ SV *sv, const char *name) {
130 5           dSP;
131             SV *rv;
132             GV *method;
133             int count;
134              
135 5 50         if (!SvROK(sv))
136 0           return NULL;
137 5           rv = SvRV(sv);
138 5 50         if (!SvOBJECT(rv) || !SvSTASH(rv))
    50          
139 0           return NULL;
140 5 100         if (!(method = gv_fetchmethod(SvSTASH(rv), name)))
141 1           return NULL;
142              
143 4           ENTER;
144 4           SAVETMPS;
145 4 50         PUSHMARK(SP);
146 4 50         XPUSHs(sv);
147 4           PUTBACK;
148 4           count = call_sv((SV *)method, G_SCALAR);
149 4           SPAGAIN;
150 4 50         if (count != 1)
151 0           croak("method call returned %d values, 1 expected", count);
152 4           rv = newSVsv(POPs);
153 4           PUTBACK;
154 4 50         FREETMPS;
155 4           LEAVE;
156 4           return sv_2mortal(rv);
157             }
158              
159             static SV *
160 1           THX_sv_2neat(pTHX_ SV *sv) {
161 1 50         if (sv_isobject(sv)) {
162 1           SV * const rv = SvRV(sv);
163 1           const char *name = sv_reftype(rv, 1);
164 1           const char *type = sv_reftype(rv, 0);
165 1           sv = sv_newmortal();
166 1           sv_setpvf(sv, "%s=%s(0x%p)", name, type, rv);
167             }
168 1           return sv;
169             }
170              
171             static void
172 0           THX_croak_cmp(pTHX_ SV *sv1, SV *sv2, const bool swap, const char *name) {
173 0 0         if (swap) {
174 0           SV * const tmp = sv1;
175 0           sv1 = sv2;
176 0           sv2 = tmp;
177             }
178 0           croak("A %s object can only be compared to another %s object ('%"SVf"', '%"SVf"')",
179             name, name, THX_sv_2neat(aTHX_ sv1), THX_sv_2neat(aTHX_ sv2));
180             }
181              
182             static SV *
183 22641           THX_newSVmoment(pTHX_ const moment_t *m, HV *stash) {
184 22641           SV *pv = newSVpvn((const char *)m, sizeof(moment_t));
185 22641           SV *sv = newRV_noinc(pv);
186 22641           sv_bless(sv, stash);
187 22641           return sv;
188             }
189              
190             static SV *
191 64           THX_sv_set_moment(pTHX_ SV *sv, const moment_t *m) {
192 64 50         if (!SvROK(sv))
193 0           croak("panic: sv_set_moment called with nonreference");
194 64           sv_setpvn_mg(SvRV(sv), (const char *)m, sizeof(moment_t));
195 64           SvTEMP_off(sv);
196 64           return sv;
197             }
198              
199             static bool
200 124993           THX_sv_isa_stash(pTHX_ SV *sv, const char *klass, HV *stash, size_t size) {
201             SV *rv;
202              
203 124993 50         SvGETMAGIC(sv);
    0          
204 124993 50         if (!SvROK(sv))
205 0           return FALSE;
206 124993           rv = SvRV(sv);
207 124993 50         if (!(SvOBJECT(rv) && SvSTASH(rv) && SvPOKp(rv) && SvCUR(rv) == size))
    50          
    100          
    50          
208 5           return FALSE;
209 124988 100         return (SvSTASH(rv) == stash || sv_derived_from(sv, klass));
    50          
210             }
211              
212             static HV *
213 2493           THX_stash_constructor(pTHX_ SV *sv, const char *name, STRLEN namelen, HV *stash) {
214             const char *pv;
215             STRLEN len;
216              
217 2493 50         SvGETMAGIC(sv);
    0          
218 2493 50         if (SvROK(sv)) {
219 0           SV * const rv = SvRV(sv);
220 0 0         if (SvOBJECT(rv) && SvSTASH(rv))
    0          
221 0           return SvSTASH(rv);
222             }
223 2493           pv = SvPV_nomg_const(sv, len);
224 2493 100         if (len == namelen && memEQ(pv, name, namelen))
    50          
225 2492           return stash;
226 1           return gv_stashpvn(pv, len, GV_ADD);
227             }
228              
229             static bool
230 124993           THX_sv_isa_moment(pTHX_ SV *sv) {
231             dMY_CXT;
232 124993           return THX_sv_isa_stash(aTHX_ sv, "Time::Moment", MY_CXT.stash, sizeof(moment_t));
233             }
234              
235             static moment_t *
236 118468           THX_sv_2moment_ptr(pTHX_ SV *sv, const char *name) {
237 118468 50         if (!THX_sv_isa_moment(aTHX_ sv))
238 0           croak("%s is not an instance of Time::Moment", name);
239 118468           return (moment_t *)SvPVX_const(SvRV(sv));
240             }
241              
242             static moment_t
243 0           THX_sv_2moment(pTHX_ SV *sv, const char *name) {
244 0           return *THX_sv_2moment_ptr(aTHX_ sv, name);
245             }
246              
247             static SV *
248 5           THX_sv_2moment_coerce_sv(pTHX_ SV *sv, HV *stash) {
249             SV *res, *rv;
250              
251 5 50         if (THX_sv_isa_moment(aTHX_ sv))
252 0           return sv;
253 5           res = THX_sv_as_object(aTHX_ sv, "__as_Time_Moment");
254 5 100         if(!res || !THX_sv_isa_moment(aTHX_ res))
    50          
255 1           croak("Cannot coerce object of type %"SVf" to Time::Moment", THX_sv_2neat(aTHX_ sv));
256 4           rv = SvRV(res);
257 4 100         if (SvSTASH(rv) != stash) {
258 1           SvREFCNT_dec(SvSTASH(rv));
259 1           SvSTASH_set(rv, (HV*)SvREFCNT_inc(stash));
260             }
261 4           return res;
262             }
263              
264             #define dSTASH_CONSTRUCTOR(sv, name, dstash) \
265             HV * const stash = THX_stash_constructor(aTHX_ sv, STR_WITH_LEN(name), dstash)
266              
267             #define dSTASH_INVOCANT \
268             HV * const stash = SvSTASH(SvRV(ST(0)))
269              
270             #define dSTASH_CONSTRUCTOR_MOMENT(sv) \
271             dMY_CXT; \
272             dSTASH_CONSTRUCTOR(sv, "Time::Moment", MY_CXT.stash)
273              
274             #define newSVmoment(m, stash) \
275             THX_newSVmoment(aTHX_ m, stash)
276              
277             #define sv_set_moment(sv, m) \
278             THX_sv_set_moment(aTHX_ sv, m);
279              
280             #define sv_2moment_ptr(sv, name) \
281             THX_sv_2moment_ptr(aTHX_ sv, name)
282              
283             #define sv_2moment(sv, name) \
284             THX_sv_2moment(aTHX_ sv, name)
285              
286             #define sv_2moment_coerce_sv(sv, stash) \
287             THX_sv_2moment_coerce_sv(aTHX_ sv, stash)
288              
289             #define sv_isa_moment(sv) \
290             THX_sv_isa_moment(aTHX_ sv)
291              
292             #define croak_cmp(sv1, sv2, swap, name) \
293             THX_croak_cmp(aTHX_ sv1, sv2, swap, name)
294              
295             #define sv_moment_param(sv) \
296             THX_sv_moment_param(aTHX_ sv)
297              
298             #define sv_reusable(sv) \
299             (SvTEMP(sv) && SvREFCNT(sv) == 1 && SvROK(sv) && SvREFCNT(SvRV(sv)) == 1)
300              
301 0           XS(XS_Time_Moment_nil) {
302 0           dVAR; dXSARGS;
303             PERL_UNUSED_VAR(items);
304 0           XSRETURN_EMPTY;
305             }
306              
307 29860           XS(XS_Time_Moment_stringify) {
308 29860           dVAR; dXSARGS;
309 29860 50         if (items < 1)
310 0           croak("Wrong number of arguments to Time::Moment::(\"\"");
311 29860           ST(0) = moment_to_string(sv_2moment_ptr(ST(0), "self"), FALSE);
312 29860           XSRETURN(1);
313             }
314              
315 8           XS(XS_Time_Moment_ncmp) {
316 8           dVAR; dXSARGS;
317             const moment_t *m1, *m2;
318             bool swap;
319             SV *svm1, *svm2;
320              
321 8 50         if (items < 3)
322 0           croak("Wrong number of arguments to Time::Moment::(<=>");
323              
324 8           svm1 = ST(0);
325 8           svm2 = ST(1);
326 8           swap = cBOOL(SvTRUE(ST(2)));
327              
328 8 50         if (!sv_isa_moment(svm2))
329 0           croak_cmp(svm1, svm2, swap, "Time::Moment");
330 8           m1 = sv_2moment_ptr(svm1, "self");
331 8           m2 = sv_2moment_ptr(svm2, "other");
332 8 50         if (swap) {
333 0           const moment_t *tmp = m1;
334 0           m1 = m2;
335 0           m2 = tmp;
336             }
337 8           XSRETURN_IV(moment_compare_instant(m1, m2));
338             }
339              
340             #ifdef HAS_GETTIMEOFDAY
341             static moment_t
342 2           THX_moment_now(pTHX_ bool utc) {
343             struct timeval tv;
344             IV off, sec;
345              
346 2           gettimeofday(&tv, NULL);
347 2 100         if (utc)
348 1           off = 0;
349             else {
350 1           const time_t when = tv.tv_sec;
351             struct tm *tm;
352             #ifdef HAS_LOCALTIME_R
353             struct tm tmbuf;
354             #ifdef LOCALTIME_R_NEEDS_TZSET
355             tzset();
356             #endif
357             tm = localtime_r(&when, &tmbuf);
358             #else
359 1           tm = localtime(&when);
360             #endif
361 1 50         if (tm == NULL)
362 0           croak("localtime() failed: %s", Strerror(errno));
363              
364 1           sec = ((1461 * (tm->tm_year - 1) >> 2) + tm->tm_yday - 25202) * 86400LL
365 1           + tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
366 1           off = (sec - tv.tv_sec) / 60;
367             }
368 2           return moment_from_epoch(tv.tv_sec, tv.tv_usec * 1000, off);
369             }
370             #endif
371              
372             MODULE = Time::Moment PACKAGE = Time::Moment
373              
374             PROTOTYPES: DISABLE
375              
376             BOOT:
377             {
378             MY_CXT_INIT;
379 24           setup_my_cxt(aTHX_ aMY_CXT);
380             #if (PERL_REVISION == 5 && PERL_VERSION < 9)
381             PL_amagic_generation++;
382             #endif
383 24           sv_setsv(get_sv("Time::Moment::()", GV_ADD), &PL_sv_yes);
384 24           newXS("Time::Moment::()", XS_Time_Moment_nil, file);
385 24           newXS("Time::Moment::(\"\"", XS_Time_Moment_stringify, file);
386 24           newXS("Time::Moment::(<=>", XS_Time_Moment_ncmp, file);
387             }
388              
389             #ifdef USE_ITHREADS
390              
391             void
392             CLONE(...)
393             CODE:
394             {
395             MY_CXT_CLONE;
396             setup_my_cxt(aTHX_ aMY_CXT);
397             PERL_UNUSED_VAR(items);
398             }
399              
400             #endif
401              
402             moment_t
403             new(klass, ...)
404             SV *klass
405             PREINIT:
406 614           dSTASH_CONSTRUCTOR_MOMENT(klass);
407 614           IV year = 1, month = 1, day = 1;
408 614           IV hour = 0, minute = 0, second = 0, ns = 0, offset = 0;
409             I32 i;
410             CODE:
411 614 50         if (((items - 1) % 2) != 0)
412 0           croak("Odd number of elements in call to constructor when named parameters were expected");
413              
414 1349 100         for (i = 1; i < items; i += 2) {
415 735           switch (sv_moment_param(ST(i))) {
416 614           case MOMENT_PARAM_YEAR: year = SvIV(ST(i+1)); break;
417 19           case MOMENT_PARAM_MONTH: month = SvIV(ST(i+1)); break;
418 19           case MOMENT_PARAM_DAY: day = SvIV(ST(i+1)); break;
419 0           case MOMENT_PARAM_HOUR: hour = SvIV(ST(i+1)); break;
420 0           case MOMENT_PARAM_MINUTE: minute = SvIV(ST(i+1)); break;
421 0           case MOMENT_PARAM_SECOND: second = SvIV(ST(i+1)); break;
422 0           case MOMENT_PARAM_NANOSECOND: ns = SvIV(ST(i+1)); break;
423 83           case MOMENT_PARAM_OFFSET: offset = SvIV(ST(i+1)); break;
424 0           default: croak("Unrecognised parameter: '%"SVf"'", ST(i));
425             }
426             }
427 614           RETVAL = moment_new(year, month, day, hour, minute, second, ns, offset);
428             OUTPUT:
429             RETVAL
430              
431             #ifdef HAS_GETTIMEOFDAY
432              
433             moment_t
434             now(klass)
435             SV *klass
436             ALIAS:
437             Time::Moment::now = 0
438             Time::Moment::now_utc = 1
439             PREINIT:
440 2           dSTASH_CONSTRUCTOR_MOMENT(klass);
441             CODE:
442 2           RETVAL = THX_moment_now(aTHX_ !!ix);
443             OUTPUT:
444             RETVAL
445              
446             #endif
447              
448             moment_t
449             from_epoch(klass, seconds, ...)
450             SV *klass
451             SV *seconds
452             PREINIT:
453 423           dSTASH_CONSTRUCTOR_MOMENT(klass);
454 423           IV precision = 6;
455             CODE:
456 423 100         if (items == 2) {
457 191 100         if (SvIOK(seconds))
458 6           RETVAL = moment_from_epoch(SvI64V(seconds), 0, 0);
459             else
460 185           RETVAL = moment_from_epoch_nv(SvNV(seconds), precision);
461             }
462 232 100         else if (items == 3) {
463 14           RETVAL = moment_from_epoch(SvI64V(seconds), SvIV(ST(2)), 0);
464             }
465             else {
466 218           SV *nanosecond = NULL;
467             I32 i;
468              
469 218 50         if ((items % 2) != 0)
470 0           croak("Odd number of elements in named parameters");
471              
472 436 100         for (i = 2; i < items; i += 2) {
473 218           switch (sv_moment_param(ST(i))) {
474 9           case MOMENT_PARAM_NANOSECOND:
475 9           nanosecond = ST(i+1);
476 9           break;
477 209           case MOMENT_PARAM_PRECISION:
478 209           precision = SvIV(ST(i+1));
479 209           break;
480 0           default:
481 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
482             }
483             }
484              
485 218 100         if (nanosecond)
486 9           RETVAL = moment_from_epoch(SvI64V(seconds), SvIV(nanosecond), 0);
487             else {
488 209 50         if (SvIOK(seconds))
489 0           RETVAL = moment_from_epoch(SvI64V(seconds), 0, 0);
490             else
491 209           RETVAL = moment_from_epoch_nv(SvNV(seconds), precision);
492             }
493             }
494             OUTPUT:
495             RETVAL
496              
497             moment_t
498             from_string(klass, string, ...)
499             SV *klass
500             SV *string
501             PREINIT:
502 777           dSTASH_CONSTRUCTOR_MOMENT(klass);
503             bool lenient;
504             const char *str;
505             STRLEN len;
506             I32 i;
507             CODE:
508 777 50         if ((items % 2) != 0)
509 0           croak("Odd number of elements in named parameters");
510              
511 777           lenient = FALSE;
512 843 100         for (i = 2; i < items; i += 2) {
513 66 50         switch (sv_moment_param(ST(i))) {
514 66           case MOMENT_PARAM_LENIENT:
515 66           lenient = cBOOL(SvTRUE((ST(i+1))));
516 66           break;
517 0           default:
518 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
519             }
520             }
521 777           str = SvPV_const(string, len);
522 777           RETVAL = moment_from_string(str, len, lenient);
523             OUTPUT:
524             RETVAL
525              
526             moment_t
527             from_rd(klass, jd, ...)
528             SV *klass
529             NV jd
530             PREINIT:
531 672           dSTASH_CONSTRUCTOR_MOMENT(klass);
532 672           NV epoch = 0;
533 672           IV precision = 3;
534 672           IV offset = 0;
535             I32 i;
536             ALIAS:
537             Time::Moment::from_rd = 0
538             Time::Moment::from_jd = 1
539             Time::Moment::from_mjd = 2
540             CODE:
541 672 50         if ((items % 2) != 0)
542 0           croak("Odd number of elements in named parameters");
543              
544 672           switch (ix) {
545 223           case 1: epoch = -1721424.5; break;
546 224           case 2: epoch = 678576; break;
547             }
548              
549 688 100         for (i = 2; i < items; i += 2) {
550 16           switch (sv_moment_param(ST(i))) {
551 3           case MOMENT_PARAM_PRECISION:
552 3           precision = SvIV(ST(i+1));
553 3           break;
554 9           case MOMENT_PARAM_EPOCH:
555 9           epoch = SvNV(ST(i+1));
556 9           break;
557 4           case MOMENT_PARAM_OFFSET:
558 4 50         if (ix == 0) {
559 4           offset = SvIV(ST(i+1));
560 4           break;
561             }
562             /* FALLTROUGH */
563             default:
564 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
565             }
566             }
567 672 100         if (ix == 0) RETVAL = moment_from_rd(jd, epoch, precision, offset);
568 447 100         else if (ix == 1) RETVAL = moment_from_jd(jd, epoch, precision);
569 224           else RETVAL = moment_from_mjd(jd, epoch, precision);
570              
571             OUTPUT:
572             RETVAL
573              
574             void
575             from_object(klass, object)
576             SV *klass
577             SV *object
578             PREINIT:
579 5           dSTASH_CONSTRUCTOR_MOMENT(klass);
580             CODE:
581 5           XSRETURN_SV(sv_2moment_coerce_sv(object, stash));
582              
583             moment_t
584             at_utc(self)
585             const moment_t *self
586             PREINIT:
587 2950           dSTASH_INVOCANT;
588             ALIAS:
589             Time::Moment::at_utc = 0
590             Time::Moment::at_midnight = 1
591             Time::Moment::at_noon = 2
592             Time::Moment::at_last_day_of_year = 3
593             Time::Moment::at_last_day_of_quarter = 4
594             Time::Moment::at_last_day_of_month = 5
595             CODE:
596 2950           switch (ix) {
597 3           case 0: RETVAL = moment_at_utc(self); break;
598 3           case 1: RETVAL = moment_at_midnight(self); break;
599 3           case 2: RETVAL = moment_at_noon(self); break;
600 5           case 3: RETVAL = moment_at_last_day_of_year(self); break;
601 11           case 4: RETVAL = moment_at_last_day_of_quarter(self); break;
602 2925           case 5: RETVAL = moment_at_last_day_of_month(self); break;
603             }
604 2950 100         if (moment_equals(self, &RETVAL))
605 115           XSRETURN(1);
606 2865 100         if (sv_reusable(ST(0))) {
    50          
    50          
    50          
607 30           sv_set_moment(ST(0), &RETVAL);
608 30           XSRETURN(1);
609             }
610             OUTPUT:
611             RETVAL
612              
613             moment_t
614             plus_seconds(self, value)
615             const moment_t *self
616             I64V value
617             PREINIT:
618 7603           dSTASH_INVOCANT;
619             ALIAS:
620             Time::Moment::plus_years = MOMENT_UNIT_YEARS
621             Time::Moment::plus_months = MOMENT_UNIT_MONTHS
622             Time::Moment::plus_weeks = MOMENT_UNIT_WEEKS
623             Time::Moment::plus_days = MOMENT_UNIT_DAYS
624             Time::Moment::plus_hours = MOMENT_UNIT_HOURS
625             Time::Moment::plus_minutes = MOMENT_UNIT_MINUTES
626             Time::Moment::plus_seconds = MOMENT_UNIT_SECONDS
627             Time::Moment::plus_milliseconds = MOMENT_UNIT_MILLIS
628             Time::Moment::plus_microseconds = MOMENT_UNIT_MICROS
629             Time::Moment::plus_nanoseconds = MOMENT_UNIT_NANOS
630             CODE:
631 7603 100         if (value == 0)
632 416           XSRETURN(1);
633 7187           RETVAL = moment_plus_unit(self, (moment_unit_t)ix, value);
634 7187 100         if (sv_reusable(ST(0))) {
    50          
    50          
    50          
635 0           sv_set_moment(ST(0), &RETVAL);
636 0           XSRETURN(1);
637             }
638             OUTPUT:
639             RETVAL
640              
641             moment_t
642             minus_seconds(self, value)
643             const moment_t *self
644             I64V value
645             PREINIT:
646 6154           dSTASH_INVOCANT;
647             ALIAS:
648             Time::Moment::minus_years = MOMENT_UNIT_YEARS
649             Time::Moment::minus_months = MOMENT_UNIT_MONTHS
650             Time::Moment::minus_weeks = MOMENT_UNIT_WEEKS
651             Time::Moment::minus_days = MOMENT_UNIT_DAYS
652             Time::Moment::minus_hours = MOMENT_UNIT_HOURS
653             Time::Moment::minus_minutes = MOMENT_UNIT_MINUTES
654             Time::Moment::minus_seconds = MOMENT_UNIT_SECONDS
655             Time::Moment::minus_milliseconds = MOMENT_UNIT_MILLIS
656             Time::Moment::minus_microseconds = MOMENT_UNIT_MICROS
657             Time::Moment::minus_nanoseconds = MOMENT_UNIT_NANOS
658             CODE:
659 6154 100         if (value == 0)
660 390           XSRETURN(1);
661 5764           RETVAL = moment_minus_unit(self, (moment_unit_t)ix, value);
662 5764 50         if (sv_reusable(ST(0))) {
    0          
    0          
    0          
663 0           sv_set_moment(ST(0), &RETVAL);
664 0           XSRETURN(1);
665             }
666             OUTPUT:
667             RETVAL
668              
669             void
670             delta_years(self, other)
671             const moment_t *self
672             const moment_t *other
673             PREINIT:
674             int64_t delta;
675             ALIAS:
676             Time::Moment::delta_years = MOMENT_UNIT_YEARS
677             Time::Moment::delta_months = MOMENT_UNIT_MONTHS
678             Time::Moment::delta_weeks = MOMENT_UNIT_WEEKS
679             Time::Moment::delta_days = MOMENT_UNIT_DAYS
680             Time::Moment::delta_hours = MOMENT_UNIT_HOURS
681             Time::Moment::delta_minutes = MOMENT_UNIT_MINUTES
682             Time::Moment::delta_seconds = MOMENT_UNIT_SECONDS
683             Time::Moment::delta_milliseconds = MOMENT_UNIT_MILLIS
684             Time::Moment::delta_microseconds = MOMENT_UNIT_MICROS
685             Time::Moment::delta_nanoseconds = MOMENT_UNIT_NANOS
686             PPCODE:
687 783           delta = moment_delta_unit(self, other, (moment_unit_t)ix);
688 783           XSRETURN_I64V(delta);
689              
690             void
691             with(self, adjuster)
692             const moment_t *self
693             SV *adjuster
694             PREINIT:
695             I32 count;
696             PERL_UNUSED_VAR(self);
697             PPCODE:
698 6508 50         SvGETMAGIC(adjuster);
    0          
699 6508 50         if (SvROK(adjuster))
700 6508           adjuster = SvRV(adjuster);
701 6508 50         if (SvTYPE(adjuster) != SVt_PVCV || SvOBJECT(adjuster))
    50          
702 0           croak("Parameter: 'adjuster' is not a CODE reference");
703 6508 50         PUSHMARK(SP);
704 6508           SP += 1;
705 6508           PUTBACK;
706 6508           count = call_sv(adjuster, G_SCALAR);
707 6508 50         if (count != 1)
708 0           croak("Expected one return value from adjuster, got %d elements", count);
709 6508 50         if (!sv_isa_moment(ST(0)))
710 0           croak("Expected an instance of Time::Moment from adjuster, got '%"SVf"'",
711             THX_sv_2neat(aTHX_ ST(0)));
712 6508           SPAGAIN;
713              
714             moment_t
715             with_year(self, value)
716             const moment_t *self
717             I64V value
718             PREINIT:
719 4876           dSTASH_INVOCANT;
720             ALIAS:
721             Time::Moment::with_year = MOMENT_FIELD_YEAR
722             Time::Moment::with_quarter = MOMENT_FIELD_QUARTER_OF_YEAR
723             Time::Moment::with_month = MOMENT_FIELD_MONTH_OF_YEAR
724             Time::Moment::with_week = MOMENT_FIELD_WEEK_OF_YEAR
725             Time::Moment::with_day_of_year = MOMENT_FIELD_DAY_OF_YEAR
726             Time::Moment::with_day_of_quarter = MOMENT_FIELD_DAY_OF_QUARTER
727             Time::Moment::with_day_of_month = MOMENT_FIELD_DAY_OF_MONTH
728             Time::Moment::with_day_of_week = MOMENT_FIELD_DAY_OF_WEEK
729             Time::Moment::with_hour = MOMENT_FIELD_HOUR_OF_DAY
730             Time::Moment::with_minute = MOMENT_FIELD_MINUTE_OF_HOUR
731             Time::Moment::with_minute_of_day = MOMENT_FIELD_MINUTE_OF_DAY
732             Time::Moment::with_second = MOMENT_FIELD_SECOND_OF_MINUTE
733             Time::Moment::with_second_of_day = MOMENT_FIELD_SECOND_OF_DAY
734             Time::Moment::with_millisecond = MOMENT_FIELD_MILLI_OF_SECOND
735             Time::Moment::with_millisecond_of_day = MOMENT_FIELD_MILLI_OF_DAY
736             Time::Moment::with_microsecond = MOMENT_FIELD_MICRO_OF_SECOND
737             Time::Moment::with_microsecond_of_day = MOMENT_FIELD_MICRO_OF_DAY
738             Time::Moment::with_nanosecond = MOMENT_FIELD_NANO_OF_SECOND
739             Time::Moment::with_nanosecond_of_day = MOMENT_FIELD_NANO_OF_DAY
740             Time::Moment::with_precision = MOMENT_FIELD_PRECISION
741             Time::Moment::with_rdn = MOMENT_FIELD_RATA_DIE_DAY
742             CODE:
743 4876           RETVAL = moment_with_field(self, (moment_component_t)ix, value);
744 4876 100         if (moment_equals(self, &RETVAL))
745 475           XSRETURN(1);
746 4431 100         if (sv_reusable(ST(0))) {
    50          
    50          
    50          
747 30           sv_set_moment(ST(0), &RETVAL);
748 30           XSRETURN(1);
749             }
750             OUTPUT:
751             RETVAL
752              
753             moment_t
754             with_offset_same_instant(self, offset)
755             const moment_t *self
756             IV offset
757             PREINIT:
758 43           dSTASH_INVOCANT;
759             ALIAS:
760             Time::Moment::with_offset_same_instant = 0
761             Time::Moment::with_offset_same_local = 1
762             CODE:
763 43 100         if (ix == 0)
764 25           RETVAL = moment_with_offset_same_instant(self, offset);
765             else
766 18           RETVAL = moment_with_offset_same_local(self, offset);
767              
768 43 100         if (moment_equals(self, &RETVAL))
769 11           XSRETURN(1);
770 36 100         if (sv_reusable(ST(0))) {
    50          
    50          
    50          
771 4           sv_set_moment(ST(0), &RETVAL);
772 4           XSRETURN(1);
773             }
774             OUTPUT:
775             RETVAL
776              
777             void
778             year(self)
779             const moment_t *self
780             ALIAS:
781             Time::Moment::year = 0
782             Time::Moment::quarter = 1
783             Time::Moment::month = 2
784             Time::Moment::week = 3
785             Time::Moment::day_of_year = 4
786             Time::Moment::day_of_quarter = 5
787             Time::Moment::day_of_month = 6
788             Time::Moment::day_of_week = 7
789             Time::Moment::hour = 8
790             Time::Moment::minute = 9
791             Time::Moment::minute_of_day = 10
792             Time::Moment::second = 11
793             Time::Moment::second_of_day = 12
794             Time::Moment::millisecond = 13
795             Time::Moment::millisecond_of_day = 14
796             Time::Moment::microsecond = 15
797             Time::Moment::nanosecond = 16
798             Time::Moment::offset = 17
799             Time::Moment::precision = 18
800             Time::Moment::rdn = 19
801             PREINIT:
802 55805           IV v = 0;
803             PPCODE:
804 55805           switch (ix) {
805 3777           case 0: v = moment_year(self); break;
806 7           case 1: v = moment_quarter(self); break;
807 29827           case 2: v = moment_month(self); break;
808 3           case 3: v = moment_week(self); break;
809 371           case 4: v = moment_day_of_year(self); break;
810 95           case 5: v = moment_day_of_quarter(self); break;
811 851           case 6: v = moment_day_of_month(self); break;
812 11809           case 7: v = moment_day_of_week(self); break;
813 1309           case 8: v = moment_hour(self); break;
814 1309           case 9: v = moment_minute(self); break;
815 9           case 10: v = moment_minute_of_day(self); break;
816 1309           case 11: v = moment_second(self); break;
817 36           case 12: v = moment_second_of_day(self); break;
818 1319           case 13: v = moment_millisecond(self); break;
819 151           case 14: v = moment_millisecond_of_day(self); break;
820 1319           case 15: v = moment_microsecond(self); break;
821 1396           case 16: v = moment_nanosecond(self); break;
822 869           case 17: v = moment_offset(self); break;
823 39           case 18: v = moment_precision(self); break;
824 0           case 19: v = moment_rata_die_day(self); break;
825             }
826 55805           XSRETURN_IV(v);
827              
828             void
829             epoch(self)
830             const moment_t *self
831             ALIAS:
832             Time::Moment::epoch = 0
833             Time::Moment::utc_rd_as_seconds = 1
834             Time::Moment::local_rd_as_seconds = 2
835             Time::Moment::microsecond_of_day = 3
836             Time::Moment::nanosecond_of_day = 4
837             PREINIT:
838 595           int64_t v = 0;
839             PPCODE:
840 595           switch (ix) {
841 249           case 0: v = moment_epoch(self); break;
842 29           case 1: v = moment_instant_rd_seconds(self); break;
843 29           case 2: v = moment_local_rd_seconds(self); break;
844 144           case 3: v = moment_microsecond_of_day(self); break;
845 144           case 4: v = moment_nanosecond_of_day(self); break;
846             }
847 595           XSRETURN_I64V(v);
848              
849             void
850             jd(self, ...)
851             const moment_t *self
852             ALIAS:
853             Time::Moment::jd = 0
854             Time::Moment::mjd = 1
855             Time::Moment::rd = 2
856             PREINIT:
857 661           NV v = 0;
858 661           IV precision = 3;
859             moment_t adjusted;
860             I32 i;
861             PPCODE:
862 661 50         if (((items - 1) % 2) != 0)
863 0           croak("Odd number of elements in named parameters");
864              
865 661 50         for (i = 1; i < items; i += 2) {
866 0 0         switch (sv_moment_param(ST(i))) {
867 0           case MOMENT_PARAM_PRECISION:
868 0           precision = SvIV(ST(i+1));
869 0           break;
870 0           default:
871 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
872             }
873             }
874 661           adjusted = moment_with_precision(self, precision);
875 661           switch (ix) {
876 220           case 0: v = moment_jd(&adjusted); break;
877 221           case 1: v = moment_mjd(&adjusted); break;
878 220           case 2: v = moment_rd(&adjusted); break;
879             }
880 661           XSRETURN_NV(v);
881              
882             void
883             length_of_year(self)
884             const moment_t *self
885             ALIAS:
886             Time::Moment::length_of_year = 0
887             Time::Moment::length_of_quarter = 1
888             Time::Moment::length_of_month = 2
889             Time::Moment::length_of_week_year = 3
890             PREINIT:
891 34           IV v = 0;
892             PPCODE:
893 34           switch (ix) {
894 2           case 0: v = moment_length_of_year(self); break;
895 8           case 1: v = moment_length_of_quarter(self); break;
896 24           case 2: v = moment_length_of_month(self); break;
897 0           case 3: v = moment_length_of_week_year(self); break;
898             }
899 34           XSRETURN_IV(v);
900              
901             void
902             utc_rd_values(self)
903             const moment_t *self
904             ALIAS:
905             Time::Moment::utc_rd_values = 0
906             Time::Moment::local_rd_values = 1
907             PREINIT:
908             IV rdn, sod, nos;
909             PPCODE:
910 2 50         if (ix == 0)
911 2           moment_to_instant_rd_values(self, &rdn, &sod, &nos);
912             else
913 0           moment_to_local_rd_values(self, &rdn, &sod, &nos);
914 2 50         EXTEND(SP, 3);
915 2           mPUSHi(rdn);
916 2           mPUSHi(sod);
917 2           mPUSHi(nos);
918 2           XSRETURN(3);
919              
920             void
921             compare(self, other, ...)
922             const moment_t *self
923             const moment_t *other
924             PREINIT:
925 4           IV precision = 9;
926             I32 i;
927             IV r;
928             PPCODE:
929 4 50         if ((items % 2) != 0)
930 0           croak("Odd number of elements in named parameters");
931              
932 4 50         for (i = 2; i < items; i += 2) {
933 0 0         switch (sv_moment_param(ST(i))) {
934 0           case MOMENT_PARAM_PRECISION:
935 0           precision = SvIV(ST(i+1));
936 0           break;
937 0           default:
938 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
939             }
940             }
941 4 50         if (precision == 9)
942 4           r = moment_compare_instant(self, other);
943             else
944 0           r = moment_compare_precision(self, other, precision);
945 4           XSRETURN_IV(r);
946              
947             void
948             is_equal(self, other)
949             const moment_t *self
950             const moment_t *other
951             ALIAS:
952             Time::Moment::is_equal = 0
953             Time::Moment::is_before = 1
954             Time::Moment::is_after = 2
955             PREINIT:
956 8           bool v = FALSE;
957             PPCODE:
958 8           switch (ix) {
959 4           case 0: v = moment_compare_instant(self, other) == 0; break;
960 2           case 1: v = moment_compare_instant(self, other) < 0; break;
961 2           case 2: v = moment_compare_instant(self, other) > 0; break;
962             }
963 8 100         XSRETURN_BOOL(v);
964              
965             void
966             is_leap_year(self)
967             const moment_t *self
968             PPCODE:
969 0 0         XSRETURN_BOOL(moment_is_leap_year(self));
970              
971             void
972             strftime(self, format)
973             const moment_t *self
974             SV *format
975             PREINIT:
976             STRLEN len;
977             const char *str;
978             SV *ret;
979             PPCODE:
980 634           str = SvPV_const(format, len);
981 634           ret = moment_strftime(self, str, len);
982 634 50         if (SvUTF8(format))
983 0           SvUTF8_on(ret);
984 634           XSRETURN_SV(ret);
985              
986             void
987             to_string(self, ...)
988             const moment_t *self
989             PREINIT:
990             bool reduced;
991             I32 i;
992             PPCODE:
993 1137 50         if (((items - 1) % 2) != 0)
994 0           croak("Odd number of elements in named parameters");
995              
996 1137           reduced = FALSE;
997 1140 100         for (i = 1; i < items; i += 2) {
998 3 50         switch (sv_moment_param(ST(i))) {
999 3           case MOMENT_PARAM_REDUCED:
1000 3           reduced = cBOOL(SvTRUE((ST(i+1))));
1001 3           break;
1002 0           default:
1003 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
1004             }
1005             }
1006 1137           XSRETURN_SV(moment_to_string(self, reduced));
1007              
1008              
1009             MODULE = Time::Moment PACKAGE = Time::Moment::Internal
1010              
1011             PROTOTYPES: DISABLE
1012              
1013             void
1014             western_easter_sunday(year)
1015             IV year
1016             PPCODE:
1017 500           XSRETURN_IV(moment_internal_western_easter(year));
1018              
1019             void
1020             orthodox_easter_sunday(year)
1021             IV year
1022             PPCODE:
1023 0           XSRETURN_IV(moment_internal_orthodox_easter(year));
1024              
1025