Roll src/third_party/WebKit a3b4a2e:7441784 (svn 202551:202552)
[chromium-blink-merge.git] / third_party / libxslt / libexslt / date.c
blob9ca993c6630d5e4581764560224b7e3af37e290a
1 /*
2 * date.c: Implementation of the EXSLT -- Dates and Times module
4 * References:
5 * http://www.exslt.org/date/date.html
7 * See Copyright for the status of this software.
9 * Authors:
10 * Charlie Bozeman <cbozeman@HiWAAY.net>
11 * Thomas Broyer <tbroyer@ltgt.net>
13 * TODO:
14 * elements:
15 * date-format
16 * functions:
17 * format-date
18 * parse-date
19 * sum
22 #define IN_LIBEXSLT
23 #include "libexslt/libexslt.h"
25 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
26 #include <win32config.h>
27 #else
28 #include "config.h"
29 #endif
31 #if defined(HAVE_LOCALTIME_R) && defined(__GLIBC__) /* _POSIX_SOURCE required by gnu libc */
32 #ifndef _AIX51 /* but on AIX we're not using gnu libc */
33 #define _POSIX_SOURCE
34 #endif
35 #endif
37 #include <libxml/tree.h>
38 #include <libxml/xpath.h>
39 #include <libxml/xpathInternals.h>
41 #include <libxslt/xsltconfig.h>
42 #include <libxslt/xsltutils.h>
43 #include <libxslt/xsltInternals.h>
44 #include <libxslt/extensions.h>
46 #include "exslt.h"
48 #include <string.h>
50 #ifdef HAVE_MATH_H
51 #include <math.h>
52 #endif
54 /* needed to get localtime_r on Solaris */
55 #ifdef __sun
56 #ifndef __EXTENSIONS__
57 #define __EXTENSIONS__
58 #endif
59 #endif
61 #ifdef HAVE_TIME_H
62 #include <time.h>
63 #endif
66 * types of date and/or time (from schema datatypes)
67 * somewhat ordered from least specific to most specific (i.e.
68 * most truncated to least truncated).
70 typedef enum {
71 EXSLT_UNKNOWN = 0,
72 XS_TIME = 1, /* time is left-truncated */
73 XS_GDAY = (XS_TIME << 1),
74 XS_GMONTH = (XS_GDAY << 1),
75 XS_GMONTHDAY = (XS_GMONTH | XS_GDAY),
76 XS_GYEAR = (XS_GMONTH << 1),
77 XS_GYEARMONTH = (XS_GYEAR | XS_GMONTH),
78 XS_DATE = (XS_GYEAR | XS_GMONTH | XS_GDAY),
79 XS_DATETIME = (XS_DATE | XS_TIME),
80 XS_DURATION = (XS_GYEAR << 1)
81 } exsltDateType;
83 /* Date value */
84 typedef struct _exsltDateValDate exsltDateValDate;
85 typedef exsltDateValDate *exsltDateValDatePtr;
86 struct _exsltDateValDate {
87 long year;
88 unsigned int mon :4; /* 1 <= mon <= 12 */
89 unsigned int day :5; /* 1 <= day <= 31 */
90 unsigned int hour :5; /* 0 <= hour <= 23 */
91 unsigned int min :6; /* 0 <= min <= 59 */
92 double sec;
93 unsigned int tz_flag :1; /* is tzo explicitely set? */
94 signed int tzo :12; /* -1440 <= tzo <= 1440 currently only -840 to +840 are needed */
97 /* Duration value */
98 typedef struct _exsltDateValDuration exsltDateValDuration;
99 typedef exsltDateValDuration *exsltDateValDurationPtr;
100 struct _exsltDateValDuration {
101 long mon; /* mon stores years also */
102 long day;
103 double sec; /* sec stores min and hour also */
106 typedef struct _exsltDateVal exsltDateVal;
107 typedef exsltDateVal *exsltDateValPtr;
108 struct _exsltDateVal {
109 exsltDateType type;
110 union {
111 exsltDateValDate date;
112 exsltDateValDuration dur;
113 } value;
116 /****************************************************************
118 * Compat./Port. macros *
120 ****************************************************************/
122 #if defined(HAVE_TIME_H) \
123 && (defined(HAVE_LOCALTIME) || defined(HAVE_LOCALTIME_R)) \
124 && (defined(HAVE_GMTIME) || defined(HAVE_GMTIME_R)) \
125 && defined(HAVE_TIME)
126 #define WITH_TIME
127 #endif
129 /****************************************************************
131 * Convenience macros and functions *
133 ****************************************************************/
135 #define IS_TZO_CHAR(c) \
136 ((c == 0) || (c == 'Z') || (c == '+') || (c == '-'))
138 #define VALID_ALWAYS(num) (num >= 0)
139 #define VALID_YEAR(yr) (yr != 0)
140 #define VALID_MONTH(mon) ((mon >= 1) && (mon <= 12))
141 /* VALID_DAY should only be used when month is unknown */
142 #define VALID_DAY(day) ((day >= 1) && (day <= 31))
143 #define VALID_HOUR(hr) ((hr >= 0) && (hr <= 23))
144 #define VALID_MIN(min) ((min >= 0) && (min <= 59))
145 #define VALID_SEC(sec) ((sec >= 0) && (sec < 60))
146 #define VALID_TZO(tzo) ((tzo > -1440) && (tzo < 1440))
147 #define IS_LEAP(y) \
148 (((y % 4 == 0) && (y % 100 != 0)) || (y % 400 == 0))
150 static const unsigned long daysInMonth[12] =
151 { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
152 static const unsigned long daysInMonthLeap[12] =
153 { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
155 #define MAX_DAYINMONTH(yr,mon) \
156 (IS_LEAP(yr) ? daysInMonthLeap[mon - 1] : daysInMonth[mon - 1])
158 #define VALID_MDAY(dt) \
159 (IS_LEAP(dt->year) ? \
160 (dt->day <= daysInMonthLeap[dt->mon - 1]) : \
161 (dt->day <= daysInMonth[dt->mon - 1]))
163 #define VALID_DATE(dt) \
164 (VALID_YEAR(dt->year) && VALID_MONTH(dt->mon) && VALID_MDAY(dt))
167 hour and min structure vals are unsigned, so normal macros give
168 warnings on some compilers.
170 #define VALID_TIME(dt) \
171 ((dt->hour <=23 ) && (dt->min <= 59) && \
172 VALID_SEC(dt->sec) && VALID_TZO(dt->tzo))
174 #define VALID_DATETIME(dt) \
175 (VALID_DATE(dt) && VALID_TIME(dt))
177 #define SECS_PER_MIN (60)
178 #define SECS_PER_HOUR (60 * SECS_PER_MIN)
179 #define SECS_PER_DAY (24 * SECS_PER_HOUR)
181 static const unsigned long dayInYearByMonth[12] =
182 { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
183 static const unsigned long dayInLeapYearByMonth[12] =
184 { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
186 #define DAY_IN_YEAR(day, month, year) \
187 ((IS_LEAP(year) ? \
188 dayInLeapYearByMonth[month - 1] : \
189 dayInYearByMonth[month - 1]) + day)
192 * _exsltDateParseGYear:
193 * @dt: pointer to a date structure
194 * @str: pointer to the string to analyze
196 * Parses a xs:gYear without time zone and fills in the appropriate
197 * field of the @dt structure. @str is updated to point just after the
198 * xs:gYear. It is supposed that @dt->year is big enough to contain
199 * the year.
201 * Returns 0 or the error code
203 static int
204 _exsltDateParseGYear (exsltDateValDatePtr dt, const xmlChar **str)
206 const xmlChar *cur = *str, *firstChar;
207 int isneg = 0, digcnt = 0;
209 if (((*cur < '0') || (*cur > '9')) &&
210 (*cur != '-') && (*cur != '+'))
211 return -1;
213 if (*cur == '-') {
214 isneg = 1;
215 cur++;
218 firstChar = cur;
220 while ((*cur >= '0') && (*cur <= '9')) {
221 dt->year = dt->year * 10 + (*cur - '0');
222 cur++;
223 digcnt++;
226 /* year must be at least 4 digits (CCYY); over 4
227 * digits cannot have a leading zero. */
228 if ((digcnt < 4) || ((digcnt > 4) && (*firstChar == '0')))
229 return 1;
231 if (isneg)
232 dt->year = - dt->year;
234 if (!VALID_YEAR(dt->year))
235 return 2;
237 *str = cur;
239 #ifdef DEBUG_EXSLT_DATE
240 xsltGenericDebug(xsltGenericDebugContext,
241 "Parsed year %04i\n", dt->year);
242 #endif
244 return 0;
248 * FORMAT_GYEAR:
249 * @yr: the year to format
250 * @cur: a pointer to an allocated buffer
252 * Formats @yr in xsl:gYear format. Result is appended to @cur and
253 * @cur is updated to point after the xsl:gYear.
255 #define FORMAT_GYEAR(yr, cur) \
256 if (yr < 0) { \
257 *cur = '-'; \
258 cur++; \
261 long year = (yr < 0) ? - yr : yr; \
262 xmlChar tmp_buf[100], *tmp = tmp_buf; \
263 /* result is in reverse-order */ \
264 while (year > 0) { \
265 *tmp = '0' + (xmlChar)(year % 10); \
266 year /= 10; \
267 tmp++; \
269 /* virtually adds leading zeros */ \
270 while ((tmp - tmp_buf) < 4) \
271 *tmp++ = '0'; \
272 /* restore the correct order */ \
273 while (tmp > tmp_buf) { \
274 tmp--; \
275 *cur = *tmp; \
276 cur++; \
281 * PARSE_2_DIGITS:
282 * @num: the integer to fill in
283 * @cur: an #xmlChar *
284 * @func: validation function for the number
285 * @invalid: an integer
287 * Parses a 2-digits integer and updates @num with the value. @cur is
288 * updated to point just after the integer.
289 * In case of error, @invalid is set to %TRUE, values of @num and
290 * @cur are undefined.
292 #define PARSE_2_DIGITS(num, cur, func, invalid) \
293 if ((cur[0] < '0') || (cur[0] > '9') || \
294 (cur[1] < '0') || (cur[1] > '9')) \
295 invalid = 1; \
296 else { \
297 int val; \
298 val = (cur[0] - '0') * 10 + (cur[1] - '0'); \
299 if (!func(val)) \
300 invalid = 2; \
301 else \
302 num = val; \
304 cur += 2;
307 * FORMAT_2_DIGITS:
308 * @num: the integer to format
309 * @cur: a pointer to an allocated buffer
311 * Formats a 2-digits integer. Result is appended to @cur and
312 * @cur is updated to point after the integer.
314 #define FORMAT_2_DIGITS(num, cur) \
315 *cur = '0' + ((num / 10) % 10); \
316 cur++; \
317 *cur = '0' + (num % 10); \
318 cur++;
321 * PARSE_FLOAT:
322 * @num: the double to fill in
323 * @cur: an #xmlChar *
324 * @invalid: an integer
326 * Parses a float and updates @num with the value. @cur is
327 * updated to point just after the float. The float must have a
328 * 2-digits integer part and may or may not have a decimal part.
329 * In case of error, @invalid is set to %TRUE, values of @num and
330 * @cur are undefined.
332 #define PARSE_FLOAT(num, cur, invalid) \
333 PARSE_2_DIGITS(num, cur, VALID_ALWAYS, invalid); \
334 if (!invalid && (*cur == '.')) { \
335 double mult = 1; \
336 cur++; \
337 if ((*cur < '0') || (*cur > '9')) \
338 invalid = 1; \
339 while ((*cur >= '0') && (*cur <= '9')) { \
340 mult /= 10; \
341 num += (*cur - '0') * mult; \
342 cur++; \
347 * FORMAT_FLOAT:
348 * @num: the double to format
349 * @cur: a pointer to an allocated buffer
350 * @pad: a flag for padding to 2 integer digits
352 * Formats a float. Result is appended to @cur and @cur is updated to
353 * point after the integer. If the @pad flag is non-zero, then the
354 * float representation has a minimum 2-digits integer part. The
355 * fractional part is formatted if @num has a fractional value.
357 #define FORMAT_FLOAT(num, cur, pad) \
359 xmlChar *sav, *str; \
360 if ((pad) && (num < 10.0)) \
361 *cur++ = '0'; \
362 str = xmlXPathCastNumberToString(num); \
363 sav = str; \
364 while (*str != 0) \
365 *cur++ = *str++; \
366 xmlFree(sav); \
370 * _exsltDateParseGMonth:
371 * @dt: pointer to a date structure
372 * @str: pointer to the string to analyze
374 * Parses a xs:gMonth without time zone and fills in the appropriate
375 * field of the @dt structure. @str is updated to point just after the
376 * xs:gMonth.
378 * Returns 0 or the error code
380 static int
381 _exsltDateParseGMonth (exsltDateValDatePtr dt, const xmlChar **str)
383 const xmlChar *cur = *str;
384 int ret = 0;
386 PARSE_2_DIGITS(dt->mon, cur, VALID_MONTH, ret);
387 if (ret != 0)
388 return ret;
390 *str = cur;
392 #ifdef DEBUG_EXSLT_DATE
393 xsltGenericDebug(xsltGenericDebugContext,
394 "Parsed month %02i\n", dt->mon);
395 #endif
397 return 0;
401 * FORMAT_GMONTH:
402 * @mon: the month to format
403 * @cur: a pointer to an allocated buffer
405 * Formats @mon in xsl:gMonth format. Result is appended to @cur and
406 * @cur is updated to point after the xsl:gMonth.
408 #define FORMAT_GMONTH(mon, cur) \
409 FORMAT_2_DIGITS(mon, cur)
412 * _exsltDateParseGDay:
413 * @dt: pointer to a date structure
414 * @str: pointer to the string to analyze
416 * Parses a xs:gDay without time zone and fills in the appropriate
417 * field of the @dt structure. @str is updated to point just after the
418 * xs:gDay.
420 * Returns 0 or the error code
422 static int
423 _exsltDateParseGDay (exsltDateValDatePtr dt, const xmlChar **str)
425 const xmlChar *cur = *str;
426 int ret = 0;
428 PARSE_2_DIGITS(dt->day, cur, VALID_DAY, ret);
429 if (ret != 0)
430 return ret;
432 *str = cur;
434 #ifdef DEBUG_EXSLT_DATE
435 xsltGenericDebug(xsltGenericDebugContext,
436 "Parsed day %02i\n", dt->day);
437 #endif
439 return 0;
443 * FORMAT_GDAY:
444 * @dt: the #exsltDateValDate to format
445 * @cur: a pointer to an allocated buffer
447 * Formats @dt in xsl:gDay format. Result is appended to @cur and
448 * @cur is updated to point after the xsl:gDay.
450 #define FORMAT_GDAY(dt, cur) \
451 FORMAT_2_DIGITS(dt->day, cur)
454 * FORMAT_DATE:
455 * @dt: the #exsltDateValDate to format
456 * @cur: a pointer to an allocated buffer
458 * Formats @dt in xsl:date format. Result is appended to @cur and
459 * @cur is updated to point after the xsl:date.
461 #define FORMAT_DATE(dt, cur) \
462 FORMAT_GYEAR(dt->year, cur); \
463 *cur = '-'; \
464 cur++; \
465 FORMAT_GMONTH(dt->mon, cur); \
466 *cur = '-'; \
467 cur++; \
468 FORMAT_GDAY(dt, cur);
471 * _exsltDateParseTime:
472 * @dt: pointer to a date structure
473 * @str: pointer to the string to analyze
475 * Parses a xs:time without time zone and fills in the appropriate
476 * fields of the @dt structure. @str is updated to point just after the
477 * xs:time.
478 * In case of error, values of @dt fields are undefined.
480 * Returns 0 or the error code
482 static int
483 _exsltDateParseTime (exsltDateValDatePtr dt, const xmlChar **str)
485 const xmlChar *cur = *str;
486 unsigned int hour = 0; /* use temp var in case str is not xs:time */
487 int ret = 0;
489 PARSE_2_DIGITS(hour, cur, VALID_HOUR, ret);
490 if (ret != 0)
491 return ret;
493 if (*cur != ':')
494 return 1;
495 cur++;
497 /* the ':' insures this string is xs:time */
498 dt->hour = hour;
500 PARSE_2_DIGITS(dt->min, cur, VALID_MIN, ret);
501 if (ret != 0)
502 return ret;
504 if (*cur != ':')
505 return 1;
506 cur++;
508 PARSE_FLOAT(dt->sec, cur, ret);
509 if (ret != 0)
510 return ret;
512 if (!VALID_TIME(dt))
513 return 2;
515 *str = cur;
517 #ifdef DEBUG_EXSLT_DATE
518 xsltGenericDebug(xsltGenericDebugContext,
519 "Parsed time %02i:%02i:%02.f\n",
520 dt->hour, dt->min, dt->sec);
521 #endif
523 return 0;
527 * FORMAT_TIME:
528 * @dt: the #exsltDateValDate to format
529 * @cur: a pointer to an allocated buffer
531 * Formats @dt in xsl:time format. Result is appended to @cur and
532 * @cur is updated to point after the xsl:time.
534 #define FORMAT_TIME(dt, cur) \
535 FORMAT_2_DIGITS(dt->hour, cur); \
536 *cur = ':'; \
537 cur++; \
538 FORMAT_2_DIGITS(dt->min, cur); \
539 *cur = ':'; \
540 cur++; \
541 FORMAT_FLOAT(dt->sec, cur, 1);
544 * _exsltDateParseTimeZone:
545 * @dt: pointer to a date structure
546 * @str: pointer to the string to analyze
548 * Parses a time zone without time zone and fills in the appropriate
549 * field of the @dt structure. @str is updated to point just after the
550 * time zone.
552 * Returns 0 or the error code
554 static int
555 _exsltDateParseTimeZone (exsltDateValDatePtr dt, const xmlChar **str)
557 const xmlChar *cur;
558 int ret = 0;
560 if (str == NULL)
561 return -1;
562 cur = *str;
563 switch (*cur) {
564 case 0:
565 dt->tz_flag = 0;
566 dt->tzo = 0;
567 break;
569 case 'Z':
570 dt->tz_flag = 1;
571 dt->tzo = 0;
572 cur++;
573 break;
575 case '+':
576 case '-': {
577 int isneg = 0, tmp = 0;
578 isneg = (*cur == '-');
580 cur++;
582 PARSE_2_DIGITS(tmp, cur, VALID_HOUR, ret);
583 if (ret != 0)
584 return ret;
586 if (*cur != ':')
587 return 1;
588 cur++;
590 dt->tzo = tmp * 60;
592 PARSE_2_DIGITS(tmp, cur, VALID_MIN, ret);
593 if (ret != 0)
594 return ret;
596 dt->tzo += tmp;
597 if (isneg)
598 dt->tzo = - dt->tzo;
600 if (!VALID_TZO(dt->tzo))
601 return 2;
603 break;
605 default:
606 return 1;
609 *str = cur;
611 #ifdef DEBUG_EXSLT_DATE
612 xsltGenericDebug(xsltGenericDebugContext,
613 "Parsed time zone offset (%s) %i\n",
614 dt->tz_flag ? "explicit" : "implicit", dt->tzo);
615 #endif
617 return 0;
621 * FORMAT_TZ:
622 * @tzo: the timezone offset to format
623 * @cur: a pointer to an allocated buffer
625 * Formats @tzo timezone. Result is appended to @cur and
626 * @cur is updated to point after the timezone.
628 #define FORMAT_TZ(tzo, cur) \
629 if (tzo == 0) { \
630 *cur = 'Z'; \
631 cur++; \
632 } else { \
633 int aTzo = (tzo < 0) ? - tzo : tzo; \
634 int tzHh = aTzo / 60, tzMm = aTzo % 60; \
635 *cur = (tzo < 0) ? '-' : '+' ; \
636 cur++; \
637 FORMAT_2_DIGITS(tzHh, cur); \
638 *cur = ':'; \
639 cur++; \
640 FORMAT_2_DIGITS(tzMm, cur); \
643 /****************************************************************
645 * XML Schema Dates/Times Datatypes Handling *
647 ****************************************************************/
650 * exsltDateCreateDate:
651 * @type: type to create
653 * Creates a new #exsltDateVal, uninitialized.
655 * Returns the #exsltDateValPtr
657 static exsltDateValPtr
658 exsltDateCreateDate (exsltDateType type)
660 exsltDateValPtr ret;
662 ret = (exsltDateValPtr) xmlMalloc(sizeof(exsltDateVal));
663 if (ret == NULL) {
664 xsltGenericError(xsltGenericErrorContext,
665 "exsltDateCreateDate: out of memory\n");
666 return (NULL);
668 memset (ret, 0, sizeof(exsltDateVal));
670 if (type != EXSLT_UNKNOWN)
671 ret->type = type;
673 return ret;
677 * exsltDateFreeDate:
678 * @date: an #exsltDateValPtr
680 * Frees up the @date
682 static void
683 exsltDateFreeDate (exsltDateValPtr date) {
684 if (date == NULL)
685 return;
687 xmlFree(date);
691 * PARSE_DIGITS:
692 * @num: the integer to fill in
693 * @cur: an #xmlChar *
694 * @num_type: an integer flag
696 * Parses a digits integer and updates @num with the value. @cur is
697 * updated to point just after the integer.
698 * In case of error, @num_type is set to -1, values of @num and
699 * @cur are undefined.
701 #define PARSE_DIGITS(num, cur, num_type) \
702 if ((*cur < '0') || (*cur > '9')) \
703 num_type = -1; \
704 else \
705 while ((*cur >= '0') && (*cur <= '9')) { \
706 num = num * 10 + (*cur - '0'); \
707 cur++; \
711 * PARSE_NUM:
712 * @num: the double to fill in
713 * @cur: an #xmlChar *
714 * @num_type: an integer flag
716 * Parses a float or integer and updates @num with the value. @cur is
717 * updated to point just after the number. If the number is a float,
718 * then it must have an integer part and a decimal part; @num_type will
719 * be set to 1. If there is no decimal part, @num_type is set to zero.
720 * In case of error, @num_type is set to -1, values of @num and
721 * @cur are undefined.
723 #define PARSE_NUM(num, cur, num_type) \
724 num = 0; \
725 PARSE_DIGITS(num, cur, num_type); \
726 if (!num_type && (*cur == '.')) { \
727 double mult = 1; \
728 cur++; \
729 if ((*cur < '0') || (*cur > '9')) \
730 num_type = -1; \
731 else \
732 num_type = 1; \
733 while ((*cur >= '0') && (*cur <= '9')) { \
734 mult /= 10; \
735 num += (*cur - '0') * mult; \
736 cur++; \
740 #ifdef WITH_TIME
742 * exsltDateCurrent:
744 * Returns the current date and time.
746 static exsltDateValPtr
747 exsltDateCurrent (void)
749 struct tm localTm, gmTm;
750 time_t secs;
751 int local_s, gm_s;
752 exsltDateValPtr ret;
754 ret = exsltDateCreateDate(XS_DATETIME);
755 if (ret == NULL)
756 return NULL;
758 /* get current time */
759 secs = time(NULL);
760 #if HAVE_LOCALTIME_R
761 localtime_r(&secs, &localTm);
762 #else
763 localTm = *localtime(&secs);
764 #endif
766 /* get real year, not years since 1900 */
767 ret->value.date.year = localTm.tm_year + 1900;
769 ret->value.date.mon = localTm.tm_mon + 1;
770 ret->value.date.day = localTm.tm_mday;
771 ret->value.date.hour = localTm.tm_hour;
772 ret->value.date.min = localTm.tm_min;
774 /* floating point seconds */
775 ret->value.date.sec = (double) localTm.tm_sec;
777 /* determine the time zone offset from local to gm time */
778 #if HAVE_GMTIME_R
779 gmtime_r(&secs, &gmTm);
780 #else
781 gmTm = *gmtime(&secs);
782 #endif
783 ret->value.date.tz_flag = 0;
784 #if 0
785 ret->value.date.tzo = (((ret->value.date.day * 1440) +
786 (ret->value.date.hour * 60) +
787 ret->value.date.min) -
788 ((gmTm.tm_mday * 1440) + (gmTm.tm_hour * 60) +
789 gmTm.tm_min));
790 #endif
791 local_s = localTm.tm_hour * SECS_PER_HOUR +
792 localTm.tm_min * SECS_PER_MIN +
793 localTm.tm_sec;
795 gm_s = gmTm.tm_hour * SECS_PER_HOUR +
796 gmTm.tm_min * SECS_PER_MIN +
797 gmTm.tm_sec;
799 if (localTm.tm_year < gmTm.tm_year) {
800 ret->value.date.tzo = -((SECS_PER_DAY - local_s) + gm_s)/60;
801 } else if (localTm.tm_year > gmTm.tm_year) {
802 ret->value.date.tzo = ((SECS_PER_DAY - gm_s) + local_s)/60;
803 } else if (localTm.tm_mon < gmTm.tm_mon) {
804 ret->value.date.tzo = -((SECS_PER_DAY - local_s) + gm_s)/60;
805 } else if (localTm.tm_mon > gmTm.tm_mon) {
806 ret->value.date.tzo = ((SECS_PER_DAY - gm_s) + local_s)/60;
807 } else if (localTm.tm_mday < gmTm.tm_mday) {
808 ret->value.date.tzo = -((SECS_PER_DAY - local_s) + gm_s)/60;
809 } else if (localTm.tm_mday > gmTm.tm_mday) {
810 ret->value.date.tzo = ((SECS_PER_DAY - gm_s) + local_s)/60;
811 } else {
812 ret->value.date.tzo = (local_s - gm_s)/60;
815 return ret;
817 #endif
820 * exsltDateParse:
821 * @dateTime: string to analyze
823 * Parses a date/time string
825 * Returns a newly built #exsltDateValPtr of NULL in case of error
827 static exsltDateValPtr
828 exsltDateParse (const xmlChar *dateTime)
830 exsltDateValPtr dt;
831 int ret;
832 const xmlChar *cur = dateTime;
834 #define RETURN_TYPE_IF_VALID(t) \
835 if (IS_TZO_CHAR(*cur)) { \
836 ret = _exsltDateParseTimeZone(&(dt->value.date), &cur); \
837 if (ret == 0) { \
838 if (*cur != 0) \
839 goto error; \
840 dt->type = t; \
841 return dt; \
845 if (dateTime == NULL)
846 return NULL;
848 if ((*cur != '-') && (*cur < '0') && (*cur > '9'))
849 return NULL;
851 dt = exsltDateCreateDate(EXSLT_UNKNOWN);
852 if (dt == NULL)
853 return NULL;
855 if ((cur[0] == '-') && (cur[1] == '-')) {
857 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
858 * xs:gDay)
860 cur += 2;
862 /* is it an xs:gDay? */
863 if (*cur == '-') {
864 ++cur;
865 ret = _exsltDateParseGDay(&(dt->value.date), &cur);
866 if (ret != 0)
867 goto error;
869 RETURN_TYPE_IF_VALID(XS_GDAY);
871 goto error;
875 * it should be an xs:gMonthDay or xs:gMonth
877 ret = _exsltDateParseGMonth(&(dt->value.date), &cur);
878 if (ret != 0)
879 goto error;
881 if (*cur != '-')
882 goto error;
883 cur++;
885 /* is it an xs:gMonth? */
886 if (*cur == '-') {
887 cur++;
888 RETURN_TYPE_IF_VALID(XS_GMONTH);
889 goto error;
892 /* it should be an xs:gMonthDay */
893 ret = _exsltDateParseGDay(&(dt->value.date), &cur);
894 if (ret != 0)
895 goto error;
897 RETURN_TYPE_IF_VALID(XS_GMONTHDAY);
899 goto error;
903 * It's a right-truncated date or an xs:time.
904 * Try to parse an xs:time then fallback on right-truncated dates.
906 if ((*cur >= '0') && (*cur <= '9')) {
907 ret = _exsltDateParseTime(&(dt->value.date), &cur);
908 if (ret == 0) {
909 /* it's an xs:time */
910 RETURN_TYPE_IF_VALID(XS_TIME);
914 /* fallback on date parsing */
915 cur = dateTime;
917 ret = _exsltDateParseGYear(&(dt->value.date), &cur);
918 if (ret != 0)
919 goto error;
921 /* is it an xs:gYear? */
922 RETURN_TYPE_IF_VALID(XS_GYEAR);
924 if (*cur != '-')
925 goto error;
926 cur++;
928 ret = _exsltDateParseGMonth(&(dt->value.date), &cur);
929 if (ret != 0)
930 goto error;
932 /* is it an xs:gYearMonth? */
933 RETURN_TYPE_IF_VALID(XS_GYEARMONTH);
935 if (*cur != '-')
936 goto error;
937 cur++;
939 ret = _exsltDateParseGDay(&(dt->value.date), &cur);
940 if ((ret != 0) || !VALID_DATE((&(dt->value.date))))
941 goto error;
943 /* is it an xs:date? */
944 RETURN_TYPE_IF_VALID(XS_DATE);
946 if (*cur != 'T')
947 goto error;
948 cur++;
950 /* it should be an xs:dateTime */
951 ret = _exsltDateParseTime(&(dt->value.date), &cur);
952 if (ret != 0)
953 goto error;
955 ret = _exsltDateParseTimeZone(&(dt->value.date), &cur);
956 if ((ret != 0) || (*cur != 0) || !VALID_DATETIME((&(dt->value.date))))
957 goto error;
959 dt->type = XS_DATETIME;
961 return dt;
963 error:
964 if (dt != NULL)
965 exsltDateFreeDate(dt);
966 return NULL;
970 * exsltDateParseDuration:
971 * @duration: string to analyze
973 * Parses a duration string
975 * Returns a newly built #exsltDateValPtr of NULL in case of error
977 static exsltDateValPtr
978 exsltDateParseDuration (const xmlChar *duration)
980 const xmlChar *cur = duration;
981 exsltDateValPtr dur;
982 int isneg = 0;
983 unsigned int seq = 0;
985 if (duration == NULL)
986 return NULL;
988 if (*cur == '-') {
989 isneg = 1;
990 cur++;
993 /* duration must start with 'P' (after sign) */
994 if (*cur++ != 'P')
995 return NULL;
997 dur = exsltDateCreateDate(XS_DURATION);
998 if (dur == NULL)
999 return NULL;
1001 while (*cur != 0) {
1002 double num;
1003 int num_type = 0; /* -1 = invalid, 0 = int, 1 = floating */
1004 const xmlChar desig[] = {'Y', 'M', 'D', 'H', 'M', 'S'};
1005 const double multi[] = { 0.0, 0.0, 86400.0, 3600.0, 60.0, 1.0, 0.0};
1007 /* input string should be empty or invalid date/time item */
1008 if (seq >= sizeof(desig))
1009 goto error;
1011 /* T designator must be present for time items */
1012 if (*cur == 'T') {
1013 if (seq <= 3) {
1014 seq = 3;
1015 cur++;
1016 } else
1017 return NULL;
1018 } else if (seq == 3)
1019 goto error;
1021 /* parse the number portion of the item */
1022 PARSE_NUM(num, cur, num_type);
1024 if ((num_type == -1) || (*cur == 0))
1025 goto error;
1027 /* update duration based on item type */
1028 while (seq < sizeof(desig)) {
1029 if (*cur == desig[seq]) {
1031 /* verify numeric type; only seconds can be float */
1032 if ((num_type != 0) && (seq < (sizeof(desig)-1)))
1033 goto error;
1035 switch (seq) {
1036 case 0:
1037 dur->value.dur.mon = (long)num * 12;
1038 break;
1039 case 1:
1040 dur->value.dur.mon += (long)num;
1041 break;
1042 default:
1043 /* convert to seconds using multiplier */
1044 dur->value.dur.sec += num * multi[seq];
1045 seq++;
1046 break;
1049 break; /* exit loop */
1051 /* no date designators found? */
1052 if (++seq == 3)
1053 goto error;
1055 cur++;
1058 if (isneg) {
1059 dur->value.dur.mon = -dur->value.dur.mon;
1060 dur->value.dur.day = -dur->value.dur.day;
1061 dur->value.dur.sec = -dur->value.dur.sec;
1064 #ifdef DEBUG_EXSLT_DATE
1065 xsltGenericDebug(xsltGenericDebugContext,
1066 "Parsed duration %f\n", dur->value.dur.sec);
1067 #endif
1069 return dur;
1071 error:
1072 if (dur != NULL)
1073 exsltDateFreeDate(dur);
1074 return NULL;
1078 * FORMAT_ITEM:
1079 * @num: number to format
1080 * @cur: current location to convert number
1081 * @limit: max value
1082 * @item: char designator
1085 #define FORMAT_ITEM(num, cur, limit, item) \
1086 if (num != 0) { \
1087 long comp = (long)num / limit; \
1088 if (comp != 0) { \
1089 FORMAT_FLOAT((double)comp, cur, 0); \
1090 *cur++ = item; \
1091 num -= (double)(comp * limit); \
1096 * exsltDateFormatDuration:
1097 * @dt: an #exsltDateValDurationPtr
1099 * Formats @dt in xs:duration format.
1101 * Returns a newly allocated string, or NULL in case of error
1103 static xmlChar *
1104 exsltDateFormatDuration (const exsltDateValDurationPtr dt)
1106 xmlChar buf[100], *cur = buf;
1107 double secs, days;
1108 double years, months;
1110 if (dt == NULL)
1111 return NULL;
1113 /* quick and dirty check */
1114 if ((dt->sec == 0.0) && (dt->day == 0) && (dt->mon == 0))
1115 return xmlStrdup((xmlChar*)"P0D");
1117 secs = dt->sec;
1118 days = (double)dt->day;
1119 years = (double)(dt->mon / 12);
1120 months = (double)(dt->mon % 12);
1122 *cur = '\0';
1123 if (secs < 0.0) {
1124 secs = -secs;
1125 *cur = '-';
1127 if (days < 0) {
1128 days = -days;
1129 *cur = '-';
1131 if (years < 0) {
1132 years = -years;
1133 *cur = '-';
1135 if (months < 0) {
1136 months = -months;
1137 *cur = '-';
1139 if (*cur == '-')
1140 cur++;
1142 *cur++ = 'P';
1144 if (years != 0.0) {
1145 FORMAT_ITEM(years, cur, 1, 'Y');
1148 if (months != 0.0) {
1149 FORMAT_ITEM(months, cur, 1, 'M');
1152 if (secs >= SECS_PER_DAY) {
1153 double tmp = floor(secs / SECS_PER_DAY);
1154 days += tmp;
1155 secs -= (tmp * SECS_PER_DAY);
1158 FORMAT_ITEM(days, cur, 1, 'D');
1159 if (secs > 0.0) {
1160 *cur++ = 'T';
1162 FORMAT_ITEM(secs, cur, SECS_PER_HOUR, 'H');
1163 FORMAT_ITEM(secs, cur, SECS_PER_MIN, 'M');
1164 if (secs > 0.0) {
1165 FORMAT_FLOAT(secs, cur, 0);
1166 *cur++ = 'S';
1169 *cur = 0;
1171 return xmlStrdup(buf);
1175 * exsltDateFormatDateTime:
1176 * @dt: an #exsltDateValDatePtr
1178 * Formats @dt in xs:dateTime format.
1180 * Returns a newly allocated string, or NULL in case of error
1182 static xmlChar *
1183 exsltDateFormatDateTime (const exsltDateValDatePtr dt)
1185 xmlChar buf[100], *cur = buf;
1187 if ((dt == NULL) || !VALID_DATETIME(dt))
1188 return NULL;
1190 FORMAT_DATE(dt, cur);
1191 *cur = 'T';
1192 cur++;
1193 FORMAT_TIME(dt, cur);
1194 FORMAT_TZ(dt->tzo, cur);
1195 *cur = 0;
1197 return xmlStrdup(buf);
1201 * exsltDateFormatDate:
1202 * @dt: an #exsltDateValDatePtr
1204 * Formats @dt in xs:date format.
1206 * Returns a newly allocated string, or NULL in case of error
1208 static xmlChar *
1209 exsltDateFormatDate (const exsltDateValDatePtr dt)
1211 xmlChar buf[100], *cur = buf;
1213 if ((dt == NULL) || !VALID_DATETIME(dt))
1214 return NULL;
1216 FORMAT_DATE(dt, cur);
1217 if (dt->tz_flag || (dt->tzo != 0)) {
1218 FORMAT_TZ(dt->tzo, cur);
1220 *cur = 0;
1222 return xmlStrdup(buf);
1226 * exsltDateFormatTime:
1227 * @dt: an #exsltDateValDatePtr
1229 * Formats @dt in xs:time format.
1231 * Returns a newly allocated string, or NULL in case of error
1233 static xmlChar *
1234 exsltDateFormatTime (const exsltDateValDatePtr dt)
1236 xmlChar buf[100], *cur = buf;
1238 if ((dt == NULL) || !VALID_TIME(dt))
1239 return NULL;
1241 FORMAT_TIME(dt, cur);
1242 if (dt->tz_flag || (dt->tzo != 0)) {
1243 FORMAT_TZ(dt->tzo, cur);
1245 *cur = 0;
1247 return xmlStrdup(buf);
1251 * exsltDateFormat:
1252 * @dt: an #exsltDateValPtr
1254 * Formats @dt in the proper format.
1255 * Note: xs:gmonth and xs:gday are not formatted as there are no
1256 * routines that output them.
1258 * Returns a newly allocated string, or NULL in case of error
1260 static xmlChar *
1261 exsltDateFormat (const exsltDateValPtr dt)
1264 if (dt == NULL)
1265 return NULL;
1267 switch (dt->type) {
1268 case XS_DURATION:
1269 return exsltDateFormatDuration(&(dt->value.dur));
1270 case XS_DATETIME:
1271 return exsltDateFormatDateTime(&(dt->value.date));
1272 case XS_DATE:
1273 return exsltDateFormatDate(&(dt->value.date));
1274 case XS_TIME:
1275 return exsltDateFormatTime(&(dt->value.date));
1276 default:
1277 break;
1280 if (dt->type & XS_GYEAR) {
1281 xmlChar buf[20], *cur = buf;
1283 FORMAT_GYEAR(dt->value.date.year, cur);
1284 if (dt->type == XS_GYEARMONTH) {
1285 *cur = '-';
1286 cur++;
1287 FORMAT_GMONTH(dt->value.date.mon, cur);
1290 if (dt->value.date.tz_flag || (dt->value.date.tzo != 0)) {
1291 FORMAT_TZ(dt->value.date.tzo, cur);
1293 *cur = 0;
1294 return xmlStrdup(buf);
1297 return NULL;
1301 * _exsltDateCastYMToDays:
1302 * @dt: an #exsltDateValPtr
1304 * Convert mon and year of @dt to total number of days. Take the
1305 * number of years since (or before) 1 AD and add the number of leap
1306 * years. This is a function because negative
1307 * years must be handled a little differently and there is no zero year.
1309 * Returns number of days.
1311 static long
1312 _exsltDateCastYMToDays (const exsltDateValPtr dt)
1314 long ret;
1316 if (dt->value.date.year < 0)
1317 ret = (dt->value.date.year * 365) +
1318 (((dt->value.date.year+1)/4)-((dt->value.date.year+1)/100)+
1319 ((dt->value.date.year+1)/400)) +
1320 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1321 else
1322 ret = ((dt->value.date.year-1) * 365) +
1323 (((dt->value.date.year-1)/4)-((dt->value.date.year-1)/100)+
1324 ((dt->value.date.year-1)/400)) +
1325 DAY_IN_YEAR(0, dt->value.date.mon, dt->value.date.year);
1327 return ret;
1331 * TIME_TO_NUMBER:
1332 * @dt: an #exsltDateValPtr
1334 * Calculates the number of seconds in the time portion of @dt.
1336 * Returns seconds.
1338 #define TIME_TO_NUMBER(dt) \
1339 ((double)((dt->value.date.hour * SECS_PER_HOUR) + \
1340 (dt->value.date.min * SECS_PER_MIN)) + dt->value.date.sec)
1343 * exsltDateCastDateToNumber:
1344 * @dt: an #exsltDateValPtr
1346 * Calculates the number of seconds from year zero.
1348 * Returns seconds from zero year.
1350 static double
1351 exsltDateCastDateToNumber (const exsltDateValPtr dt)
1353 double ret = 0.0;
1355 if (dt == NULL)
1356 return 0.0;
1358 if ((dt->type & XS_GYEAR) == XS_GYEAR) {
1359 ret = (double)_exsltDateCastYMToDays(dt) * SECS_PER_DAY;
1362 /* add in days */
1363 if (dt->type == XS_DURATION) {
1364 ret += (double)dt->value.dur.day * SECS_PER_DAY;
1365 ret += dt->value.dur.sec;
1366 } else {
1367 ret += (double)dt->value.date.day * SECS_PER_DAY;
1368 /* add in time */
1369 ret += TIME_TO_NUMBER(dt);
1373 return ret;
1377 * _exsltDateTruncateDate:
1378 * @dt: an #exsltDateValPtr
1379 * @type: dateTime type to set to
1381 * Set @dt to truncated @type.
1383 * Returns 0 success, non-zero otherwise.
1385 static int
1386 _exsltDateTruncateDate (exsltDateValPtr dt, exsltDateType type)
1388 if (dt == NULL)
1389 return 1;
1391 if ((type & XS_TIME) != XS_TIME) {
1392 dt->value.date.hour = 0;
1393 dt->value.date.min = 0;
1394 dt->value.date.sec = 0.0;
1397 if ((type & XS_GDAY) != XS_GDAY)
1398 dt->value.date.day = 0;
1400 if ((type & XS_GMONTH) != XS_GMONTH)
1401 dt->value.date.mon = 0;
1403 if ((type & XS_GYEAR) != XS_GYEAR)
1404 dt->value.date.year = 0;
1406 dt->type = type;
1408 return 0;
1412 * _exsltDayInWeek:
1413 * @yday: year day (1-366)
1414 * @yr: year
1416 * Determine the day-in-week from @yday and @yr. 0001-01-01 was
1417 * a Monday so all other days are calculated from there. Take the
1418 * number of years since (or before) add the number of leap years and
1419 * the day-in-year and mod by 7. This is a function because negative
1420 * years must be handled a little differently and there is no zero year.
1422 * Returns day in week (Sunday = 0).
1424 static long
1425 _exsltDateDayInWeek(long yday, long yr)
1427 long ret;
1429 if (yr < 0) {
1430 ret = ((yr + (((yr+1)/4)-((yr+1)/100)+((yr+1)/400)) + yday) % 7);
1431 if (ret < 0)
1432 ret += 7;
1433 } else
1434 ret = (((yr-1) + (((yr-1)/4)-((yr-1)/100)+((yr-1)/400)) + yday) % 7);
1436 return ret;
1440 * macros for adding date/times and durations
1442 #define FQUOTIENT(a,b) ((floor(((double)a/(double)b))))
1443 #define MODULO(a,b) ((a - FQUOTIENT(a,b) * b))
1444 #define FQUOTIENT_RANGE(a,low,high) (FQUOTIENT((a-low),(high-low)))
1445 #define MODULO_RANGE(a,low,high) ((MODULO((a-low),(high-low)))+low)
1448 * _exsltDateAdd:
1449 * @dt: an #exsltDateValPtr
1450 * @dur: an #exsltDateValPtr of type #XS_DURATION
1452 * Compute a new date/time from @dt and @dur. This function assumes @dt
1453 * is either #XS_DATETIME, #XS_DATE, #XS_GYEARMONTH, or #XS_GYEAR.
1455 * Returns date/time pointer or NULL.
1457 static exsltDateValPtr
1458 _exsltDateAdd (exsltDateValPtr dt, exsltDateValPtr dur)
1460 exsltDateValPtr ret;
1461 long carry, tempdays, temp;
1462 exsltDateValDatePtr r, d;
1463 exsltDateValDurationPtr u;
1465 if ((dt == NULL) || (dur == NULL))
1466 return NULL;
1468 ret = exsltDateCreateDate(dt->type);
1469 if (ret == NULL)
1470 return NULL;
1472 r = &(ret->value.date);
1473 d = &(dt->value.date);
1474 u = &(dur->value.dur);
1476 /* normalization */
1477 if (d->mon == 0)
1478 d->mon = 1;
1480 /* normalize for time zone offset */
1481 u->sec -= (d->tzo * 60); /* changed from + to - (bug 153000) */
1482 d->tzo = 0;
1484 /* normalization */
1485 if (d->day == 0)
1486 d->day = 1;
1488 /* month */
1489 carry = d->mon + u->mon;
1490 r->mon = (unsigned int)MODULO_RANGE(carry, 1, 13);
1491 carry = (long)FQUOTIENT_RANGE(carry, 1, 13);
1493 /* year (may be modified later) */
1494 r->year = d->year + carry;
1495 if (r->year == 0) {
1496 if (d->year > 0)
1497 r->year--;
1498 else
1499 r->year++;
1502 /* time zone */
1503 r->tzo = d->tzo;
1504 r->tz_flag = d->tz_flag;
1506 /* seconds */
1507 r->sec = d->sec + u->sec;
1508 carry = (long)FQUOTIENT((long)r->sec, 60);
1509 if (r->sec != 0.0) {
1510 r->sec = MODULO(r->sec, 60.0);
1513 /* minute */
1514 carry += d->min;
1515 r->min = (unsigned int)MODULO(carry, 60);
1516 carry = (long)FQUOTIENT(carry, 60);
1518 /* hours */
1519 carry += d->hour;
1520 r->hour = (unsigned int)MODULO(carry, 24);
1521 carry = (long)FQUOTIENT(carry, 24);
1524 * days
1525 * Note we use tempdays because the temporary values may need more
1526 * than 5 bits
1528 if ((VALID_YEAR(r->year)) && (VALID_MONTH(r->mon)) &&
1529 (d->day > MAX_DAYINMONTH(r->year, r->mon)))
1530 tempdays = MAX_DAYINMONTH(r->year, r->mon);
1531 else if (d->day < 1)
1532 tempdays = 1;
1533 else
1534 tempdays = d->day;
1536 tempdays += u->day + carry;
1538 while (1) {
1539 if (tempdays < 1) {
1540 long tmon = (long)MODULO_RANGE((int)r->mon-1, 1, 13);
1541 long tyr = r->year + (long)FQUOTIENT_RANGE((int)r->mon-1, 1, 13);
1542 if (tyr == 0)
1543 tyr--;
1545 * Coverity detected an overrun in daysInMonth
1546 * of size 12 at position 12 with index variable "((r)->mon - 1)"
1548 if (tmon < 0)
1549 tmon = 0;
1550 if (tmon > 12)
1551 tmon = 12;
1552 tempdays += MAX_DAYINMONTH(tyr, tmon);
1553 carry = -1;
1554 } else if (tempdays > (long)MAX_DAYINMONTH(r->year, r->mon)) {
1555 tempdays = tempdays - MAX_DAYINMONTH(r->year, r->mon);
1556 carry = 1;
1557 } else
1558 break;
1560 temp = r->mon + carry;
1561 r->mon = (unsigned int)MODULO_RANGE(temp, 1, 13);
1562 r->year = r->year + (long)FQUOTIENT_RANGE(temp, 1, 13);
1563 if (r->year == 0) {
1564 if (temp < 1)
1565 r->year--;
1566 else
1567 r->year++;
1571 r->day = tempdays;
1574 * adjust the date/time type to the date values
1576 if (ret->type != XS_DATETIME) {
1577 if ((r->hour) || (r->min) || (r->sec))
1578 ret->type = XS_DATETIME;
1579 else if (ret->type != XS_DATE) {
1580 if (r->day != 1)
1581 ret->type = XS_DATE;
1582 else if ((ret->type != XS_GYEARMONTH) && (r->mon != 1))
1583 ret->type = XS_GYEARMONTH;
1587 return ret;
1591 * exsltDateNormalize:
1592 * @dt: an #exsltDateValPtr
1594 * Normalize @dt to GMT time.
1597 static void
1598 exsltDateNormalize (exsltDateValPtr dt)
1600 exsltDateValPtr dur, tmp;
1602 if (dt == NULL)
1603 return;
1605 if (((dt->type & XS_TIME) != XS_TIME) && (dt->value.date.tzo == 0))
1606 return;
1608 dur = exsltDateCreateDate(XS_DURATION);
1609 if (dur == NULL)
1610 return;
1612 tmp = _exsltDateAdd(dt, dur);
1613 if (tmp == NULL)
1614 return;
1616 memcpy(dt, tmp, sizeof(exsltDateVal));
1618 exsltDateFreeDate(tmp);
1619 exsltDateFreeDate(dur);
1621 dt->value.date.tzo = 0;
1625 * _exsltDateDifference:
1626 * @x: an #exsltDateValPtr
1627 * @y: an #exsltDateValPtr
1628 * @flag: force difference in days
1630 * Calculate the difference between @x and @y as a duration
1631 * (i.e. y - x). If the @flag is set then even if the least specific
1632 * format of @x or @y is xs:gYear or xs:gYearMonth.
1634 * Returns date/time pointer or NULL.
1636 static exsltDateValPtr
1637 _exsltDateDifference (exsltDateValPtr x, exsltDateValPtr y, int flag)
1639 exsltDateValPtr ret;
1641 if ((x == NULL) || (y == NULL))
1642 return NULL;
1644 if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) ||
1645 ((y->type < XS_GYEAR) || (y->type > XS_DATETIME)))
1646 return NULL;
1648 exsltDateNormalize(x);
1649 exsltDateNormalize(y);
1652 * the operand with the most specific format must be converted to
1653 * the same type as the operand with the least specific format.
1655 if (x->type != y->type) {
1656 if (x->type < y->type) {
1657 _exsltDateTruncateDate(y, x->type);
1658 } else {
1659 _exsltDateTruncateDate(x, y->type);
1663 ret = exsltDateCreateDate(XS_DURATION);
1664 if (ret == NULL)
1665 return NULL;
1667 if (((x->type == XS_GYEAR) || (x->type == XS_GYEARMONTH)) && (!flag)) {
1668 /* compute the difference in months */
1669 ret->value.dur.mon = ((y->value.date.year * 12) + y->value.date.mon) -
1670 ((x->value.date.year * 12) + x->value.date.mon);
1671 /* The above will give a wrong result if x and y are on different sides
1672 of the September 1752. Resolution is welcome :-) */
1673 } else {
1674 ret->value.dur.day = _exsltDateCastYMToDays(y) -
1675 _exsltDateCastYMToDays(x);
1676 ret->value.dur.day += y->value.date.day - x->value.date.day;
1677 ret->value.dur.sec = TIME_TO_NUMBER(y) - TIME_TO_NUMBER(x);
1678 if (ret->value.dur.day > 0.0 && ret->value.dur.sec < 0.0) {
1679 ret->value.dur.day -= 1;
1680 ret->value.dur.sec = ret->value.dur.sec + SECS_PER_DAY;
1681 } else if (ret->value.dur.day < 0.0 && ret->value.dur.sec > 0.0) {
1682 ret->value.dur.day += 1;
1683 ret->value.dur.sec = ret->value.dur.sec - SECS_PER_DAY;
1687 return ret;
1691 * _exsltDateAddDurCalc
1692 * @ret: an exsltDateValPtr for the return value:
1693 * @x: an exsltDateValPtr for the first operand
1694 * @y: an exsltDateValPtr for the second operand
1696 * Add two durations, catering for possible negative values.
1697 * The sum is placed in @ret.
1699 * Returns 1 for success, 0 if error detected.
1701 static int
1702 _exsltDateAddDurCalc (exsltDateValPtr ret, exsltDateValPtr x,
1703 exsltDateValPtr y)
1705 long carry;
1707 /* months */
1708 ret->value.dur.mon = x->value.dur.mon + y->value.dur.mon;
1710 /* seconds */
1711 ret->value.dur.sec = x->value.dur.sec + y->value.dur.sec;
1712 carry = (long)FQUOTIENT(ret->value.dur.sec, SECS_PER_DAY);
1713 if (ret->value.dur.sec != 0.0) {
1714 ret->value.dur.sec = MODULO(ret->value.dur.sec, SECS_PER_DAY);
1716 * Our function MODULO always gives us a positive value, so
1717 * if we end up with a "-ve" carry we need to adjust it
1718 * appropriately (bug 154021)
1720 if ((carry < 0) && (ret->value.dur.sec != 0)) {
1721 /* change seconds to equiv negative modulus */
1722 ret->value.dur.sec = ret->value.dur.sec - SECS_PER_DAY;
1723 carry++;
1727 /* days */
1728 ret->value.dur.day = x->value.dur.day + y->value.dur.day + carry;
1731 * are the results indeterminate? i.e. how do you subtract days from
1732 * months or years?
1734 if ((((ret->value.dur.day > 0) || (ret->value.dur.sec > 0)) &&
1735 (ret->value.dur.mon < 0)) ||
1736 (((ret->value.dur.day < 0) || (ret->value.dur.sec < 0)) &&
1737 (ret->value.dur.mon > 0))) {
1738 return 0;
1740 return 1;
1744 * _exsltDateAddDuration:
1745 * @x: an #exsltDateValPtr of type #XS_DURATION
1746 * @y: an #exsltDateValPtr of type #XS_DURATION
1748 * Compute a new duration from @x and @y.
1750 * Returns date/time pointer or NULL.
1752 static exsltDateValPtr
1753 _exsltDateAddDuration (exsltDateValPtr x, exsltDateValPtr y)
1755 exsltDateValPtr ret;
1757 if ((x == NULL) || (y == NULL))
1758 return NULL;
1760 ret = exsltDateCreateDate(XS_DURATION);
1761 if (ret == NULL)
1762 return NULL;
1764 if (_exsltDateAddDurCalc(ret, x, y))
1765 return ret;
1767 exsltDateFreeDate(ret);
1768 return NULL;
1771 /****************************************************************
1773 * EXSLT - Dates and Times functions *
1775 ****************************************************************/
1778 * exsltDateDateTime:
1780 * Implements the EXSLT - Dates and Times date-time() function:
1781 * string date:date-time()
1783 * Returns the current date and time as a date/time string.
1785 static xmlChar *
1786 exsltDateDateTime (void)
1788 xmlChar *ret = NULL;
1789 #ifdef WITH_TIME
1790 exsltDateValPtr cur;
1792 cur = exsltDateCurrent();
1793 if (cur != NULL) {
1794 ret = exsltDateFormatDateTime(&(cur->value.date));
1795 exsltDateFreeDate(cur);
1797 #endif
1799 return ret;
1803 * exsltDateDate:
1804 * @dateTime: a date/time string
1806 * Implements the EXSLT - Dates and Times date() function:
1807 * string date:date (string?)
1809 * Returns the date specified in the date/time string given as the
1810 * argument. If no argument is given, then the current local
1811 * date/time, as returned by date:date-time is used as a default
1812 * argument.
1813 * The date/time string specified as an argument must be a string in
1814 * the format defined as the lexical representation of either
1815 * xs:dateTime or xs:date. If the argument is not in either of these
1816 * formats, returns NULL.
1818 static xmlChar *
1819 exsltDateDate (const xmlChar *dateTime)
1821 exsltDateValPtr dt = NULL;
1822 xmlChar *ret = NULL;
1824 if (dateTime == NULL) {
1825 #ifdef WITH_TIME
1826 dt = exsltDateCurrent();
1827 if (dt == NULL)
1828 #endif
1829 return NULL;
1830 } else {
1831 dt = exsltDateParse(dateTime);
1832 if (dt == NULL)
1833 return NULL;
1834 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
1835 exsltDateFreeDate(dt);
1836 return NULL;
1840 ret = exsltDateFormatDate(&(dt->value.date));
1841 exsltDateFreeDate(dt);
1843 return ret;
1847 * exsltDateTime:
1848 * @dateTime: a date/time string
1850 * Implements the EXSLT - Dates and Times time() function:
1851 * string date:time (string?)
1853 * Returns the time specified in the date/time string given as the
1854 * argument. If no argument is given, then the current local
1855 * date/time, as returned by date:date-time is used as a default
1856 * argument.
1857 * The date/time string specified as an argument must be a string in
1858 * the format defined as the lexical representation of either
1859 * xs:dateTime or xs:time. If the argument is not in either of these
1860 * formats, returns NULL.
1862 static xmlChar *
1863 exsltDateTime (const xmlChar *dateTime)
1865 exsltDateValPtr dt = NULL;
1866 xmlChar *ret = NULL;
1868 if (dateTime == NULL) {
1869 #ifdef WITH_TIME
1870 dt = exsltDateCurrent();
1871 if (dt == NULL)
1872 #endif
1873 return NULL;
1874 } else {
1875 dt = exsltDateParse(dateTime);
1876 if (dt == NULL)
1877 return NULL;
1878 if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
1879 exsltDateFreeDate(dt);
1880 return NULL;
1884 ret = exsltDateFormatTime(&(dt->value.date));
1885 exsltDateFreeDate(dt);
1887 return ret;
1891 * exsltDateYear:
1892 * @dateTime: a date/time string
1894 * Implements the EXSLT - Dates and Times year() function
1895 * number date:year (string?)
1896 * Returns the year of a date as a number. If no argument is given,
1897 * then the current local date/time, as returned by date:date-time is
1898 * used as a default argument.
1899 * The date/time string specified as the first argument must be a
1900 * right-truncated string in the format defined as the lexical
1901 * representation of xs:dateTime in one of the formats defined in [XML
1902 * Schema Part 2: Datatypes]. The permitted formats are as follows:
1903 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
1904 * - xs:date (CCYY-MM-DD)
1905 * - xs:gYearMonth (CCYY-MM)
1906 * - xs:gYear (CCYY)
1907 * If the date/time string is not in one of these formats, then NaN is
1908 * returned.
1910 static double
1911 exsltDateYear (const xmlChar *dateTime)
1913 exsltDateValPtr dt;
1914 double ret;
1916 if (dateTime == NULL) {
1917 #ifdef WITH_TIME
1918 dt = exsltDateCurrent();
1919 if (dt == NULL)
1920 #endif
1921 return xmlXPathNAN;
1922 } else {
1923 dt = exsltDateParse(dateTime);
1924 if (dt == NULL)
1925 return xmlXPathNAN;
1926 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) &&
1927 (dt->type != XS_GYEARMONTH) && (dt->type != XS_GYEAR)) {
1928 exsltDateFreeDate(dt);
1929 return xmlXPathNAN;
1933 ret = (double) dt->value.date.year;
1934 exsltDateFreeDate(dt);
1936 return ret;
1940 * exsltDateLeapYear:
1941 * @dateTime: a date/time string
1943 * Implements the EXSLT - Dates and Times leap-year() function:
1944 * boolean date:leap-yea (string?)
1945 * Returns true if the year given in a date is a leap year. If no
1946 * argument is given, then the current local date/time, as returned by
1947 * date:date-time is used as a default argument.
1948 * The date/time string specified as the first argument must be a
1949 * right-truncated string in the format defined as the lexical
1950 * representation of xs:dateTime in one of the formats defined in [XML
1951 * Schema Part 2: Datatypes]. The permitted formats are as follows:
1952 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
1953 * - xs:date (CCYY-MM-DD)
1954 * - xs:gYearMonth (CCYY-MM)
1955 * - xs:gYear (CCYY)
1956 * If the date/time string is not in one of these formats, then NaN is
1957 * returned.
1959 static xmlXPathObjectPtr
1960 exsltDateLeapYear (const xmlChar *dateTime)
1962 double year;
1964 year = exsltDateYear(dateTime);
1965 if (xmlXPathIsNaN(year))
1966 return xmlXPathNewFloat(xmlXPathNAN);
1968 if (IS_LEAP((long)year))
1969 return xmlXPathNewBoolean(1);
1971 return xmlXPathNewBoolean(0);
1975 * exsltDateMonthInYear:
1976 * @dateTime: a date/time string
1978 * Implements the EXSLT - Dates and Times month-in-year() function:
1979 * number date:month-in-year (string?)
1980 * Returns the month of a date as a number. If no argument is given,
1981 * then the current local date/time, as returned by date:date-time is
1982 * used the default argument.
1983 * The date/time string specified as the argument is a left or
1984 * right-truncated string in the format defined as the lexical
1985 * representation of xs:dateTime in one of the formats defined in [XML
1986 * Schema Part 2: Datatypes]. The permitted formats are as follows:
1987 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
1988 * - xs:date (CCYY-MM-DD)
1989 * - xs:gYearMonth (CCYY-MM)
1990 * - xs:gMonth (--MM--)
1991 * - xs:gMonthDay (--MM-DD)
1992 * If the date/time string is not in one of these formats, then NaN is
1993 * returned.
1995 static double
1996 exsltDateMonthInYear (const xmlChar *dateTime)
1998 exsltDateValPtr dt;
1999 double ret;
2001 if (dateTime == NULL) {
2002 #ifdef WITH_TIME
2003 dt = exsltDateCurrent();
2004 if (dt == NULL)
2005 #endif
2006 return xmlXPathNAN;
2007 } else {
2008 dt = exsltDateParse(dateTime);
2009 if (dt == NULL)
2010 return xmlXPathNAN;
2011 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) &&
2012 (dt->type != XS_GYEARMONTH) && (dt->type != XS_GMONTH) &&
2013 (dt->type != XS_GMONTHDAY)) {
2014 exsltDateFreeDate(dt);
2015 return xmlXPathNAN;
2019 ret = (double) dt->value.date.mon;
2020 exsltDateFreeDate(dt);
2022 return ret;
2026 * exsltDateMonthName:
2027 * @dateTime: a date/time string
2029 * Implements the EXSLT - Dates and Time month-name() function
2030 * string date:month-name (string?)
2031 * Returns the full name of the month of a date. If no argument is
2032 * given, then the current local date/time, as returned by
2033 * date:date-time is used the default argument.
2034 * The date/time string specified as the argument is a left or
2035 * right-truncated string in the format defined as the lexical
2036 * representation of xs:dateTime in one of the formats defined in [XML
2037 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2038 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2039 * - xs:date (CCYY-MM-DD)
2040 * - xs:gYearMonth (CCYY-MM)
2041 * - xs:gMonth (--MM--)
2042 * If the date/time string is not in one of these formats, then an
2043 * empty string ('') is returned.
2044 * The result is an English month name: one of 'January', 'February',
2045 * 'March', 'April', 'May', 'June', 'July', 'August', 'September',
2046 * 'October', 'November' or 'December'.
2048 static const xmlChar *
2049 exsltDateMonthName (const xmlChar *dateTime)
2051 static const xmlChar monthNames[13][10] = {
2052 { 0 },
2053 { 'J', 'a', 'n', 'u', 'a', 'r', 'y', 0 },
2054 { 'F', 'e', 'b', 'r', 'u', 'a', 'r', 'y', 0 },
2055 { 'M', 'a', 'r', 'c', 'h', 0 },
2056 { 'A', 'p', 'r', 'i', 'l', 0 },
2057 { 'M', 'a', 'y', 0 },
2058 { 'J', 'u', 'n', 'e', 0 },
2059 { 'J', 'u', 'l', 'y', 0 },
2060 { 'A', 'u', 'g', 'u', 's', 't', 0 },
2061 { 'S', 'e', 'p', 't', 'e', 'm', 'b', 'e', 'r', 0 },
2062 { 'O', 'c', 't', 'o', 'b', 'e', 'r', 0 },
2063 { 'N', 'o', 'v', 'e', 'm', 'b', 'e', 'r', 0 },
2064 { 'D', 'e', 'c', 'e', 'm', 'b', 'e', 'r', 0 }
2066 int month;
2067 month = (int) exsltDateMonthInYear(dateTime);
2068 if (!VALID_MONTH(month))
2069 month = 0;
2070 return monthNames[month];
2074 * exsltDateMonthAbbreviation:
2075 * @dateTime: a date/time string
2077 * Implements the EXSLT - Dates and Time month-abbreviation() function
2078 * string date:month-abbreviation (string?)
2079 * Returns the abbreviation of the month of a date. If no argument is
2080 * given, then the current local date/time, as returned by
2081 * date:date-time is used the default argument.
2082 * The date/time string specified as the argument is a left or
2083 * right-truncated string in the format defined as the lexical
2084 * representation of xs:dateTime in one of the formats defined in [XML
2085 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2086 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2087 * - xs:date (CCYY-MM-DD)
2088 * - xs:gYearMonth (CCYY-MM)
2089 * - xs:gMonth (--MM--)
2090 * If the date/time string is not in one of these formats, then an
2091 * empty string ('') is returned.
2092 * The result is an English month abbreviation: one of 'Jan', 'Feb',
2093 * 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov' or
2094 * 'Dec'.
2096 static const xmlChar *
2097 exsltDateMonthAbbreviation (const xmlChar *dateTime)
2099 static const xmlChar monthAbbreviations[13][4] = {
2100 { 0 },
2101 { 'J', 'a', 'n', 0 },
2102 { 'F', 'e', 'b', 0 },
2103 { 'M', 'a', 'r', 0 },
2104 { 'A', 'p', 'r', 0 },
2105 { 'M', 'a', 'y', 0 },
2106 { 'J', 'u', 'n', 0 },
2107 { 'J', 'u', 'l', 0 },
2108 { 'A', 'u', 'g', 0 },
2109 { 'S', 'e', 'p', 0 },
2110 { 'O', 'c', 't', 0 },
2111 { 'N', 'o', 'v', 0 },
2112 { 'D', 'e', 'c', 0 }
2114 int month;
2115 month = (int) exsltDateMonthInYear(dateTime);
2116 if(!VALID_MONTH(month))
2117 month = 0;
2118 return monthAbbreviations[month];
2122 * exsltDateWeekInYear:
2123 * @dateTime: a date/time string
2125 * Implements the EXSLT - Dates and Times week-in-year() function
2126 * number date:week-in-year (string?)
2127 * Returns the week of the year as a number. If no argument is given,
2128 * then the current local date/time, as returned by date:date-time is
2129 * used as the default argument. For the purposes of numbering,
2130 * counting follows ISO 8601: week 1 in a year is the week containing
2131 * the first Thursday of the year, with new weeks beginning on a
2132 * Monday.
2133 * The date/time string specified as the argument is a right-truncated
2134 * string in the format defined as the lexical representation of
2135 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2136 * Datatypes]. The permitted formats are as follows:
2137 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2138 * - xs:date (CCYY-MM-DD)
2139 * If the date/time string is not in one of these formats, then NaN is
2140 * returned.
2142 static double
2143 exsltDateWeekInYear (const xmlChar *dateTime)
2145 exsltDateValPtr dt;
2146 long diy, diw, year, ret;
2148 if (dateTime == NULL) {
2149 #ifdef WITH_TIME
2150 dt = exsltDateCurrent();
2151 if (dt == NULL)
2152 #endif
2153 return xmlXPathNAN;
2154 } else {
2155 dt = exsltDateParse(dateTime);
2156 if (dt == NULL)
2157 return xmlXPathNAN;
2158 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2159 exsltDateFreeDate(dt);
2160 return xmlXPathNAN;
2164 diy = DAY_IN_YEAR(dt->value.date.day, dt->value.date.mon,
2165 dt->value.date.year);
2168 * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday
2169 * is the first day-in-week
2171 diw = (_exsltDateDayInWeek(diy, dt->value.date.year) + 6) % 7;
2173 /* ISO 8601 adjustment, 3 is Thu */
2174 diy += (3 - diw);
2175 if(diy < 1) {
2176 year = dt->value.date.year - 1;
2177 if(year == 0) year--;
2178 diy = DAY_IN_YEAR(31, 12, year) + diy;
2179 } else if (diy > (long)DAY_IN_YEAR(31, 12, dt->value.date.year)) {
2180 diy -= DAY_IN_YEAR(31, 12, dt->value.date.year);
2183 ret = ((diy - 1) / 7) + 1;
2185 exsltDateFreeDate(dt);
2187 return (double) ret;
2191 * exsltDateWeekInMonth:
2192 * @dateTime: a date/time string
2194 * Implements the EXSLT - Dates and Times week-in-month() function
2195 * number date:week-in-month (string?)
2196 * The date:week-in-month function returns the week in a month of a
2197 * date as a number. If no argument is given, then the current local
2198 * date/time, as returned by date:date-time is used the default
2199 * argument. For the purposes of numbering, the first day of the month
2200 * is in week 1 and new weeks begin on a Monday (so the first and last
2201 * weeks in a month will often have less than 7 days in them).
2202 * The date/time string specified as the argument is a right-truncated
2203 * string in the format defined as the lexical representation of
2204 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2205 * Datatypes]. The permitted formats are as follows:
2206 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2207 * - xs:date (CCYY-MM-DD)
2208 * If the date/time string is not in one of these formats, then NaN is
2209 * returned.
2211 static double
2212 exsltDateWeekInMonth (const xmlChar *dateTime)
2214 exsltDateValPtr dt;
2215 long fdiy, fdiw, ret;
2217 if (dateTime == NULL) {
2218 #ifdef WITH_TIME
2219 dt = exsltDateCurrent();
2220 if (dt == NULL)
2221 #endif
2222 return xmlXPathNAN;
2223 } else {
2224 dt = exsltDateParse(dateTime);
2225 if (dt == NULL)
2226 return xmlXPathNAN;
2227 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2228 exsltDateFreeDate(dt);
2229 return xmlXPathNAN;
2233 fdiy = DAY_IN_YEAR(1, dt->value.date.mon, dt->value.date.year);
2235 * Determine day-in-week (0=Sun, 1=Mon, etc.) then adjust so Monday
2236 * is the first day-in-week
2238 fdiw = (_exsltDateDayInWeek(fdiy, dt->value.date.year) + 6) % 7;
2240 ret = ((dt->value.date.day + fdiw - 1) / 7) + 1;
2242 exsltDateFreeDate(dt);
2244 return (double) ret;
2248 * exsltDateDayInYear:
2249 * @dateTime: a date/time string
2251 * Implements the EXSLT - Dates and Times day-in-year() function
2252 * number date:day-in-year (string?)
2253 * Returns the day of a date in a year as a number. If no argument is
2254 * given, then the current local date/time, as returned by
2255 * date:date-time is used the default argument.
2256 * The date/time string specified as the argument is a right-truncated
2257 * string in the format defined as the lexical representation of
2258 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2259 * Datatypes]. The permitted formats are as follows:
2260 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2261 * - xs:date (CCYY-MM-DD)
2262 * If the date/time string is not in one of these formats, then NaN is
2263 * returned.
2265 static double
2266 exsltDateDayInYear (const xmlChar *dateTime)
2268 exsltDateValPtr dt;
2269 long ret;
2271 if (dateTime == NULL) {
2272 #ifdef WITH_TIME
2273 dt = exsltDateCurrent();
2274 if (dt == NULL)
2275 #endif
2276 return xmlXPathNAN;
2277 } else {
2278 dt = exsltDateParse(dateTime);
2279 if (dt == NULL)
2280 return xmlXPathNAN;
2281 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2282 exsltDateFreeDate(dt);
2283 return xmlXPathNAN;
2287 ret = DAY_IN_YEAR(dt->value.date.day, dt->value.date.mon,
2288 dt->value.date.year);
2290 exsltDateFreeDate(dt);
2292 return (double) ret;
2296 * exsltDateDayInMonth:
2297 * @dateTime: a date/time string
2299 * Implements the EXSLT - Dates and Times day-in-month() function:
2300 * number date:day-in-month (string?)
2301 * Returns the day of a date as a number. If no argument is given,
2302 * then the current local date/time, as returned by date:date-time is
2303 * used the default argument.
2304 * The date/time string specified as the argument is a left or
2305 * right-truncated string in the format defined as the lexical
2306 * representation of xs:dateTime in one of the formats defined in [XML
2307 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2308 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2309 * - xs:date (CCYY-MM-DD)
2310 * - xs:gMonthDay (--MM-DD)
2311 * - xs:gDay (---DD)
2312 * If the date/time string is not in one of these formats, then NaN is
2313 * returned.
2315 static double
2316 exsltDateDayInMonth (const xmlChar *dateTime)
2318 exsltDateValPtr dt;
2319 double ret;
2321 if (dateTime == NULL) {
2322 #ifdef WITH_TIME
2323 dt = exsltDateCurrent();
2324 if (dt == NULL)
2325 #endif
2326 return xmlXPathNAN;
2327 } else {
2328 dt = exsltDateParse(dateTime);
2329 if (dt == NULL)
2330 return xmlXPathNAN;
2331 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE) &&
2332 (dt->type != XS_GMONTHDAY) && (dt->type != XS_GDAY)) {
2333 exsltDateFreeDate(dt);
2334 return xmlXPathNAN;
2338 ret = (double) dt->value.date.day;
2339 exsltDateFreeDate(dt);
2341 return ret;
2345 * exsltDateDayOfWeekInMonth:
2346 * @dateTime: a date/time string
2348 * Implements the EXSLT - Dates and Times day-of-week-in-month() function:
2349 * number date:day-of-week-in-month (string?)
2350 * Returns the day-of-the-week in a month of a date as a number
2351 * (e.g. 3 for the 3rd Tuesday in May). If no argument is
2352 * given, then the current local date/time, as returned by
2353 * date:date-time is used the default argument.
2354 * The date/time string specified as the argument is a right-truncated
2355 * string in the format defined as the lexical representation of
2356 * xs:dateTime in one of the formats defined in [XML Schema Part 2:
2357 * Datatypes]. The permitted formats are as follows:
2358 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2359 * - xs:date (CCYY-MM-DD)
2360 * If the date/time string is not in one of these formats, then NaN is
2361 * returned.
2363 static double
2364 exsltDateDayOfWeekInMonth (const xmlChar *dateTime)
2366 exsltDateValPtr dt;
2367 long ret;
2369 if (dateTime == NULL) {
2370 #ifdef WITH_TIME
2371 dt = exsltDateCurrent();
2372 if (dt == NULL)
2373 #endif
2374 return xmlXPathNAN;
2375 } else {
2376 dt = exsltDateParse(dateTime);
2377 if (dt == NULL)
2378 return xmlXPathNAN;
2379 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2380 exsltDateFreeDate(dt);
2381 return xmlXPathNAN;
2385 ret = ((dt->value.date.day -1) / 7) + 1;
2387 exsltDateFreeDate(dt);
2389 return (double) ret;
2393 * exsltDateDayInWeek:
2394 * @dateTime: a date/time string
2396 * Implements the EXSLT - Dates and Times day-in-week() function:
2397 * number date:day-in-week (string?)
2398 * Returns the day of the week given in a date as a number. If no
2399 * argument is given, then the current local date/time, as returned by
2400 * date:date-time is used the default argument.
2401 * The date/time string specified as the argument is a left or
2402 * right-truncated string in the format defined as the lexical
2403 * representation of xs:dateTime in one of the formats defined in [XML
2404 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2405 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2406 * - xs:date (CCYY-MM-DD)
2407 * If the date/time string is not in one of these formats, then NaN is
2408 * returned.
2409 * The numbering of days of the week starts at 1 for Sunday, 2 for
2410 * Monday and so on up to 7 for Saturday.
2412 static double
2413 exsltDateDayInWeek (const xmlChar *dateTime)
2415 exsltDateValPtr dt;
2416 long diy, ret;
2418 if (dateTime == NULL) {
2419 #ifdef WITH_TIME
2420 dt = exsltDateCurrent();
2421 if (dt == NULL)
2422 #endif
2423 return xmlXPathNAN;
2424 } else {
2425 dt = exsltDateParse(dateTime);
2426 if (dt == NULL)
2427 return xmlXPathNAN;
2428 if ((dt->type != XS_DATETIME) && (dt->type != XS_DATE)) {
2429 exsltDateFreeDate(dt);
2430 return xmlXPathNAN;
2434 diy = DAY_IN_YEAR(dt->value.date.day, dt->value.date.mon,
2435 dt->value.date.year);
2437 ret = _exsltDateDayInWeek(diy, dt->value.date.year) + 1;
2439 exsltDateFreeDate(dt);
2441 return (double) ret;
2445 * exsltDateDayName:
2446 * @dateTime: a date/time string
2448 * Implements the EXSLT - Dates and Time day-name() function
2449 * string date:day-name (string?)
2450 * Returns the full name of the day of the week of a date. If no
2451 * argument is given, then the current local date/time, as returned by
2452 * date:date-time is used the default argument.
2453 * The date/time string specified as the argument is a left or
2454 * right-truncated string in the format defined as the lexical
2455 * representation of xs:dateTime in one of the formats defined in [XML
2456 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2457 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2458 * - xs:date (CCYY-MM-DD)
2459 * If the date/time string is not in one of these formats, then an
2460 * empty string ('') is returned.
2461 * The result is an English day name: one of 'Sunday', 'Monday',
2462 * 'Tuesday', 'Wednesday', 'Thursday' or 'Friday'.
2464 static const xmlChar *
2465 exsltDateDayName (const xmlChar *dateTime)
2467 static const xmlChar dayNames[8][10] = {
2468 { 0 },
2469 { 'S', 'u', 'n', 'd', 'a', 'y', 0 },
2470 { 'M', 'o', 'n', 'd', 'a', 'y', 0 },
2471 { 'T', 'u', 'e', 's', 'd', 'a', 'y', 0 },
2472 { 'W', 'e', 'd', 'n', 'e', 's', 'd', 'a', 'y', 0 },
2473 { 'T', 'h', 'u', 'r', 's', 'd', 'a', 'y', 0 },
2474 { 'F', 'r', 'i', 'd', 'a', 'y', 0 },
2475 { 'S', 'a', 't', 'u', 'r', 'd', 'a', 'y', 0 }
2477 int day;
2478 day = (int) exsltDateDayInWeek(dateTime);
2479 if((day < 1) || (day > 7))
2480 day = 0;
2481 return dayNames[day];
2485 * exsltDateDayAbbreviation:
2486 * @dateTime: a date/time string
2488 * Implements the EXSLT - Dates and Time day-abbreviation() function
2489 * string date:day-abbreviation (string?)
2490 * Returns the abbreviation of the day of the week of a date. If no
2491 * argument is given, then the current local date/time, as returned by
2492 * date:date-time is used the default argument.
2493 * The date/time string specified as the argument is a left or
2494 * right-truncated string in the format defined as the lexical
2495 * representation of xs:dateTime in one of the formats defined in [XML
2496 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2497 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2498 * - xs:date (CCYY-MM-DD)
2499 * If the date/time string is not in one of these formats, then an
2500 * empty string ('') is returned.
2501 * The result is a three-letter English day abbreviation: one of
2502 * 'Sun', 'Mon', 'Tue', 'Wed', 'Thu' or 'Fri'.
2504 static const xmlChar *
2505 exsltDateDayAbbreviation (const xmlChar *dateTime)
2507 static const xmlChar dayAbbreviations[8][4] = {
2508 { 0 },
2509 { 'S', 'u', 'n', 0 },
2510 { 'M', 'o', 'n', 0 },
2511 { 'T', 'u', 'e', 0 },
2512 { 'W', 'e', 'd', 0 },
2513 { 'T', 'h', 'u', 0 },
2514 { 'F', 'r', 'i', 0 },
2515 { 'S', 'a', 't', 0 }
2517 int day;
2518 day = (int) exsltDateDayInWeek(dateTime);
2519 if((day < 1) || (day > 7))
2520 day = 0;
2521 return dayAbbreviations[day];
2525 * exsltDateHourInDay:
2526 * @dateTime: a date/time string
2528 * Implements the EXSLT - Dates and Times day-in-month() function:
2529 * number date:day-in-month (string?)
2530 * Returns the hour of the day as a number. If no argument is given,
2531 * then the current local date/time, as returned by date:date-time is
2532 * used the default argument.
2533 * The date/time string specified as the argument is a left or
2534 * right-truncated string in the format defined as the lexical
2535 * representation of xs:dateTime in one of the formats defined in [XML
2536 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2537 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2538 * - xs:time (hh:mm:ss)
2539 * If the date/time string is not in one of these formats, then NaN is
2540 * returned.
2542 static double
2543 exsltDateHourInDay (const xmlChar *dateTime)
2545 exsltDateValPtr dt;
2546 double ret;
2548 if (dateTime == NULL) {
2549 #ifdef WITH_TIME
2550 dt = exsltDateCurrent();
2551 if (dt == NULL)
2552 #endif
2553 return xmlXPathNAN;
2554 } else {
2555 dt = exsltDateParse(dateTime);
2556 if (dt == NULL)
2557 return xmlXPathNAN;
2558 if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
2559 exsltDateFreeDate(dt);
2560 return xmlXPathNAN;
2564 ret = (double) dt->value.date.hour;
2565 exsltDateFreeDate(dt);
2567 return ret;
2571 * exsltDateMinuteInHour:
2572 * @dateTime: a date/time string
2574 * Implements the EXSLT - Dates and Times day-in-month() function:
2575 * number date:day-in-month (string?)
2576 * Returns the minute of the hour as a number. If no argument is
2577 * given, then the current local date/time, as returned by
2578 * date:date-time is used the default argument.
2579 * The date/time string specified as the argument is a left or
2580 * right-truncated string in the format defined as the lexical
2581 * representation of xs:dateTime in one of the formats defined in [XML
2582 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2583 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2584 * - xs:time (hh:mm:ss)
2585 * If the date/time string is not in one of these formats, then NaN is
2586 * returned.
2588 static double
2589 exsltDateMinuteInHour (const xmlChar *dateTime)
2591 exsltDateValPtr dt;
2592 double ret;
2594 if (dateTime == NULL) {
2595 #ifdef WITH_TIME
2596 dt = exsltDateCurrent();
2597 if (dt == NULL)
2598 #endif
2599 return xmlXPathNAN;
2600 } else {
2601 dt = exsltDateParse(dateTime);
2602 if (dt == NULL)
2603 return xmlXPathNAN;
2604 if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
2605 exsltDateFreeDate(dt);
2606 return xmlXPathNAN;
2610 ret = (double) dt->value.date.min;
2611 exsltDateFreeDate(dt);
2613 return ret;
2617 * exsltDateSecondInMinute:
2618 * @dateTime: a date/time string
2620 * Implements the EXSLT - Dates and Times second-in-minute() function:
2621 * number date:day-in-month (string?)
2622 * Returns the second of the minute as a number. If no argument is
2623 * given, then the current local date/time, as returned by
2624 * date:date-time is used the default argument.
2625 * The date/time string specified as the argument is a left or
2626 * right-truncated string in the format defined as the lexical
2627 * representation of xs:dateTime in one of the formats defined in [XML
2628 * Schema Part 2: Datatypes]. The permitted formats are as follows:
2629 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2630 * - xs:time (hh:mm:ss)
2631 * If the date/time string is not in one of these formats, then NaN is
2632 * returned.
2634 * Returns the second or NaN.
2636 static double
2637 exsltDateSecondInMinute (const xmlChar *dateTime)
2639 exsltDateValPtr dt;
2640 double ret;
2642 if (dateTime == NULL) {
2643 #ifdef WITH_TIME
2644 dt = exsltDateCurrent();
2645 if (dt == NULL)
2646 #endif
2647 return xmlXPathNAN;
2648 } else {
2649 dt = exsltDateParse(dateTime);
2650 if (dt == NULL)
2651 return xmlXPathNAN;
2652 if ((dt->type != XS_DATETIME) && (dt->type != XS_TIME)) {
2653 exsltDateFreeDate(dt);
2654 return xmlXPathNAN;
2658 ret = dt->value.date.sec;
2659 exsltDateFreeDate(dt);
2661 return ret;
2665 * exsltDateAdd:
2666 * @xstr: date/time string
2667 * @ystr: date/time string
2669 * Implements the date:add (string,string) function which returns the
2670 * date/time * resulting from adding a duration to a date/time.
2671 * The first argument (@xstr) must be right-truncated date/time
2672 * strings in one of the formats defined in [XML Schema Part 2:
2673 * Datatypes]. The permitted formats are as follows:
2674 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2675 * - xs:date (CCYY-MM-DD)
2676 * - xs:gYearMonth (CCYY-MM)
2677 * - xs:gYear (CCYY)
2678 * The second argument (@ystr) is a string in the format defined for
2679 * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
2680 * The return value is a right-truncated date/time strings in one of
2681 * the formats defined in [XML Schema Part 2: Datatypes] and listed
2682 * above. This value is calculated using the algorithm described in
2683 * [Appendix E Adding durations to dateTimes] of [XML Schema Part 2:
2684 * Datatypes].
2686 * Returns date/time string or NULL.
2688 static xmlChar *
2689 exsltDateAdd (const xmlChar *xstr, const xmlChar *ystr)
2691 exsltDateValPtr dt, dur, res;
2692 xmlChar *ret;
2694 if ((xstr == NULL) || (ystr == NULL))
2695 return NULL;
2697 dt = exsltDateParse(xstr);
2698 if (dt == NULL)
2699 return NULL;
2700 else if ((dt->type < XS_GYEAR) || (dt->type > XS_DATETIME)) {
2701 exsltDateFreeDate(dt);
2702 return NULL;
2705 dur = exsltDateParseDuration(ystr);
2706 if (dur == NULL) {
2707 exsltDateFreeDate(dt);
2708 return NULL;
2711 res = _exsltDateAdd(dt, dur);
2713 exsltDateFreeDate(dt);
2714 exsltDateFreeDate(dur);
2716 if (res == NULL)
2717 return NULL;
2719 ret = exsltDateFormat(res);
2720 exsltDateFreeDate(res);
2722 return ret;
2726 * exsltDateAddDuration:
2727 * @xstr: first duration string
2728 * @ystr: second duration string
2730 * Implements the date:add-duration (string,string) function which returns
2731 * the duration resulting from adding two durations together.
2732 * Both arguments are strings in the format defined for xs:duration
2733 * in [3.2.6 duration] of [XML Schema Part 2: Datatypes]. If either
2734 * argument is not in this format, the function returns an empty string
2735 * ('').
2736 * The return value is a string in the format defined for xs:duration
2737 * in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
2738 * The durations can usually be added by summing the numbers given for
2739 * each of the components in the durations. However, if the durations
2740 * are differently signed, then this sometimes results in durations
2741 * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D').
2742 * In these cases, the function returns an empty string ('').
2744 * Returns duration string or NULL.
2746 static xmlChar *
2747 exsltDateAddDuration (const xmlChar *xstr, const xmlChar *ystr)
2749 exsltDateValPtr x, y, res;
2750 xmlChar *ret;
2752 if ((xstr == NULL) || (ystr == NULL))
2753 return NULL;
2755 x = exsltDateParseDuration(xstr);
2756 if (x == NULL)
2757 return NULL;
2759 y = exsltDateParseDuration(ystr);
2760 if (y == NULL) {
2761 exsltDateFreeDate(x);
2762 return NULL;
2765 res = _exsltDateAddDuration(x, y);
2767 exsltDateFreeDate(x);
2768 exsltDateFreeDate(y);
2770 if (res == NULL)
2771 return NULL;
2773 ret = exsltDateFormatDuration(&(res->value.dur));
2774 exsltDateFreeDate(res);
2776 return ret;
2780 * exsltDateSumFunction:
2781 * @ns: a node set of duration strings
2783 * The date:sum function adds a set of durations together.
2784 * The string values of the nodes in the node set passed as an argument
2785 * are interpreted as durations and added together as if using the
2786 * date:add-duration function. (from exslt.org)
2788 * The return value is a string in the format defined for xs:duration
2789 * in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
2790 * The durations can usually be added by summing the numbers given for
2791 * each of the components in the durations. However, if the durations
2792 * are differently signed, then this sometimes results in durations
2793 * that are impossible to express in this syntax (e.g. 'P1M' + '-P1D').
2794 * In these cases, the function returns an empty string ('').
2796 * Returns duration string or NULL.
2798 static void
2799 exsltDateSumFunction (xmlXPathParserContextPtr ctxt, int nargs)
2801 xmlNodeSetPtr ns;
2802 void *user = NULL;
2803 xmlChar *tmp;
2804 exsltDateValPtr x, total;
2805 xmlChar *ret;
2806 int i;
2808 if (nargs != 1) {
2809 xmlXPathSetArityError (ctxt);
2810 return;
2813 /* We need to delay the freeing of value->user */
2814 if ((ctxt->value != NULL) && ctxt->value->boolval != 0) {
2815 user = ctxt->value->user;
2816 ctxt->value->boolval = 0;
2817 ctxt->value->user = NULL;
2820 ns = xmlXPathPopNodeSet (ctxt);
2821 if (xmlXPathCheckError (ctxt))
2822 return;
2824 if ((ns == NULL) || (ns->nodeNr == 0)) {
2825 xmlXPathReturnEmptyString (ctxt);
2826 if (ns != NULL)
2827 xmlXPathFreeNodeSet (ns);
2828 return;
2831 total = exsltDateCreateDate (XS_DURATION);
2832 if (total == NULL) {
2833 xmlXPathFreeNodeSet (ns);
2834 return;
2837 for (i = 0; i < ns->nodeNr; i++) {
2838 int result;
2839 tmp = xmlXPathCastNodeToString (ns->nodeTab[i]);
2840 if (tmp == NULL) {
2841 xmlXPathFreeNodeSet (ns);
2842 exsltDateFreeDate (total);
2843 return;
2846 x = exsltDateParseDuration (tmp);
2847 if (x == NULL) {
2848 xmlFree (tmp);
2849 exsltDateFreeDate (total);
2850 xmlXPathFreeNodeSet (ns);
2851 xmlXPathReturnEmptyString (ctxt);
2852 return;
2855 result = _exsltDateAddDurCalc(total, total, x);
2857 exsltDateFreeDate (x);
2858 xmlFree (tmp);
2859 if (!result) {
2860 exsltDateFreeDate (total);
2861 xmlXPathFreeNodeSet (ns);
2862 xmlXPathReturnEmptyString (ctxt);
2863 return;
2867 ret = exsltDateFormatDuration (&(total->value.dur));
2868 exsltDateFreeDate (total);
2870 xmlXPathFreeNodeSet (ns);
2871 if (user != NULL)
2872 xmlFreeNodeList ((xmlNodePtr) user);
2874 if (ret == NULL)
2875 xmlXPathReturnEmptyString (ctxt);
2876 else
2877 xmlXPathReturnString (ctxt, ret);
2881 * exsltDateSeconds:
2882 * @dateTime: a date/time string
2884 * Implements the EXSLT - Dates and Times seconds() function:
2885 * number date:seconds(string?)
2886 * The date:seconds function returns the number of seconds specified
2887 * by the argument string. If no argument is given, then the current
2888 * local date/time, as returned by exsltDateCurrent() is used as the
2889 * default argument. If the date/time string is a xs:duration, then the
2890 * years and months must be zero (or not present). Parsing a duration
2891 * converts the fields to seconds. If the date/time string is not a
2892 * duration (and not null), then the legal formats are:
2893 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2894 * - xs:date (CCYY-MM-DD)
2895 * - xs:gYearMonth (CCYY-MM)
2896 * - xs:gYear (CCYY)
2897 * In these cases the difference between the @dateTime and
2898 * 1970-01-01T00:00:00Z is calculated and converted to seconds.
2900 * Note that there was some confusion over whether "difference" meant
2901 * that a dateTime of 1970-01-01T00:00:01Z should be a positive one or
2902 * a negative one. After correspondence with exslt.org, it was determined
2903 * that the intent of the specification was to have it positive. The
2904 * coding was modified in July 2003 to reflect this.
2906 * Returns seconds or Nan.
2908 static double
2909 exsltDateSeconds (const xmlChar *dateTime)
2911 exsltDateValPtr dt;
2912 double ret = xmlXPathNAN;
2914 if (dateTime == NULL) {
2915 #ifdef WITH_TIME
2916 dt = exsltDateCurrent();
2917 if (dt == NULL)
2918 #endif
2919 return xmlXPathNAN;
2920 } else {
2921 dt = exsltDateParseDuration(dateTime);
2922 if (dt == NULL)
2923 dt = exsltDateParse(dateTime);
2926 if (dt == NULL)
2927 return xmlXPathNAN;
2929 if ((dt->type <= XS_DATETIME) && (dt->type >= XS_GYEAR)) {
2930 exsltDateValPtr y, dur;
2933 * compute the difference between the given (or current) date
2934 * and epoch date
2936 y = exsltDateCreateDate(XS_DATETIME);
2937 if (y != NULL) {
2938 y->value.date.year = 1970;
2939 y->value.date.mon = 1;
2940 y->value.date.day = 1;
2941 y->value.date.tz_flag = 1;
2943 dur = _exsltDateDifference(y, dt, 1);
2944 if (dur != NULL) {
2945 ret = exsltDateCastDateToNumber(dur);
2946 exsltDateFreeDate(dur);
2948 exsltDateFreeDate(y);
2951 } else if ((dt->type == XS_DURATION) && (dt->value.dur.mon == 0))
2952 ret = exsltDateCastDateToNumber(dt);
2954 exsltDateFreeDate(dt);
2956 return ret;
2960 * exsltDateDifference:
2961 * @xstr: date/time string
2962 * @ystr: date/time string
2964 * Implements the date:difference (string,string) function which returns
2965 * the duration between the first date and the second date. If the first
2966 * date occurs before the second date, then the result is a positive
2967 * duration; if it occurs after the second date, the result is a
2968 * negative duration. The two dates must both be right-truncated
2969 * date/time strings in one of the formats defined in [XML Schema Part
2970 * 2: Datatypes]. The date/time with the most specific format (i.e. the
2971 * least truncation) is converted into the same format as the date with
2972 * the least specific format (i.e. the most truncation). The permitted
2973 * formats are as follows, from most specific to least specific:
2974 * - xs:dateTime (CCYY-MM-DDThh:mm:ss)
2975 * - xs:date (CCYY-MM-DD)
2976 * - xs:gYearMonth (CCYY-MM)
2977 * - xs:gYear (CCYY)
2978 * If either of the arguments is not in one of these formats,
2979 * date:difference returns the empty string ('').
2980 * The difference between the date/times is returned as a string in the
2981 * format defined for xs:duration in [3.2.6 duration] of [XML Schema
2982 * Part 2: Datatypes].
2983 * If the date/time string with the least specific format is in either
2984 * xs:gYearMonth or xs:gYear format, then the number of days, hours,
2985 * minutes and seconds in the duration string must be equal to zero.
2986 * (The format of the string will be PnYnM.) The number of months
2987 * specified in the duration must be less than 12.
2988 * Otherwise, the number of years and months in the duration string
2989 * must be equal to zero. (The format of the string will be
2990 * PnDTnHnMnS.) The number of seconds specified in the duration string
2991 * must be less than 60; the number of minutes must be less than 60;
2992 * the number of hours must be less than 24.
2994 * Returns duration string or NULL.
2996 static xmlChar *
2997 exsltDateDifference (const xmlChar *xstr, const xmlChar *ystr)
2999 exsltDateValPtr x, y, dur;
3000 xmlChar *ret = NULL;
3002 if ((xstr == NULL) || (ystr == NULL))
3003 return NULL;
3005 x = exsltDateParse(xstr);
3006 if (x == NULL)
3007 return NULL;
3009 y = exsltDateParse(ystr);
3010 if (y == NULL) {
3011 exsltDateFreeDate(x);
3012 return NULL;
3015 if (((x->type < XS_GYEAR) || (x->type > XS_DATETIME)) ||
3016 ((y->type < XS_GYEAR) || (y->type > XS_DATETIME))) {
3017 exsltDateFreeDate(x);
3018 exsltDateFreeDate(y);
3019 return NULL;
3022 dur = _exsltDateDifference(x, y, 0);
3024 exsltDateFreeDate(x);
3025 exsltDateFreeDate(y);
3027 if (dur == NULL)
3028 return NULL;
3030 ret = exsltDateFormatDuration(&(dur->value.dur));
3031 exsltDateFreeDate(dur);
3033 return ret;
3037 * exsltDateDuration:
3038 * @number: a xmlChar string
3040 * Implements the The date:duration function returns a duration string
3041 * representing the number of seconds specified by the argument string.
3042 * If no argument is given, then the result of calling date:seconds
3043 * without any arguments is used as a default argument.
3044 * The duration is returned as a string in the format defined for
3045 * xs:duration in [3.2.6 duration] of [XML Schema Part 2: Datatypes].
3046 * The number of years and months in the duration string must be equal
3047 * to zero. (The format of the string will be PnDTnHnMnS.) The number
3048 * of seconds specified in the duration string must be less than 60;
3049 * the number of minutes must be less than 60; the number of hours must
3050 * be less than 24.
3051 * If the argument is Infinity, -Infinity or NaN, then date:duration
3052 * returns an empty string ('').
3054 * Returns duration string or NULL.
3056 static xmlChar *
3057 exsltDateDuration (const xmlChar *number)
3059 exsltDateValPtr dur;
3060 double secs;
3061 xmlChar *ret;
3063 if (number == NULL)
3064 secs = exsltDateSeconds(number);
3065 else
3066 secs = xmlXPathCastStringToNumber(number);
3068 if ((xmlXPathIsNaN(secs)) || (xmlXPathIsInf(secs)))
3069 return NULL;
3071 dur = exsltDateCreateDate(XS_DURATION);
3072 if (dur == NULL)
3073 return NULL;
3075 dur->value.dur.sec = secs;
3077 ret = exsltDateFormatDuration(&(dur->value.dur));
3078 exsltDateFreeDate(dur);
3080 return ret;
3083 /****************************************************************
3085 * Wrappers for use by the XPath engine *
3087 ****************************************************************/
3089 #ifdef WITH_TIME
3091 * exsltDateDateTimeFunction:
3092 * @ctxt: an XPath parser context
3093 * @nargs : the number of arguments
3095 * Wraps exsltDateDateTime() for use by the XPath engine.
3097 static void
3098 exsltDateDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs)
3100 xmlChar *ret;
3102 if (nargs != 0) {
3103 xmlXPathSetArityError(ctxt);
3104 return;
3107 ret = exsltDateDateTime();
3108 if (ret == NULL)
3109 xmlXPathReturnEmptyString(ctxt);
3110 else
3111 xmlXPathReturnString(ctxt, ret);
3113 #endif
3116 * exsltDateDateFunction:
3117 * @ctxt: an XPath parser context
3118 * @nargs : the number of arguments
3120 * Wraps exsltDateDate() for use by the XPath engine.
3122 static void
3123 exsltDateDateFunction (xmlXPathParserContextPtr ctxt, int nargs)
3125 xmlChar *ret, *dt = NULL;
3127 if ((nargs < 0) || (nargs > 1)) {
3128 xmlXPathSetArityError(ctxt);
3129 return;
3131 if (nargs == 1) {
3132 dt = xmlXPathPopString(ctxt);
3133 if (xmlXPathCheckError(ctxt)) {
3134 xmlXPathSetTypeError(ctxt);
3135 return;
3139 ret = exsltDateDate(dt);
3141 if (ret == NULL) {
3142 xsltGenericDebug(xsltGenericDebugContext,
3143 "{http://exslt.org/dates-and-times}date: "
3144 "invalid date or format %s\n", dt);
3145 xmlXPathReturnEmptyString(ctxt);
3146 } else {
3147 xmlXPathReturnString(ctxt, ret);
3150 if (dt != NULL)
3151 xmlFree(dt);
3155 * exsltDateTimeFunction:
3156 * @ctxt: an XPath parser context
3157 * @nargs : the number of arguments
3159 * Wraps exsltDateTime() for use by the XPath engine.
3161 static void
3162 exsltDateTimeFunction (xmlXPathParserContextPtr ctxt, int nargs)
3164 xmlChar *ret, *dt = NULL;
3166 if ((nargs < 0) || (nargs > 1)) {
3167 xmlXPathSetArityError(ctxt);
3168 return;
3170 if (nargs == 1) {
3171 dt = xmlXPathPopString(ctxt);
3172 if (xmlXPathCheckError(ctxt)) {
3173 xmlXPathSetTypeError(ctxt);
3174 return;
3178 ret = exsltDateTime(dt);
3180 if (ret == NULL) {
3181 xsltGenericDebug(xsltGenericDebugContext,
3182 "{http://exslt.org/dates-and-times}time: "
3183 "invalid date or format %s\n", dt);
3184 xmlXPathReturnEmptyString(ctxt);
3185 } else {
3186 xmlXPathReturnString(ctxt, ret);
3189 if (dt != NULL)
3190 xmlFree(dt);
3194 * exsltDateYearFunction:
3195 * @ctxt: an XPath parser context
3196 * @nargs : the number of arguments
3198 * Wraps exsltDateYear() for use by the XPath engine.
3200 static void
3201 exsltDateYearFunction (xmlXPathParserContextPtr ctxt, int nargs)
3203 xmlChar *dt = NULL;
3204 double ret;
3206 if ((nargs < 0) || (nargs > 1)) {
3207 xmlXPathSetArityError(ctxt);
3208 return;
3211 if (nargs == 1) {
3212 dt = xmlXPathPopString(ctxt);
3213 if (xmlXPathCheckError(ctxt)) {
3214 xmlXPathSetTypeError(ctxt);
3215 return;
3219 ret = exsltDateYear(dt);
3221 if (dt != NULL)
3222 xmlFree(dt);
3224 xmlXPathReturnNumber(ctxt, ret);
3228 * exsltDateLeapYearFunction:
3229 * @ctxt: an XPath parser context
3230 * @nargs : the number of arguments
3232 * Wraps exsltDateLeapYear() for use by the XPath engine.
3234 static void
3235 exsltDateLeapYearFunction (xmlXPathParserContextPtr ctxt, int nargs)
3237 xmlChar *dt = NULL;
3238 xmlXPathObjectPtr ret;
3240 if ((nargs < 0) || (nargs > 1)) {
3241 xmlXPathSetArityError(ctxt);
3242 return;
3245 if (nargs == 1) {
3246 dt = xmlXPathPopString(ctxt);
3247 if (xmlXPathCheckError(ctxt)) {
3248 xmlXPathSetTypeError(ctxt);
3249 return;
3253 ret = exsltDateLeapYear(dt);
3255 if (dt != NULL)
3256 xmlFree(dt);
3258 valuePush(ctxt, ret);
3261 #define X_IN_Y(x, y) \
3262 static void \
3263 exsltDate##x##In##y##Function (xmlXPathParserContextPtr ctxt, \
3264 int nargs) { \
3265 xmlChar *dt = NULL; \
3266 double ret; \
3268 if ((nargs < 0) || (nargs > 1)) { \
3269 xmlXPathSetArityError(ctxt); \
3270 return; \
3273 if (nargs == 1) { \
3274 dt = xmlXPathPopString(ctxt); \
3275 if (xmlXPathCheckError(ctxt)) { \
3276 xmlXPathSetTypeError(ctxt); \
3277 return; \
3281 ret = exsltDate##x##In##y(dt); \
3283 if (dt != NULL) \
3284 xmlFree(dt); \
3286 xmlXPathReturnNumber(ctxt, ret); \
3290 * exsltDateMonthInYearFunction:
3291 * @ctxt: an XPath parser context
3292 * @nargs : the number of arguments
3294 * Wraps exsltDateMonthInYear() for use by the XPath engine.
3296 X_IN_Y(Month,Year)
3299 * exsltDateMonthNameFunction:
3300 * @ctxt: an XPath parser context
3301 * @nargs : the number of arguments
3303 * Wraps exsltDateMonthName() for use by the XPath engine.
3305 static void
3306 exsltDateMonthNameFunction (xmlXPathParserContextPtr ctxt, int nargs)
3308 xmlChar *dt = NULL;
3309 const xmlChar *ret;
3311 if ((nargs < 0) || (nargs > 1)) {
3312 xmlXPathSetArityError(ctxt);
3313 return;
3316 if (nargs == 1) {
3317 dt = xmlXPathPopString(ctxt);
3318 if (xmlXPathCheckError(ctxt)) {
3319 xmlXPathSetTypeError(ctxt);
3320 return;
3324 ret = exsltDateMonthName(dt);
3326 if (dt != NULL)
3327 xmlFree(dt);
3329 if (ret == NULL)
3330 xmlXPathReturnEmptyString(ctxt);
3331 else
3332 xmlXPathReturnString(ctxt, xmlStrdup(ret));
3336 * exsltDateMonthAbbreviationFunction:
3337 * @ctxt: an XPath parser context
3338 * @nargs : the number of arguments
3340 * Wraps exsltDateMonthAbbreviation() for use by the XPath engine.
3342 static void
3343 exsltDateMonthAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3345 xmlChar *dt = NULL;
3346 const xmlChar *ret;
3348 if ((nargs < 0) || (nargs > 1)) {
3349 xmlXPathSetArityError(ctxt);
3350 return;
3353 if (nargs == 1) {
3354 dt = xmlXPathPopString(ctxt);
3355 if (xmlXPathCheckError(ctxt)) {
3356 xmlXPathSetTypeError(ctxt);
3357 return;
3361 ret = exsltDateMonthAbbreviation(dt);
3363 if (dt != NULL)
3364 xmlFree(dt);
3366 if (ret == NULL)
3367 xmlXPathReturnEmptyString(ctxt);
3368 else
3369 xmlXPathReturnString(ctxt, xmlStrdup(ret));
3373 * exsltDateWeekInYearFunction:
3374 * @ctxt: an XPath parser context
3375 * @nargs : the number of arguments
3377 * Wraps exsltDateWeekInYear() for use by the XPath engine.
3379 X_IN_Y(Week,Year)
3382 * exsltDateWeekInMonthFunction:
3383 * @ctxt: an XPath parser context
3384 * @nargs : the number of arguments
3386 * Wraps exsltDateWeekInMonthYear() for use by the XPath engine.
3388 X_IN_Y(Week,Month)
3391 * exsltDateDayInYearFunction:
3392 * @ctxt: an XPath parser context
3393 * @nargs : the number of arguments
3395 * Wraps exsltDateDayInYear() for use by the XPath engine.
3397 X_IN_Y(Day,Year)
3400 * exsltDateDayInMonthFunction:
3401 * @ctxt: an XPath parser context
3402 * @nargs : the number of arguments
3404 * Wraps exsltDateDayInMonth() for use by the XPath engine.
3406 X_IN_Y(Day,Month)
3409 * exsltDateDayOfWeekInMonthFunction:
3410 * @ctxt: an XPath parser context
3411 * @nargs : the number of arguments
3413 * Wraps exsltDayOfWeekInMonth() for use by the XPath engine.
3415 X_IN_Y(DayOfWeek,Month)
3418 * exsltDateDayInWeekFunction:
3419 * @ctxt: an XPath parser context
3420 * @nargs : the number of arguments
3422 * Wraps exsltDateDayInWeek() for use by the XPath engine.
3424 X_IN_Y(Day,Week)
3427 * exsltDateDayNameFunction:
3428 * @ctxt: an XPath parser context
3429 * @nargs : the number of arguments
3431 * Wraps exsltDateDayName() for use by the XPath engine.
3433 static void
3434 exsltDateDayNameFunction (xmlXPathParserContextPtr ctxt, int nargs)
3436 xmlChar *dt = NULL;
3437 const xmlChar *ret;
3439 if ((nargs < 0) || (nargs > 1)) {
3440 xmlXPathSetArityError(ctxt);
3441 return;
3444 if (nargs == 1) {
3445 dt = xmlXPathPopString(ctxt);
3446 if (xmlXPathCheckError(ctxt)) {
3447 xmlXPathSetTypeError(ctxt);
3448 return;
3452 ret = exsltDateDayName(dt);
3454 if (dt != NULL)
3455 xmlFree(dt);
3457 if (ret == NULL)
3458 xmlXPathReturnEmptyString(ctxt);
3459 else
3460 xmlXPathReturnString(ctxt, xmlStrdup(ret));
3464 * exsltDateMonthDayFunction:
3465 * @ctxt: an XPath parser context
3466 * @nargs : the number of arguments
3468 * Wraps exsltDateDayAbbreviation() for use by the XPath engine.
3470 static void
3471 exsltDateDayAbbreviationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3473 xmlChar *dt = NULL;
3474 const xmlChar *ret;
3476 if ((nargs < 0) || (nargs > 1)) {
3477 xmlXPathSetArityError(ctxt);
3478 return;
3481 if (nargs == 1) {
3482 dt = xmlXPathPopString(ctxt);
3483 if (xmlXPathCheckError(ctxt)) {
3484 xmlXPathSetTypeError(ctxt);
3485 return;
3489 ret = exsltDateDayAbbreviation(dt);
3491 if (dt != NULL)
3492 xmlFree(dt);
3494 if (ret == NULL)
3495 xmlXPathReturnEmptyString(ctxt);
3496 else
3497 xmlXPathReturnString(ctxt, xmlStrdup(ret));
3502 * exsltDateHourInDayFunction:
3503 * @ctxt: an XPath parser context
3504 * @nargs : the number of arguments
3506 * Wraps exsltDateHourInDay() for use by the XPath engine.
3508 X_IN_Y(Hour,Day)
3511 * exsltDateMinuteInHourFunction:
3512 * @ctxt: an XPath parser context
3513 * @nargs : the number of arguments
3515 * Wraps exsltDateMinuteInHour() for use by the XPath engine.
3517 X_IN_Y(Minute,Hour)
3520 * exsltDateSecondInMinuteFunction:
3521 * @ctxt: an XPath parser context
3522 * @nargs : the number of arguments
3524 * Wraps exsltDateSecondInMinute() for use by the XPath engine.
3526 X_IN_Y(Second,Minute)
3529 * exsltDateSecondsFunction:
3530 * @ctxt: an XPath parser context
3531 * @nargs : the number of arguments
3533 * Wraps exsltDateSeconds() for use by the XPath engine.
3535 static void
3536 exsltDateSecondsFunction (xmlXPathParserContextPtr ctxt, int nargs)
3538 xmlChar *str = NULL;
3539 double ret;
3541 if (nargs > 1) {
3542 xmlXPathSetArityError(ctxt);
3543 return;
3546 if (nargs == 1) {
3547 str = xmlXPathPopString(ctxt);
3548 if (xmlXPathCheckError(ctxt)) {
3549 xmlXPathSetTypeError(ctxt);
3550 return;
3554 ret = exsltDateSeconds(str);
3555 if (str != NULL)
3556 xmlFree(str);
3558 xmlXPathReturnNumber(ctxt, ret);
3562 * exsltDateAddFunction:
3563 * @ctxt: an XPath parser context
3564 * @nargs: the number of arguments
3566 * Wraps exsltDateAdd() for use by the XPath processor.
3568 static void
3569 exsltDateAddFunction (xmlXPathParserContextPtr ctxt, int nargs)
3571 xmlChar *ret, *xstr, *ystr;
3573 if (nargs != 2) {
3574 xmlXPathSetArityError(ctxt);
3575 return;
3577 ystr = xmlXPathPopString(ctxt);
3578 if (xmlXPathCheckError(ctxt))
3579 return;
3581 xstr = xmlXPathPopString(ctxt);
3582 if (xmlXPathCheckError(ctxt)) {
3583 xmlFree(ystr);
3584 return;
3587 ret = exsltDateAdd(xstr, ystr);
3589 xmlFree(ystr);
3590 xmlFree(xstr);
3592 if (ret == NULL)
3593 xmlXPathReturnEmptyString(ctxt);
3594 else
3595 xmlXPathReturnString(ctxt, ret);
3599 * exsltDateAddDurationFunction:
3600 * @ctxt: an XPath parser context
3601 * @nargs: the number of arguments
3603 * Wraps exsltDateAddDuration() for use by the XPath processor.
3605 static void
3606 exsltDateAddDurationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3608 xmlChar *ret, *xstr, *ystr;
3610 if (nargs != 2) {
3611 xmlXPathSetArityError(ctxt);
3612 return;
3614 ystr = xmlXPathPopString(ctxt);
3615 if (xmlXPathCheckError(ctxt))
3616 return;
3618 xstr = xmlXPathPopString(ctxt);
3619 if (xmlXPathCheckError(ctxt)) {
3620 xmlFree(ystr);
3621 return;
3624 ret = exsltDateAddDuration(xstr, ystr);
3626 xmlFree(ystr);
3627 xmlFree(xstr);
3629 if (ret == NULL)
3630 xmlXPathReturnEmptyString(ctxt);
3631 else
3632 xmlXPathReturnString(ctxt, ret);
3636 * exsltDateDifferenceFunction:
3637 * @ctxt: an XPath parser context
3638 * @nargs: the number of arguments
3640 * Wraps exsltDateDifference() for use by the XPath processor.
3642 static void
3643 exsltDateDifferenceFunction (xmlXPathParserContextPtr ctxt, int nargs)
3645 xmlChar *ret, *xstr, *ystr;
3647 if (nargs != 2) {
3648 xmlXPathSetArityError(ctxt);
3649 return;
3651 ystr = xmlXPathPopString(ctxt);
3652 if (xmlXPathCheckError(ctxt))
3653 return;
3655 xstr = xmlXPathPopString(ctxt);
3656 if (xmlXPathCheckError(ctxt)) {
3657 xmlFree(ystr);
3658 return;
3661 ret = exsltDateDifference(xstr, ystr);
3663 xmlFree(ystr);
3664 xmlFree(xstr);
3666 if (ret == NULL)
3667 xmlXPathReturnEmptyString(ctxt);
3668 else
3669 xmlXPathReturnString(ctxt, ret);
3673 * exsltDateDurationFunction:
3674 * @ctxt: an XPath parser context
3675 * @nargs : the number of arguments
3677 * Wraps exsltDateDuration() for use by the XPath engine
3679 static void
3680 exsltDateDurationFunction (xmlXPathParserContextPtr ctxt, int nargs)
3682 xmlChar *ret;
3683 xmlChar *number = NULL;
3685 if ((nargs < 0) || (nargs > 1)) {
3686 xmlXPathSetArityError(ctxt);
3687 return;
3690 if (nargs == 1) {
3691 number = xmlXPathPopString(ctxt);
3692 if (xmlXPathCheckError(ctxt)) {
3693 xmlXPathSetTypeError(ctxt);
3694 return;
3698 ret = exsltDateDuration(number);
3700 if (number != NULL)
3701 xmlFree(number);
3703 if (ret == NULL)
3704 xmlXPathReturnEmptyString(ctxt);
3705 else
3706 xmlXPathReturnString(ctxt, ret);
3710 * exsltDateRegister:
3712 * Registers the EXSLT - Dates and Times module
3714 void
3715 exsltDateRegister (void)
3717 xsltRegisterExtModuleFunction ((const xmlChar *) "add",
3718 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3719 exsltDateAddFunction);
3720 xsltRegisterExtModuleFunction ((const xmlChar *) "add-duration",
3721 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3722 exsltDateAddDurationFunction);
3723 xsltRegisterExtModuleFunction ((const xmlChar *) "date",
3724 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3725 exsltDateDateFunction);
3726 #ifdef WITH_TIME
3727 xsltRegisterExtModuleFunction ((const xmlChar *) "date-time",
3728 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3729 exsltDateDateTimeFunction);
3730 #endif
3731 xsltRegisterExtModuleFunction ((const xmlChar *) "day-abbreviation",
3732 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3733 exsltDateDayAbbreviationFunction);
3734 xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-month",
3735 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3736 exsltDateDayInMonthFunction);
3737 xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-week",
3738 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3739 exsltDateDayInWeekFunction);
3740 xsltRegisterExtModuleFunction ((const xmlChar *) "day-in-year",
3741 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3742 exsltDateDayInYearFunction);
3743 xsltRegisterExtModuleFunction ((const xmlChar *) "day-name",
3744 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3745 exsltDateDayNameFunction);
3746 xsltRegisterExtModuleFunction ((const xmlChar *) "day-of-week-in-month",
3747 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3748 exsltDateDayOfWeekInMonthFunction);
3749 xsltRegisterExtModuleFunction ((const xmlChar *) "difference",
3750 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3751 exsltDateDifferenceFunction);
3752 xsltRegisterExtModuleFunction ((const xmlChar *) "duration",
3753 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3754 exsltDateDurationFunction);
3755 xsltRegisterExtModuleFunction ((const xmlChar *) "hour-in-day",
3756 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3757 exsltDateHourInDayFunction);
3758 xsltRegisterExtModuleFunction ((const xmlChar *) "leap-year",
3759 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3760 exsltDateLeapYearFunction);
3761 xsltRegisterExtModuleFunction ((const xmlChar *) "minute-in-hour",
3762 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3763 exsltDateMinuteInHourFunction);
3764 xsltRegisterExtModuleFunction ((const xmlChar *) "month-abbreviation",
3765 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3766 exsltDateMonthAbbreviationFunction);
3767 xsltRegisterExtModuleFunction ((const xmlChar *) "month-in-year",
3768 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3769 exsltDateMonthInYearFunction);
3770 xsltRegisterExtModuleFunction ((const xmlChar *) "month-name",
3771 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3772 exsltDateMonthNameFunction);
3773 xsltRegisterExtModuleFunction ((const xmlChar *) "second-in-minute",
3774 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3775 exsltDateSecondInMinuteFunction);
3776 xsltRegisterExtModuleFunction ((const xmlChar *) "seconds",
3777 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3778 exsltDateSecondsFunction);
3779 xsltRegisterExtModuleFunction ((const xmlChar *) "sum",
3780 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3781 exsltDateSumFunction);
3782 xsltRegisterExtModuleFunction ((const xmlChar *) "time",
3783 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3784 exsltDateTimeFunction);
3785 xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-month",
3786 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3787 exsltDateWeekInMonthFunction);
3788 xsltRegisterExtModuleFunction ((const xmlChar *) "week-in-year",
3789 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3790 exsltDateWeekInYearFunction);
3791 xsltRegisterExtModuleFunction ((const xmlChar *) "year",
3792 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3793 exsltDateYearFunction);
3797 * exsltDateXpathCtxtRegister:
3799 * Registers the EXSLT - Dates and Times module for use outside XSLT
3802 exsltDateXpathCtxtRegister (xmlXPathContextPtr ctxt, const xmlChar *prefix)
3804 if (ctxt
3805 && prefix
3806 && !xmlXPathRegisterNs(ctxt,
3807 prefix,
3808 (const xmlChar *) EXSLT_DATE_NAMESPACE)
3809 && !xmlXPathRegisterFuncNS(ctxt,
3810 (const xmlChar *) "add",
3811 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3812 exsltDateAddFunction)
3813 && !xmlXPathRegisterFuncNS(ctxt,
3814 (const xmlChar *) "add-duration",
3815 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3816 exsltDateAddDurationFunction)
3817 && !xmlXPathRegisterFuncNS(ctxt,
3818 (const xmlChar *) "date",
3819 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3820 exsltDateDateFunction)
3821 #ifdef WITH_TIME
3822 && !xmlXPathRegisterFuncNS(ctxt,
3823 (const xmlChar *) "date-time",
3824 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3825 exsltDateDateTimeFunction)
3826 #endif
3827 && !xmlXPathRegisterFuncNS(ctxt,
3828 (const xmlChar *) "day-abbreviation",
3829 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3830 exsltDateDayAbbreviationFunction)
3831 && !xmlXPathRegisterFuncNS(ctxt,
3832 (const xmlChar *) "day-in-month",
3833 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3834 exsltDateDayInMonthFunction)
3835 && !xmlXPathRegisterFuncNS(ctxt,
3836 (const xmlChar *) "day-in-week",
3837 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3838 exsltDateDayInWeekFunction)
3839 && !xmlXPathRegisterFuncNS(ctxt,
3840 (const xmlChar *) "day-in-year",
3841 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3842 exsltDateDayInYearFunction)
3843 && !xmlXPathRegisterFuncNS(ctxt,
3844 (const xmlChar *) "day-name",
3845 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3846 exsltDateDayNameFunction)
3847 && !xmlXPathRegisterFuncNS(ctxt,
3848 (const xmlChar *) "day-of-week-in-month",
3849 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3850 exsltDateDayOfWeekInMonthFunction)
3851 && !xmlXPathRegisterFuncNS(ctxt,
3852 (const xmlChar *) "difference",
3853 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3854 exsltDateDifferenceFunction)
3855 && !xmlXPathRegisterFuncNS(ctxt,
3856 (const xmlChar *) "duration",
3857 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3858 exsltDateDurationFunction)
3859 && !xmlXPathRegisterFuncNS(ctxt,
3860 (const xmlChar *) "hour-in-day",
3861 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3862 exsltDateHourInDayFunction)
3863 && !xmlXPathRegisterFuncNS(ctxt,
3864 (const xmlChar *) "leap-year",
3865 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3866 exsltDateLeapYearFunction)
3867 && !xmlXPathRegisterFuncNS(ctxt,
3868 (const xmlChar *) "minute-in-hour",
3869 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3870 exsltDateMinuteInHourFunction)
3871 && !xmlXPathRegisterFuncNS(ctxt,
3872 (const xmlChar *) "month-abbreviation",
3873 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3874 exsltDateMonthAbbreviationFunction)
3875 && !xmlXPathRegisterFuncNS(ctxt,
3876 (const xmlChar *) "month-in-year",
3877 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3878 exsltDateMonthInYearFunction)
3879 && !xmlXPathRegisterFuncNS(ctxt,
3880 (const xmlChar *) "month-name",
3881 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3882 exsltDateMonthNameFunction)
3883 && !xmlXPathRegisterFuncNS(ctxt,
3884 (const xmlChar *) "second-in-minute",
3885 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3886 exsltDateSecondInMinuteFunction)
3887 && !xmlXPathRegisterFuncNS(ctxt,
3888 (const xmlChar *) "seconds",
3889 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3890 exsltDateSecondsFunction)
3891 && !xmlXPathRegisterFuncNS(ctxt,
3892 (const xmlChar *) "sum",
3893 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3894 exsltDateSumFunction)
3895 && !xmlXPathRegisterFuncNS(ctxt,
3896 (const xmlChar *) "time",
3897 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3898 exsltDateTimeFunction)
3899 && !xmlXPathRegisterFuncNS(ctxt,
3900 (const xmlChar *) "week-in-month",
3901 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3902 exsltDateWeekInMonthFunction)
3903 && !xmlXPathRegisterFuncNS(ctxt,
3904 (const xmlChar *) "week-in-year",
3905 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3906 exsltDateWeekInYearFunction)
3907 && !xmlXPathRegisterFuncNS(ctxt,
3908 (const xmlChar *) "year",
3909 (const xmlChar *) EXSLT_DATE_NAMESPACE,
3910 exsltDateYearFunction)) {
3911 return 0;
3913 return -1;