File Coverage

Moment.xs
Criterion Covered Total %
statement 315 396 79.5
branch 173 396 43.6
condition n/a
subroutine n/a
pod n/a
total 488 792 61.6


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 538           moment_param(const char *s, const STRLEN len) {
76 538           switch (len) {
77             case 3:
78 19 50         if (memEQ(s, "day", 3))
79 19           return MOMENT_PARAM_DAY;
80 0           break;
81             case 4:
82 114 50         if (memEQ(s, "year", 4))
83 114           return MOMENT_PARAM_YEAR;
84 0 0         if (memEQ(s, "hour", 4))
85 0           return MOMENT_PARAM_HOUR;
86 0           break;
87             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             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             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             case 9:
108 212 50         if (memEQ(s, "precision", 9))
109 212           return MOMENT_PARAM_PRECISION;
110 0           break;
111             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 538           THX_sv_moment_param(pTHX_ SV *sv) {
121             const char *str;
122             STRLEN len;
123              
124 538 50         str = SvPV_const(sv, len);
125 538           return moment_param(str, len);
126             }
127              
128             static SV *
129 4           THX_sv_as_object(pTHX_ SV *sv, const char *name) {
130 4           dSP;
131             SV *rv;
132             GV *method;
133             int count;
134              
135 4 50         if (!SvROK(sv))
136 0           return NULL;
137 4           rv = SvRV(sv);
138 4 50         if (!SvOBJECT(rv) || !SvSTASH(rv))
    50          
139 0           return NULL;
140 4 100         if (!(method = gv_fetchmethod(SvSTASH(rv), name)))
141 1           return NULL;
142              
143 3           ENTER;
144 3           SAVETMPS;
145 3 50         PUSHMARK(SP);
146 3 50         XPUSHs(sv);
147 3           PUTBACK;
148 3           count = call_sv((SV *)method, G_SCALAR);
149 3           SPAGAIN;
150 3 50         if (count != 1)
151 0           croak("method call returned %d values, 1 expected", count);
152 3           rv = newSVsv(POPs);
153 3           PUTBACK;
154 3 50         FREETMPS;
155 3           LEAVE;
156 3           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 3904           THX_newSVmoment(pTHX_ const moment_t *m, HV *stash) {
184 3904           SV *pv = newSVpvn((const char *)m, sizeof(moment_t));
185 3904           SV *sv = newRV_noinc(pv);
186 3904           sv_bless(sv, stash);
187 3904           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 23748           THX_sv_isa_stash(pTHX_ SV *sv, const char *klass, HV *stash, size_t size) {
201             SV *rv;
202              
203 23748 50         SvGETMAGIC(sv);
    0          
204 23748 50         if (!SvROK(sv))
205 0           return FALSE;
206 23748           rv = SvRV(sv);
207 23748 50         if (!(SvOBJECT(rv) && SvSTASH(rv) && SvPOKp(rv) && SvCUR(rv) == size))
    50          
    100          
    50          
208 4           return FALSE;
209 23744 50         return (SvSTASH(rv) == stash || sv_derived_from(sv, klass));
    0          
210             }
211              
212             static HV *
213 1480           THX_stash_constructor(pTHX_ SV *sv, const char *name, STRLEN namelen, HV *stash) {
214             const char *pv;
215             STRLEN len;
216              
217 1480 50         SvGETMAGIC(sv);
    0          
218 1480 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 1480 50         pv = SvPV_nomg_const(sv, len);
224 1480 50         if (len == namelen && memEQ(pv, name, namelen))
    50          
225 1480           return stash;
226 1480           return gv_stashpvn(pv, len, GV_ADD);
227             }
228              
229             static bool
230 23748           THX_sv_isa_moment(pTHX_ SV *sv) {
231             dMY_CXT;
232 23748           return THX_sv_isa_stash(aTHX_ sv, "Time::Moment", MY_CXT.stash, sizeof(moment_t));
233             }
234              
235             static moment_t *
236 23537           THX_sv_2moment_ptr(pTHX_ SV *sv, const char *name) {
237 23537 50         if (!THX_sv_isa_moment(aTHX_ sv))
238 0           croak("%s is not an instance of Time::Moment", name);
239 23537           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 4           THX_sv_2moment_coerce_sv(pTHX_ SV *sv) {
249             SV *res;
250              
251 4 50         if (THX_sv_isa_moment(aTHX_ sv))
252 0           return sv;
253 4           res = THX_sv_as_object(aTHX_ sv, "__as_Time_Moment");
254 4 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 3           return res;
257             }
258              
259             #define dSTASH_CONSTRUCTOR(sv, name, dstash) \
260             HV * const stash = THX_stash_constructor(aTHX_ sv, STR_WITH_LEN(name), dstash)
261              
262             #define dSTASH_INVOCANT \
263             HV * const stash = SvSTASH(SvRV(ST(0)))
264              
265             #define dSTASH_CONSTRUCTOR_MOMENT(sv) \
266             dMY_CXT; \
267             dSTASH_CONSTRUCTOR(sv, "Time::Moment", MY_CXT.stash)
268              
269             #define newSVmoment(m, stash) \
270             THX_newSVmoment(aTHX_ m, stash)
271              
272             #define sv_set_moment(sv, m) \
273             THX_sv_set_moment(aTHX_ sv, m);
274              
275             #define sv_2moment_ptr(sv, name) \
276             THX_sv_2moment_ptr(aTHX_ sv, name)
277              
278             #define sv_2moment(sv, name) \
279             THX_sv_2moment(aTHX_ sv, name)
280              
281             #define sv_2moment_coerce_sv(sv) \
282             THX_sv_2moment_coerce_sv(aTHX_ sv)
283              
284             #define sv_isa_moment(sv) \
285             THX_sv_isa_moment(aTHX_ sv)
286              
287             #define croak_cmp(sv1, sv2, swap, name) \
288             THX_croak_cmp(aTHX_ sv1, sv2, swap, name)
289              
290             #define sv_moment_param(sv) \
291             THX_sv_moment_param(aTHX_ sv)
292              
293             #define sv_reusable(sv) \
294             (SvTEMP(sv) && SvREFCNT(sv) == 1 && SvROK(sv) && SvREFCNT(SvRV(sv)) == 1)
295              
296 0           XS(XS_Time_Moment_nil) {
297 0           dVAR; dXSARGS;
298             PERL_UNUSED_VAR(items);
299 0           XSRETURN_EMPTY;
300             }
301              
302 3295           XS(XS_Time_Moment_stringify) {
303 3295           dVAR; dXSARGS;
304 3295 50         if (items < 1)
305 0           croak("Wrong number of arguments to Time::Moment::(\"\"");
306 3295           ST(0) = moment_to_string(sv_2moment_ptr(ST(0), "self"), FALSE);
307 3295           XSRETURN(1);
308             }
309              
310 8           XS(XS_Time_Moment_ncmp) {
311 8           dVAR; dXSARGS;
312             const moment_t *m1, *m2;
313             bool swap;
314             SV *svm1, *svm2;
315              
316 8 50         if (items < 3)
317 0           croak("Wrong number of arguments to Time::Moment::(<=>");
318              
319 8           svm1 = ST(0);
320 8           svm2 = ST(1);
321 8 50         swap = cBOOL(SvTRUE(ST(2)));
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
322              
323 8 50         if (!sv_isa_moment(svm2))
324 0           croak_cmp(svm1, svm2, swap, "Time::Moment");
325 8           m1 = sv_2moment_ptr(svm1, "self");
326 8           m2 = sv_2moment_ptr(svm2, "other");
327 8 50         if (swap) {
328 0           const moment_t *tmp = m1;
329 0           m1 = m2;
330 0           m2 = tmp;
331             }
332 8           XSRETURN_IV(moment_compare_instant(m1, m2));
333             }
334              
335             #ifdef HAS_GETTIMEOFDAY
336             static moment_t
337 2           THX_moment_now(pTHX_ bool utc) {
338             struct timeval tv;
339             IV off, sec;
340              
341 2           gettimeofday(&tv, NULL);
342 2 100         if (utc)
343 1           off = 0;
344             else {
345 1           const time_t when = tv.tv_sec;
346             struct tm *tm;
347             #ifdef HAS_LOCALTIME_R
348             struct tm tmbuf;
349             #ifdef LOCALTIME_R_NEEDS_TZSET
350             tzset();
351             #endif
352             tm = localtime_r(&when, &tmbuf);
353             #else
354 1           tm = localtime(&when);
355             #endif
356 1 50         if (tm == NULL)
357 0           croak("localtime() failed: %s", Strerror(errno));
358              
359 2           sec = ((1461 * (tm->tm_year - 1) >> 2) + tm->tm_yday - 25202) * 86400
360 1           + tm->tm_hour * 3600 + tm->tm_min * 60 + tm->tm_sec;
361 1           off = (sec - tv.tv_sec) / 60;
362             }
363 2           return moment_from_epoch(tv.tv_sec, tv.tv_usec * 1000, off);
364             }
365             #endif
366              
367             MODULE = Time::Moment PACKAGE = Time::Moment
368              
369             PROTOTYPES: DISABLE
370              
371             BOOT:
372             {
373             MY_CXT_INIT;
374 24           setup_my_cxt(aTHX_ aMY_CXT);
375             #if (PERL_REVISION == 5 && PERL_VERSION < 9)
376             PL_amagic_generation++;
377             #endif
378 24           sv_setsv(get_sv("Time::Moment::()", GV_ADD), &PL_sv_yes);
379 24           newXS("Time::Moment::()", XS_Time_Moment_nil, file);
380 24           newXS("Time::Moment::(\"\"", XS_Time_Moment_stringify, file);
381 24           newXS("Time::Moment::(<=>", XS_Time_Moment_ncmp, file);
382             }
383              
384             #ifdef USE_ITHREADS
385              
386             void
387             CLONE(...)
388             CODE:
389             {
390             MY_CXT_CLONE;
391             setup_my_cxt(aTHX_ aMY_CXT);
392             PERL_UNUSED_VAR(items);
393             }
394              
395             #endif
396              
397             moment_t
398             new(klass, ...)
399             SV *klass
400             PREINIT:
401 114           dSTASH_CONSTRUCTOR_MOMENT(klass);
402 114           IV year = 1, month = 1, day = 1;
403 114           IV hour = 0, minute = 0, second = 0, ns = 0, offset = 0;
404             I32 i;
405             CODE:
406 114 50         if (((items - 1) % 2) != 0)
407 0           croak("Odd number of elements in call to constructor when named parameters were expected");
408              
409 349 100         for (i = 1; i < items; i += 2) {
410 235           switch (sv_moment_param(ST(i))) {
411 114 50         case MOMENT_PARAM_YEAR: year = SvIV(ST(i+1)); break;
412 19 50         case MOMENT_PARAM_MONTH: month = SvIV(ST(i+1)); break;
413 19 50         case MOMENT_PARAM_DAY: day = SvIV(ST(i+1)); break;
414 0 0         case MOMENT_PARAM_HOUR: hour = SvIV(ST(i+1)); break;
415 0 0         case MOMENT_PARAM_MINUTE: minute = SvIV(ST(i+1)); break;
416 0 0         case MOMENT_PARAM_SECOND: second = SvIV(ST(i+1)); break;
417 0 0         case MOMENT_PARAM_NANOSECOND: ns = SvIV(ST(i+1)); break;
418 83 50         case MOMENT_PARAM_OFFSET: offset = SvIV(ST(i+1)); break;
419 0           default: croak("Unrecognised parameter: '%"SVf"'", ST(i));
420             }
421             }
422 114           RETVAL = moment_new(year, month, day, hour, minute, second, ns, offset);
423             OUTPUT:
424             RETVAL
425              
426             #ifdef HAS_GETTIMEOFDAY
427              
428             moment_t
429             now(klass)
430             SV *klass
431             ALIAS:
432             Time::Moment::now = 0
433             Time::Moment::now_utc = 1
434             PREINIT:
435 2           dSTASH_CONSTRUCTOR_MOMENT(klass);
436             CODE:
437 2           RETVAL = THX_moment_now(aTHX_ !!ix);
438             OUTPUT:
439             RETVAL
440              
441             #endif
442              
443             moment_t
444             from_epoch(klass, seconds, ...)
445             SV *klass
446             SV *seconds
447             PREINIT:
448 422           dSTASH_CONSTRUCTOR_MOMENT(klass);
449 422           IV precision = 6;
450             CODE:
451 422 100         if (items == 2) {
452 190 100         if (SvIOK(seconds))
453 5 50         RETVAL = moment_from_epoch(SvI64V(seconds), 0, 0);
454             else
455 190 50         RETVAL = moment_from_epoch_nv(SvNV(seconds), precision);
456             }
457 232 100         else if (items == 3) {
458 14 50         RETVAL = moment_from_epoch(SvI64V(seconds), SvIV(ST(2)), 0);
    50          
459             }
460             else {
461 218           SV *nanosecond = NULL;
462             I32 i;
463              
464 218 50         if ((items % 2) != 0)
465 0           croak("Odd number of elements in named parameters");
466              
467 436 100         for (i = 2; i < items; i += 2) {
468 218           switch (sv_moment_param(ST(i))) {
469             case MOMENT_PARAM_NANOSECOND:
470 9           nanosecond = ST(i+1);
471 9           break;
472             case MOMENT_PARAM_PRECISION:
473 209 50         precision = SvIV(ST(i+1));
474 209           break;
475             default:
476 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
477             }
478             }
479              
480 218 100         if (nanosecond)
481 9 50         RETVAL = moment_from_epoch(SvI64V(seconds), SvIV(nanosecond), 0);
    50          
482             else {
483 209 50         if (SvIOK(seconds))
484 0 0         RETVAL = moment_from_epoch(SvI64V(seconds), 0, 0);
485             else
486 209 50         RETVAL = moment_from_epoch_nv(SvNV(seconds), precision);
487             }
488             }
489             OUTPUT:
490             RETVAL
491              
492             moment_t
493             from_string(klass, string, ...)
494             SV *klass
495             SV *string
496             PREINIT:
497 266           dSTASH_CONSTRUCTOR_MOMENT(klass);
498             bool lenient;
499             const char *str;
500             STRLEN len;
501             I32 i;
502             CODE:
503 266 50         if ((items % 2) != 0)
504 0           croak("Odd number of elements in named parameters");
505              
506 266           lenient = FALSE;
507 332 100         for (i = 2; i < items; i += 2) {
508 66 50         switch (sv_moment_param(ST(i))) {
509             case MOMENT_PARAM_LENIENT:
510 66 50         lenient = cBOOL(SvTRUE((ST(i+1))));
    50          
    0          
    50          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
511 66           break;
512             default:
513 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
514             }
515             }
516 266 50         str = SvPV_const(string, len);
517 266           RETVAL = moment_from_string(str, len, lenient);
518             OUTPUT:
519             RETVAL
520              
521             moment_t
522             from_rd(klass, jd, ...)
523             SV *klass
524             NV jd
525             PREINIT:
526 672           dSTASH_CONSTRUCTOR_MOMENT(klass);
527 672           NV epoch = 0;
528 672           IV precision = 3;
529 672           IV offset = 0;
530             I32 i;
531             ALIAS:
532             Time::Moment::from_rd = 0
533             Time::Moment::from_jd = 1
534             Time::Moment::from_mjd = 2
535             CODE:
536 672 50         if ((items % 2) != 0)
537 0           croak("Odd number of elements in named parameters");
538              
539 672           switch (ix) {
540 223           case 1: epoch = -1721424.5; break;
541 224           case 2: epoch = 678576; break;
542             }
543              
544 688 100         for (i = 2; i < items; i += 2) {
545 16           switch (sv_moment_param(ST(i))) {
546             case MOMENT_PARAM_PRECISION:
547 3 50         precision = SvIV(ST(i+1));
548 3           break;
549             case MOMENT_PARAM_EPOCH:
550 9 50         epoch = SvNV(ST(i+1));
551 9           break;
552             case MOMENT_PARAM_OFFSET:
553 4 50         if (ix == 0) {
554 4 50         offset = SvIV(ST(i+1));
555 4           break;
556             }
557             /* FALLTROUGH */
558             default:
559 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
560             }
561             }
562 672 100         if (ix == 0) RETVAL = moment_from_rd(jd, epoch, precision, offset);
563 447 100         else if (ix == 1) RETVAL = moment_from_jd(jd, epoch, precision);
564 224           else RETVAL = moment_from_mjd(jd, epoch, precision);
565              
566             OUTPUT:
567             RETVAL
568              
569             void
570             from_object(klass, object)
571             SV *klass
572             SV *object
573             PREINIT:
574 4           dSTASH_CONSTRUCTOR_MOMENT(klass);
575             CODE:
576             /* PERL_UNUSED_VAR() fails on certain compilers because HV * const stash */
577             if (0) {
578             HV * dummy = stash;
579             PERL_UNUSED_VAR(dummy);
580             }
581 4           XSRETURN_SV(sv_2moment_coerce_sv(object));
582              
583             moment_t
584             at_utc(self)
585             const moment_t *self
586             PREINIT:
587 52           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 52           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 27           case 5: RETVAL = moment_at_last_day_of_month(self); break;
603             }
604 52 100         if (moment_equals(self, &RETVAL))
605 31           XSRETURN(1);
606 51 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 559           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 559 100         if (value == 0)
632 25           XSRETURN(1);
633 534           RETVAL = moment_plus_unit(self, (moment_unit_t)ix, value);
634 534 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 526           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 526 100         if (value == 0)
660 24           XSRETURN(1);
661 502           RETVAL = moment_minus_unit(self, (moment_unit_t)ix, value);
662 502 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 196 50         SvGETMAGIC(adjuster);
    0          
699 196 50         if (SvROK(adjuster))
700 196           adjuster = SvRV(adjuster);
701 196 50         if (SvTYPE(adjuster) != SVt_PVCV || SvOBJECT(adjuster))
    50          
702 0           croak("Parameter: 'adjuster' is not a CODE reference");
703 196 50         PUSHMARK(SP);
704 196           SP += 1;
705 196           PUTBACK;
706 196           count = call_sv(adjuster, G_SCALAR);
707 196 50         if (count != 1)
708 0           croak("Expected one return value from adjuster, got %d elements", count);
709 196 50         if (!sv_isa_moment(ST(0)))
710 0           croak("Expected an instance of Time::Moment from adjuster, got '%"SVf"'",
711 0           THX_sv_2neat(aTHX_ ST(0)));
712 196           SPAGAIN;
713              
714             moment_t
715             with_year(self, value)
716             const moment_t *self
717             I64V value
718             PREINIT:
719 1459           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 1459           RETVAL = moment_with_field(self, (moment_component_t)ix, value);
744 1459 100         if (moment_equals(self, &RETVAL))
745 54           XSRETURN(1);
746 1435 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 12741           IV v = 0;
803             PPCODE:
804 12741           switch (ix) {
805 1309           case 0: v = moment_year(self); break;
806 7           case 1: v = moment_quarter(self); break;
807 847           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 201           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 144           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 868           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 12741           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 594           int64_t v = 0;
839             PPCODE:
840 594           switch (ix) {
841 248           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 594           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             case MOMENT_PARAM_PRECISION:
868 0 0         precision = SvIV(ST(i+1));
869 0           break;
870             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             case MOMENT_PARAM_PRECISION:
935 0 0         precision = SvIV(ST(i+1));
936 0           break;
937             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 50         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 1135 50         if (((items - 1) % 2) != 0)
994 0           croak("Odd number of elements in named parameters");
995              
996 1135           reduced = FALSE;
997 1138 100         for (i = 1; i < items; i += 2) {
998 3 50         switch (sv_moment_param(ST(i))) {
999             case MOMENT_PARAM_REDUCED:
1000 3 50         reduced = cBOOL(SvTRUE((ST(i+1))));
    50          
    0          
    50          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    0          
    0          
    50          
    0          
1001 3           break;
1002             default:
1003 0           croak("Unrecognised parameter: '%"SVf"'", ST(i));
1004             }
1005             }
1006 1135           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 0           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