2 * date.c: Implementation of the EXSLT -- Dates and Times module
5 * http://www.exslt.org/date/date.html
7 * See Copyright for the status of this software.
10 * Charlie Bozeman <cbozeman@HiWAAY.net>
11 * Thomas Broyer <tbroyer@ltgt.net>
23 #include "libexslt/libexslt.h"
25 #if defined(WIN32) && !defined (__CYGWIN__) && (!__MINGW32__)
26 #include <win32config.h>
31 #if HAVE_LOCALTIME_R /* _POSIX_SOURCE required by gnu libc */
32 #ifndef _AIX51 /* but on AIX we're not using gnu libc */
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>
54 /* needed to get localtime_r on Solaris */
56 #ifndef __EXTENSIONS__
57 #define __EXTENSIONS__
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).
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)
84 typedef struct _exsltDateValDate exsltDateValDate
;
85 typedef exsltDateValDate
*exsltDateValDatePtr
;
86 struct _exsltDateValDate
{
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 */
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 */
98 typedef struct _exsltDateValDuration exsltDateValDuration
;
99 typedef exsltDateValDuration
*exsltDateValDurationPtr
;
100 struct _exsltDateValDuration
{
101 long mon
; /* mon stores years also */
103 double sec
; /* sec stores min and hour also */
106 typedef struct _exsltDateVal exsltDateVal
;
107 typedef exsltDateVal
*exsltDateValPtr
;
108 struct _exsltDateVal
{
111 exsltDateValDate date
;
112 exsltDateValDuration dur
;
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)
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))
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) \
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
201 * Returns 0 or the error code
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
!= '+'))
220 while ((*cur
>= '0') && (*cur
<= '9')) {
221 dt
->year
= dt
->year
* 10 + (*cur
- '0');
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')))
232 dt
->year
= - dt
->year
;
234 if (!VALID_YEAR(dt
->year
))
239 #ifdef DEBUG_EXSLT_DATE
240 xsltGenericDebug(xsltGenericDebugContext
,
241 "Parsed year %04i\n", dt
->year
);
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) \
261 long year = (yr < 0) ? - yr : yr; \
262 xmlChar tmp_buf[100], *tmp = tmp_buf; \
263 /* result is in reverse-order */ \
265 *tmp = '0' + (xmlChar)(year % 10); \
269 /* virtually adds leading zeros */ \
270 while ((tmp - tmp_buf) < 4) \
272 /* restore the correct order */ \
273 while (tmp > tmp_buf) { \
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')) \
298 val = (cur[0] - '0') * 10 + (cur[1] - '0'); \
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); \
317 *cur = '0' + (num % 10); \
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 == '.')) { \
337 if ((*cur < '0') || (*cur > '9')) \
339 while ((*cur >= '0') && (*cur <= '9')) { \
341 num += (*cur - '0') * mult; \
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)) \
362 str = xmlXPathCastNumberToString(num); \
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
378 * Returns 0 or the error code
381 _exsltDateParseGMonth (exsltDateValDatePtr dt
, const xmlChar
**str
)
383 const xmlChar
*cur
= *str
;
386 PARSE_2_DIGITS(dt
->mon
, cur
, VALID_MONTH
, ret
);
392 #ifdef DEBUG_EXSLT_DATE
393 xsltGenericDebug(xsltGenericDebugContext
,
394 "Parsed month %02i\n", dt
->mon
);
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
420 * Returns 0 or the error code
423 _exsltDateParseGDay (exsltDateValDatePtr dt
, const xmlChar
**str
)
425 const xmlChar
*cur
= *str
;
428 PARSE_2_DIGITS(dt
->day
, cur
, VALID_DAY
, ret
);
434 #ifdef DEBUG_EXSLT_DATE
435 xsltGenericDebug(xsltGenericDebugContext
,
436 "Parsed day %02i\n", dt
->day
);
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)
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); \
465 FORMAT_GMONTH(dt->mon, 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
478 * In case of error, values of @dt fields are undefined.
480 * Returns 0 or the error code
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 */
489 PARSE_2_DIGITS(hour
, cur
, VALID_HOUR
, ret
);
497 /* the ':' insures this string is xs:time */
500 PARSE_2_DIGITS(dt
->min
, cur
, VALID_MIN
, ret
);
508 PARSE_FLOAT(dt
->sec
, cur
, ret
);
517 #ifdef DEBUG_EXSLT_DATE
518 xsltGenericDebug(xsltGenericDebugContext
,
519 "Parsed time %02i:%02i:%02.f\n",
520 dt
->hour
, dt
->min
, dt
->sec
);
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); \
538 FORMAT_2_DIGITS(dt->min, 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
552 * Returns 0 or the error code
555 _exsltDateParseTimeZone (exsltDateValDatePtr dt
, const xmlChar
**str
)
577 int isneg
= 0, tmp
= 0;
578 isneg
= (*cur
== '-');
582 PARSE_2_DIGITS(tmp
, cur
, VALID_HOUR
, ret
);
592 PARSE_2_DIGITS(tmp
, cur
, VALID_MIN
, ret
);
600 if (!VALID_TZO(dt
->tzo
))
611 #ifdef DEBUG_EXSLT_DATE
612 xsltGenericDebug(xsltGenericDebugContext
,
613 "Parsed time zone offset (%s) %i\n",
614 dt
->tz_flag
? "explicit" : "implicit", dt
->tzo
);
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) \
633 int aTzo = (tzo < 0) ? - tzo : tzo; \
634 int tzHh = aTzo / 60, tzMm = aTzo % 60; \
635 *cur = (tzo < 0) ? '-' : '+' ; \
637 FORMAT_2_DIGITS(tzHh, 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
)
662 ret
= (exsltDateValPtr
) xmlMalloc(sizeof(exsltDateVal
));
664 xsltGenericError(xsltGenericErrorContext
,
665 "exsltDateCreateDate: out of memory\n");
668 memset (ret
, 0, sizeof(exsltDateVal
));
670 if (type
!= EXSLT_UNKNOWN
)
678 * @date: an #exsltDateValPtr
683 exsltDateFreeDate (exsltDateValPtr date
) {
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')) \
705 while ((*cur >= '0') && (*cur <= '9')) { \
706 num = num * 10 + (*cur - '0'); \
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) \
725 PARSE_DIGITS(num, cur, num_type); \
726 if (!num_type && (*cur == '.')) { \
729 if ((*cur < '0') || (*cur > '9')) \
733 while ((*cur >= '0') && (*cur <= '9')) { \
735 num += (*cur - '0') * mult; \
744 * Returns the current date and time.
746 static exsltDateValPtr
747 exsltDateCurrent (void)
749 struct tm localTm
, gmTm
;
754 ret
= exsltDateCreateDate(XS_DATETIME
);
758 /* get current time */
761 localtime_r(&secs
, &localTm
);
763 localTm
= *localtime(&secs
);
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 */
779 gmtime_r(&secs
, &gmTm
);
781 gmTm
= *gmtime(&secs
);
783 ret
->value
.date
.tz_flag
= 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) +
791 local_s
= localTm
.tm_hour
* SECS_PER_HOUR
+
792 localTm
.tm_min
* SECS_PER_MIN
+
795 gm_s
= gmTm
.tm_hour
* SECS_PER_HOUR
+
796 gmTm
.tm_min
* SECS_PER_MIN
+
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;
812 ret
->value
.date
.tzo
= (local_s
- gm_s
)/60;
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
)
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); \
845 if (dateTime
== NULL
)
848 if ((*cur
!= '-') && (*cur
< '0') && (*cur
> '9'))
851 dt
= exsltDateCreateDate(EXSLT_UNKNOWN
);
855 if ((cur
[0] == '-') && (cur
[1] == '-')) {
857 * It's an incomplete date (xs:gMonthDay, xs:gMonth or
862 /* is it an xs:gDay? */
865 ret
= _exsltDateParseGDay(&(dt
->value
.date
), &cur
);
869 RETURN_TYPE_IF_VALID(XS_GDAY
);
875 * it should be an xs:gMonthDay or xs:gMonth
877 ret
= _exsltDateParseGMonth(&(dt
->value
.date
), &cur
);
885 /* is it an xs:gMonth? */
888 RETURN_TYPE_IF_VALID(XS_GMONTH
);
892 /* it should be an xs:gMonthDay */
893 ret
= _exsltDateParseGDay(&(dt
->value
.date
), &cur
);
897 RETURN_TYPE_IF_VALID(XS_GMONTHDAY
);
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
);
909 /* it's an xs:time */
910 RETURN_TYPE_IF_VALID(XS_TIME
);
914 /* fallback on date parsing */
917 ret
= _exsltDateParseGYear(&(dt
->value
.date
), &cur
);
921 /* is it an xs:gYear? */
922 RETURN_TYPE_IF_VALID(XS_GYEAR
);
928 ret
= _exsltDateParseGMonth(&(dt
->value
.date
), &cur
);
932 /* is it an xs:gYearMonth? */
933 RETURN_TYPE_IF_VALID(XS_GYEARMONTH
);
939 ret
= _exsltDateParseGDay(&(dt
->value
.date
), &cur
);
940 if ((ret
!= 0) || !VALID_DATE((&(dt
->value
.date
))))
943 /* is it an xs:date? */
944 RETURN_TYPE_IF_VALID(XS_DATE
);
950 /* it should be an xs:dateTime */
951 ret
= _exsltDateParseTime(&(dt
->value
.date
), &cur
);
955 ret
= _exsltDateParseTimeZone(&(dt
->value
.date
), &cur
);
956 if ((ret
!= 0) || (*cur
!= 0) || !VALID_DATETIME((&(dt
->value
.date
))))
959 dt
->type
= XS_DATETIME
;
965 exsltDateFreeDate(dt
);
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
;
983 unsigned int seq
= 0;
985 if (duration
== NULL
)
993 /* duration must start with 'P' (after sign) */
997 dur
= exsltDateCreateDate(XS_DURATION
);
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
))
1011 /* T designator must be present for time items */
1018 } else if (seq
== 3)
1021 /* parse the number portion of the item */
1022 PARSE_NUM(num
, cur
, num_type
);
1024 if ((num_type
== -1) || (*cur
== 0))
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)))
1037 dur
->value
.dur
.mon
= (long)num
* 12;
1040 dur
->value
.dur
.mon
+= (long)num
;
1043 /* convert to seconds using multiplier */
1044 dur
->value
.dur
.sec
+= num
* multi
[seq
];
1049 break; /* exit loop */
1051 /* no date designators found? */
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
);
1073 exsltDateFreeDate(dur
);
1079 * @num: number to format
1080 * @cur: current location to convert number
1082 * @item: char designator
1085 #define FORMAT_ITEM(num, cur, limit, item) \
1087 long comp = (long)num / limit; \
1089 FORMAT_FLOAT((double)comp, cur, 0); \
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
1104 exsltDateFormatDuration (const exsltDateValDurationPtr dt
)
1106 xmlChar buf
[100], *cur
= buf
;
1108 double years
, months
;
1113 /* quick and dirty check */
1114 if ((dt
->sec
== 0.0) && (dt
->day
== 0) && (dt
->mon
== 0))
1115 return xmlStrdup((xmlChar
*)"P0D");
1118 days
= (double)dt
->day
;
1119 years
= (double)(dt
->mon
/ 12);
1120 months
= (double)(dt
->mon
% 12);
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
);
1155 secs
-= (tmp
* SECS_PER_DAY
);
1158 FORMAT_ITEM(days
, cur
, 1, 'D');
1162 FORMAT_ITEM(secs
, cur
, SECS_PER_HOUR
, 'H');
1163 FORMAT_ITEM(secs
, cur
, SECS_PER_MIN
, 'M');
1165 FORMAT_FLOAT(secs
, 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
1183 exsltDateFormatDateTime (const exsltDateValDatePtr dt
)
1185 xmlChar buf
[100], *cur
= buf
;
1187 if ((dt
== NULL
) || !VALID_DATETIME(dt
))
1190 FORMAT_DATE(dt
, cur
);
1193 FORMAT_TIME(dt
, cur
);
1194 FORMAT_TZ(dt
->tzo
, cur
);
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
1209 exsltDateFormatDate (const exsltDateValDatePtr dt
)
1211 xmlChar buf
[100], *cur
= buf
;
1213 if ((dt
== NULL
) || !VALID_DATETIME(dt
))
1216 FORMAT_DATE(dt
, cur
);
1217 if (dt
->tz_flag
|| (dt
->tzo
!= 0)) {
1218 FORMAT_TZ(dt
->tzo
, cur
);
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
1234 exsltDateFormatTime (const exsltDateValDatePtr dt
)
1236 xmlChar buf
[100], *cur
= buf
;
1238 if ((dt
== NULL
) || !VALID_TIME(dt
))
1241 FORMAT_TIME(dt
, cur
);
1242 if (dt
->tz_flag
|| (dt
->tzo
!= 0)) {
1243 FORMAT_TZ(dt
->tzo
, cur
);
1247 return xmlStrdup(buf
);
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
1261 exsltDateFormat (const exsltDateValPtr dt
)
1269 return exsltDateFormatDuration(&(dt
->value
.dur
));
1271 return exsltDateFormatDateTime(&(dt
->value
.date
));
1273 return exsltDateFormatDate(&(dt
->value
.date
));
1275 return exsltDateFormatTime(&(dt
->value
.date
));
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
) {
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
);
1294 return xmlStrdup(buf
);
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.
1312 _exsltDateCastYMToDays (const exsltDateValPtr dt
)
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
);
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
);
1332 * @dt: an #exsltDateValPtr
1334 * Calculates the number of seconds in the time portion of @dt.
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.
1351 exsltDateCastDateToNumber (const exsltDateValPtr dt
)
1358 if ((dt
->type
& XS_GYEAR
) == XS_GYEAR
) {
1359 ret
= (double)_exsltDateCastYMToDays(dt
) * SECS_PER_DAY
;
1363 if (dt
->type
== XS_DURATION
) {
1364 ret
+= (double)dt
->value
.dur
.day
* SECS_PER_DAY
;
1365 ret
+= dt
->value
.dur
.sec
;
1367 ret
+= (double)dt
->value
.date
.day
* SECS_PER_DAY
;
1369 ret
+= TIME_TO_NUMBER(dt
);
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.
1386 _exsltDateTruncateDate (exsltDateValPtr dt
, exsltDateType type
)
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;
1413 * @yday: year day (1-366)
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).
1425 _exsltDateDayInWeek(long yday
, long yr
)
1430 ret
= ((yr
+ (((yr
+1)/4)-((yr
+1)/100)+((yr
+1)/400)) + yday
) % 7);
1434 ret
= (((yr
-1) + (((yr
-1)/4)-((yr
-1)/100)+((yr
-1)/400)) + yday
) % 7);
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)
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
))
1468 ret
= exsltDateCreateDate(dt
->type
);
1472 r
= &(ret
->value
.date
);
1473 d
= &(dt
->value
.date
);
1474 u
= &(dur
->value
.dur
);
1480 /* normalize for time zone offset */
1481 u
->sec
-= (d
->tzo
* 60); /* changed from + to - (bug 153000) */
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
;
1504 r
->tz_flag
= d
->tz_flag
;
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);
1515 r
->min
= (unsigned int)MODULO(carry
, 60);
1516 carry
= (long)FQUOTIENT(carry
, 60);
1520 r
->hour
= (unsigned int)MODULO(carry
, 24);
1521 carry
= (long)FQUOTIENT(carry
, 24);
1525 * Note we use tempdays because the temporary values may need more
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)
1536 tempdays
+= u
->day
+ carry
;
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);
1545 * Coverity detected an overrun in daysInMonth
1546 * of size 12 at position 12 with index variable "((r)->mon - 1)"
1552 tempdays
+= MAX_DAYINMONTH(tyr
, tmon
);
1554 } else if (tempdays
> (long)MAX_DAYINMONTH(r
->year
, r
->mon
)) {
1555 tempdays
= tempdays
- MAX_DAYINMONTH(r
->year
, r
->mon
);
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);
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
->mon
!= 1) && (r
->day
!= 1))
1581 ret
->type
= XS_DATE
;
1582 else if ((ret
->type
!= XS_GYEARMONTH
) && (r
->mon
!= 1))
1583 ret
->type
= XS_GYEARMONTH
;
1591 * exsltDateNormalize:
1592 * @dt: an #exsltDateValPtr
1594 * Normalize @dt to GMT time.
1598 exsltDateNormalize (exsltDateValPtr dt
)
1600 exsltDateValPtr dur
, tmp
;
1605 if (((dt
->type
& XS_TIME
) != XS_TIME
) || (dt
->value
.date
.tzo
== 0))
1608 dur
= exsltDateCreateDate(XS_DURATION
);
1612 tmp
= _exsltDateAdd(dt
, dur
);
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
))
1644 if (((x
->type
< XS_GYEAR
) || (x
->type
> XS_DATETIME
)) ||
1645 ((y
->type
< XS_GYEAR
) || (y
->type
> XS_DATETIME
)))
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
);
1659 _exsltDateTruncateDate(x
, y
->type
);
1663 ret
= exsltDateCreateDate(XS_DURATION
);
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 :-) */
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
;
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.
1702 _exsltDateAddDurCalc (exsltDateValPtr ret
, exsltDateValPtr x
,
1708 ret
->value
.dur
.mon
= x
->value
.dur
.mon
+ y
->value
.dur
.mon
;
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
;
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
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))) {
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
))
1760 ret
= exsltDateCreateDate(XS_DURATION
);
1764 if (_exsltDateAddDurCalc(ret
, x
, y
))
1767 exsltDateFreeDate(ret
);
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.
1786 exsltDateDateTime (void)
1788 xmlChar
*ret
= NULL
;
1790 exsltDateValPtr cur
;
1792 cur
= exsltDateCurrent();
1794 ret
= exsltDateFormatDateTime(&(cur
->value
.date
));
1795 exsltDateFreeDate(cur
);
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
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.
1819 exsltDateDate (const xmlChar
*dateTime
)
1821 exsltDateValPtr dt
= NULL
;
1822 xmlChar
*ret
= NULL
;
1824 if (dateTime
== NULL
) {
1826 dt
= exsltDateCurrent();
1831 dt
= exsltDateParse(dateTime
);
1834 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
)) {
1835 exsltDateFreeDate(dt
);
1840 ret
= exsltDateFormatDate(&(dt
->value
.date
));
1841 exsltDateFreeDate(dt
);
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
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.
1863 exsltDateTime (const xmlChar
*dateTime
)
1865 exsltDateValPtr dt
= NULL
;
1866 xmlChar
*ret
= NULL
;
1868 if (dateTime
== NULL
) {
1870 dt
= exsltDateCurrent();
1875 dt
= exsltDateParse(dateTime
);
1878 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_TIME
)) {
1879 exsltDateFreeDate(dt
);
1884 ret
= exsltDateFormatTime(&(dt
->value
.date
));
1885 exsltDateFreeDate(dt
);
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)
1907 * If the date/time string is not in one of these formats, then NaN is
1911 exsltDateYear (const xmlChar
*dateTime
)
1916 if (dateTime
== NULL
) {
1918 dt
= exsltDateCurrent();
1923 dt
= exsltDateParse(dateTime
);
1926 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
) &&
1927 (dt
->type
!= XS_GYEARMONTH
) && (dt
->type
!= XS_GYEAR
)) {
1928 exsltDateFreeDate(dt
);
1933 ret
= (double) dt
->value
.date
.year
;
1934 exsltDateFreeDate(dt
);
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)
1956 * If the date/time string is not in one of these formats, then NaN is
1959 static xmlXPathObjectPtr
1960 exsltDateLeapYear (const xmlChar
*dateTime
)
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
1996 exsltDateMonthInYear (const xmlChar
*dateTime
)
2001 if (dateTime
== NULL
) {
2003 dt
= exsltDateCurrent();
2008 dt
= exsltDateParse(dateTime
);
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
);
2019 ret
= (double) dt
->value
.date
.mon
;
2020 exsltDateFreeDate(dt
);
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] = {
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 }
2067 month
= (int) exsltDateMonthInYear(dateTime
);
2068 if (!VALID_MONTH(month
))
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
2096 static const xmlChar
*
2097 exsltDateMonthAbbreviation (const xmlChar
*dateTime
)
2099 static const xmlChar monthAbbreviations
[13][4] = {
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 }
2115 month
= (int) exsltDateMonthInYear(dateTime
);
2116 if(!VALID_MONTH(month
))
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
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
2143 exsltDateWeekInYear (const xmlChar
*dateTime
)
2146 long diy
, diw
, year
, ret
;
2148 if (dateTime
== NULL
) {
2150 dt
= exsltDateCurrent();
2155 dt
= exsltDateParse(dateTime
);
2158 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
)) {
2159 exsltDateFreeDate(dt
);
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 */
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
2212 exsltDateWeekInMonth (const xmlChar
*dateTime
)
2215 long fdiy
, fdiw
, ret
;
2217 if (dateTime
== NULL
) {
2219 dt
= exsltDateCurrent();
2224 dt
= exsltDateParse(dateTime
);
2227 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
)) {
2228 exsltDateFreeDate(dt
);
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
2266 exsltDateDayInYear (const xmlChar
*dateTime
)
2271 if (dateTime
== NULL
) {
2273 dt
= exsltDateCurrent();
2278 dt
= exsltDateParse(dateTime
);
2281 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
)) {
2282 exsltDateFreeDate(dt
);
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)
2312 * If the date/time string is not in one of these formats, then NaN is
2316 exsltDateDayInMonth (const xmlChar
*dateTime
)
2321 if (dateTime
== NULL
) {
2323 dt
= exsltDateCurrent();
2328 dt
= exsltDateParse(dateTime
);
2331 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
) &&
2332 (dt
->type
!= XS_GMONTHDAY
) && (dt
->type
!= XS_GDAY
)) {
2333 exsltDateFreeDate(dt
);
2338 ret
= (double) dt
->value
.date
.day
;
2339 exsltDateFreeDate(dt
);
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
2364 exsltDateDayOfWeekInMonth (const xmlChar
*dateTime
)
2369 if (dateTime
== NULL
) {
2371 dt
= exsltDateCurrent();
2376 dt
= exsltDateParse(dateTime
);
2379 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
)) {
2380 exsltDateFreeDate(dt
);
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
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.
2413 exsltDateDayInWeek (const xmlChar
*dateTime
)
2418 if (dateTime
== NULL
) {
2420 dt
= exsltDateCurrent();
2425 dt
= exsltDateParse(dateTime
);
2428 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_DATE
)) {
2429 exsltDateFreeDate(dt
);
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
;
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] = {
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 }
2478 day
= (int) exsltDateDayInWeek(dateTime
);
2479 if((day
< 1) || (day
> 7))
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] = {
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 }
2518 day
= (int) exsltDateDayInWeek(dateTime
);
2519 if((day
< 1) || (day
> 7))
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
2543 exsltDateHourInDay (const xmlChar
*dateTime
)
2548 if (dateTime
== NULL
) {
2550 dt
= exsltDateCurrent();
2555 dt
= exsltDateParse(dateTime
);
2558 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_TIME
)) {
2559 exsltDateFreeDate(dt
);
2564 ret
= (double) dt
->value
.date
.hour
;
2565 exsltDateFreeDate(dt
);
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
2589 exsltDateMinuteInHour (const xmlChar
*dateTime
)
2594 if (dateTime
== NULL
) {
2596 dt
= exsltDateCurrent();
2601 dt
= exsltDateParse(dateTime
);
2604 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_TIME
)) {
2605 exsltDateFreeDate(dt
);
2610 ret
= (double) dt
->value
.date
.min
;
2611 exsltDateFreeDate(dt
);
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
2634 * Returns the second or NaN.
2637 exsltDateSecondInMinute (const xmlChar
*dateTime
)
2642 if (dateTime
== NULL
) {
2644 dt
= exsltDateCurrent();
2649 dt
= exsltDateParse(dateTime
);
2652 if ((dt
->type
!= XS_DATETIME
) && (dt
->type
!= XS_TIME
)) {
2653 exsltDateFreeDate(dt
);
2658 ret
= dt
->value
.date
.sec
;
2659 exsltDateFreeDate(dt
);
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)
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:
2686 * Returns date/time string or NULL.
2689 exsltDateAdd (const xmlChar
*xstr
, const xmlChar
*ystr
)
2691 exsltDateValPtr dt
, dur
, res
;
2694 if ((xstr
== NULL
) || (ystr
== NULL
))
2697 dt
= exsltDateParse(xstr
);
2700 else if ((dt
->type
< XS_GYEAR
) || (dt
->type
> XS_DATETIME
)) {
2701 exsltDateFreeDate(dt
);
2705 dur
= exsltDateParseDuration(ystr
);
2707 exsltDateFreeDate(dt
);
2711 res
= _exsltDateAdd(dt
, dur
);
2713 exsltDateFreeDate(dt
);
2714 exsltDateFreeDate(dur
);
2719 ret
= exsltDateFormat(res
);
2720 exsltDateFreeDate(res
);
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
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.
2747 exsltDateAddDuration (const xmlChar
*xstr
, const xmlChar
*ystr
)
2749 exsltDateValPtr x
, y
, res
;
2752 if ((xstr
== NULL
) || (ystr
== NULL
))
2755 x
= exsltDateParseDuration(xstr
);
2759 y
= exsltDateParseDuration(ystr
);
2761 exsltDateFreeDate(x
);
2765 res
= _exsltDateAddDuration(x
, y
);
2767 exsltDateFreeDate(x
);
2768 exsltDateFreeDate(y
);
2773 ret
= exsltDateFormatDuration(&(res
->value
.dur
));
2774 exsltDateFreeDate(res
);
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.
2799 exsltDateSumFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
2804 exsltDateValPtr x
, total
;
2809 xmlXPathSetArityError (ctxt
);
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
))
2824 if ((ns
== NULL
) || (ns
->nodeNr
== 0)) {
2825 xmlXPathReturnEmptyString (ctxt
);
2827 xmlXPathFreeNodeSet (ns
);
2831 total
= exsltDateCreateDate (XS_DURATION
);
2832 if (total
== NULL
) {
2833 xmlXPathFreeNodeSet (ns
);
2837 for (i
= 0; i
< ns
->nodeNr
; i
++) {
2839 tmp
= xmlXPathCastNodeToString (ns
->nodeTab
[i
]);
2841 xmlXPathFreeNodeSet (ns
);
2842 exsltDateFreeDate (total
);
2846 x
= exsltDateParseDuration (tmp
);
2849 exsltDateFreeDate (total
);
2850 xmlXPathFreeNodeSet (ns
);
2851 xmlXPathReturnEmptyString (ctxt
);
2855 result
= _exsltDateAddDurCalc(total
, total
, x
);
2857 exsltDateFreeDate (x
);
2860 exsltDateFreeDate (total
);
2861 xmlXPathFreeNodeSet (ns
);
2862 xmlXPathReturnEmptyString (ctxt
);
2867 ret
= exsltDateFormatDuration (&(total
->value
.dur
));
2868 exsltDateFreeDate (total
);
2870 xmlXPathFreeNodeSet (ns
);
2872 xmlFreeNodeList ((xmlNodePtr
) user
);
2875 xmlXPathReturnEmptyString (ctxt
);
2877 xmlXPathReturnString (ctxt
, ret
);
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)
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.
2909 exsltDateSeconds (const xmlChar
*dateTime
)
2912 double ret
= xmlXPathNAN
;
2914 if (dateTime
== NULL
) {
2916 dt
= exsltDateCurrent();
2921 dt
= exsltDateParseDuration(dateTime
);
2923 dt
= exsltDateParse(dateTime
);
2929 if ((dt
->type
<= XS_DATETIME
) && (dt
->type
>= XS_GYEAR
)) {
2930 exsltDateValPtr y
, dur
;
2933 * compute the difference between the given (or current) date
2936 y
= exsltDateCreateDate(XS_DATETIME
);
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);
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
);
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)
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.
2997 exsltDateDifference (const xmlChar
*xstr
, const xmlChar
*ystr
)
2999 exsltDateValPtr x
, y
, dur
;
3000 xmlChar
*ret
= NULL
;
3002 if ((xstr
== NULL
) || (ystr
== NULL
))
3005 x
= exsltDateParse(xstr
);
3009 y
= exsltDateParse(ystr
);
3011 exsltDateFreeDate(x
);
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
);
3022 dur
= _exsltDateDifference(x
, y
, 0);
3024 exsltDateFreeDate(x
);
3025 exsltDateFreeDate(y
);
3030 ret
= exsltDateFormatDuration(&(dur
->value
.dur
));
3031 exsltDateFreeDate(dur
);
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
3051 * If the argument is Infinity, -Infinity or NaN, then date:duration
3052 * returns an empty string ('').
3054 * Returns duration string or NULL.
3057 exsltDateDuration (const xmlChar
*number
)
3059 exsltDateValPtr dur
;
3064 secs
= exsltDateSeconds(number
);
3066 secs
= xmlXPathCastStringToNumber(number
);
3068 if ((xmlXPathIsNaN(secs
)) || (xmlXPathIsInf(secs
)))
3071 dur
= exsltDateCreateDate(XS_DURATION
);
3075 dur
->value
.dur
.sec
= secs
;
3077 ret
= exsltDateFormatDuration(&(dur
->value
.dur
));
3078 exsltDateFreeDate(dur
);
3083 /****************************************************************
3085 * Wrappers for use by the XPath engine *
3087 ****************************************************************/
3091 * exsltDateDateTimeFunction:
3092 * @ctxt: an XPath parser context
3093 * @nargs : the number of arguments
3095 * Wraps exsltDateDateTime() for use by the XPath engine.
3098 exsltDateDateTimeFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3103 xmlXPathSetArityError(ctxt
);
3107 ret
= exsltDateDateTime();
3109 xmlXPathReturnEmptyString(ctxt
);
3111 xmlXPathReturnString(ctxt
, ret
);
3116 * exsltDateDateFunction:
3117 * @ctxt: an XPath parser context
3118 * @nargs : the number of arguments
3120 * Wraps exsltDateDate() for use by the XPath engine.
3123 exsltDateDateFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3125 xmlChar
*ret
, *dt
= NULL
;
3127 if ((nargs
< 0) || (nargs
> 1)) {
3128 xmlXPathSetArityError(ctxt
);
3132 dt
= xmlXPathPopString(ctxt
);
3133 if (xmlXPathCheckError(ctxt
)) {
3134 xmlXPathSetTypeError(ctxt
);
3139 ret
= exsltDateDate(dt
);
3142 xsltGenericDebug(xsltGenericDebugContext
,
3143 "{http://exslt.org/dates-and-times}date: "
3144 "invalid date or format %s\n", dt
);
3145 xmlXPathReturnEmptyString(ctxt
);
3147 xmlXPathReturnString(ctxt
, ret
);
3155 * exsltDateTimeFunction:
3156 * @ctxt: an XPath parser context
3157 * @nargs : the number of arguments
3159 * Wraps exsltDateTime() for use by the XPath engine.
3162 exsltDateTimeFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3164 xmlChar
*ret
, *dt
= NULL
;
3166 if ((nargs
< 0) || (nargs
> 1)) {
3167 xmlXPathSetArityError(ctxt
);
3171 dt
= xmlXPathPopString(ctxt
);
3172 if (xmlXPathCheckError(ctxt
)) {
3173 xmlXPathSetTypeError(ctxt
);
3178 ret
= exsltDateTime(dt
);
3181 xsltGenericDebug(xsltGenericDebugContext
,
3182 "{http://exslt.org/dates-and-times}time: "
3183 "invalid date or format %s\n", dt
);
3184 xmlXPathReturnEmptyString(ctxt
);
3186 xmlXPathReturnString(ctxt
, ret
);
3194 * exsltDateYearFunction:
3195 * @ctxt: an XPath parser context
3196 * @nargs : the number of arguments
3198 * Wraps exsltDateYear() for use by the XPath engine.
3201 exsltDateYearFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3206 if ((nargs
< 0) || (nargs
> 1)) {
3207 xmlXPathSetArityError(ctxt
);
3212 dt
= xmlXPathPopString(ctxt
);
3213 if (xmlXPathCheckError(ctxt
)) {
3214 xmlXPathSetTypeError(ctxt
);
3219 ret
= exsltDateYear(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.
3235 exsltDateLeapYearFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3238 xmlXPathObjectPtr ret
;
3240 if ((nargs
< 0) || (nargs
> 1)) {
3241 xmlXPathSetArityError(ctxt
);
3246 dt
= xmlXPathPopString(ctxt
);
3247 if (xmlXPathCheckError(ctxt
)) {
3248 xmlXPathSetTypeError(ctxt
);
3253 ret
= exsltDateLeapYear(dt
);
3258 valuePush(ctxt
, ret
);
3261 #define X_IN_Y(x, y) \
3263 exsltDate##x##In##y##Function (xmlXPathParserContextPtr ctxt, \
3265 xmlChar *dt = NULL; \
3268 if ((nargs < 0) || (nargs > 1)) { \
3269 xmlXPathSetArityError(ctxt); \
3274 dt = xmlXPathPopString(ctxt); \
3275 if (xmlXPathCheckError(ctxt)) { \
3276 xmlXPathSetTypeError(ctxt); \
3281 ret = exsltDate##x##In##y(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.
3299 * exsltDateMonthNameFunction:
3300 * @ctxt: an XPath parser context
3301 * @nargs : the number of arguments
3303 * Wraps exsltDateMonthName() for use by the XPath engine.
3306 exsltDateMonthNameFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3311 if ((nargs
< 0) || (nargs
> 1)) {
3312 xmlXPathSetArityError(ctxt
);
3317 dt
= xmlXPathPopString(ctxt
);
3318 if (xmlXPathCheckError(ctxt
)) {
3319 xmlXPathSetTypeError(ctxt
);
3324 ret
= exsltDateMonthName(dt
);
3330 xmlXPathReturnEmptyString(ctxt
);
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.
3343 exsltDateMonthAbbreviationFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3348 if ((nargs
< 0) || (nargs
> 1)) {
3349 xmlXPathSetArityError(ctxt
);
3354 dt
= xmlXPathPopString(ctxt
);
3355 if (xmlXPathCheckError(ctxt
)) {
3356 xmlXPathSetTypeError(ctxt
);
3361 ret
= exsltDateMonthAbbreviation(dt
);
3367 xmlXPathReturnEmptyString(ctxt
);
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.
3382 * exsltDateWeekInMonthFunction:
3383 * @ctxt: an XPath parser context
3384 * @nargs : the number of arguments
3386 * Wraps exsltDateWeekInMonthYear() for use by the XPath engine.
3391 * exsltDateDayInYearFunction:
3392 * @ctxt: an XPath parser context
3393 * @nargs : the number of arguments
3395 * Wraps exsltDateDayInYear() for use by the XPath engine.
3400 * exsltDateDayInMonthFunction:
3401 * @ctxt: an XPath parser context
3402 * @nargs : the number of arguments
3404 * Wraps exsltDateDayInMonth() for use by the XPath engine.
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.
3427 * exsltDateDayNameFunction:
3428 * @ctxt: an XPath parser context
3429 * @nargs : the number of arguments
3431 * Wraps exsltDateDayName() for use by the XPath engine.
3434 exsltDateDayNameFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3439 if ((nargs
< 0) || (nargs
> 1)) {
3440 xmlXPathSetArityError(ctxt
);
3445 dt
= xmlXPathPopString(ctxt
);
3446 if (xmlXPathCheckError(ctxt
)) {
3447 xmlXPathSetTypeError(ctxt
);
3452 ret
= exsltDateDayName(dt
);
3458 xmlXPathReturnEmptyString(ctxt
);
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.
3471 exsltDateDayAbbreviationFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3476 if ((nargs
< 0) || (nargs
> 1)) {
3477 xmlXPathSetArityError(ctxt
);
3482 dt
= xmlXPathPopString(ctxt
);
3483 if (xmlXPathCheckError(ctxt
)) {
3484 xmlXPathSetTypeError(ctxt
);
3489 ret
= exsltDateDayAbbreviation(dt
);
3495 xmlXPathReturnEmptyString(ctxt
);
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.
3511 * exsltDateMinuteInHourFunction:
3512 * @ctxt: an XPath parser context
3513 * @nargs : the number of arguments
3515 * Wraps exsltDateMinuteInHour() for use by the XPath engine.
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.
3536 exsltDateSecondsFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3538 xmlChar
*str
= NULL
;
3542 xmlXPathSetArityError(ctxt
);
3547 str
= xmlXPathPopString(ctxt
);
3548 if (xmlXPathCheckError(ctxt
)) {
3549 xmlXPathSetTypeError(ctxt
);
3554 ret
= exsltDateSeconds(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.
3569 exsltDateAddFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3571 xmlChar
*ret
, *xstr
, *ystr
;
3574 xmlXPathSetArityError(ctxt
);
3577 ystr
= xmlXPathPopString(ctxt
);
3578 if (xmlXPathCheckError(ctxt
))
3581 xstr
= xmlXPathPopString(ctxt
);
3582 if (xmlXPathCheckError(ctxt
)) {
3587 ret
= exsltDateAdd(xstr
, ystr
);
3593 xmlXPathReturnEmptyString(ctxt
);
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.
3606 exsltDateAddDurationFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3608 xmlChar
*ret
, *xstr
, *ystr
;
3611 xmlXPathSetArityError(ctxt
);
3614 ystr
= xmlXPathPopString(ctxt
);
3615 if (xmlXPathCheckError(ctxt
))
3618 xstr
= xmlXPathPopString(ctxt
);
3619 if (xmlXPathCheckError(ctxt
)) {
3624 ret
= exsltDateAddDuration(xstr
, ystr
);
3630 xmlXPathReturnEmptyString(ctxt
);
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.
3643 exsltDateDifferenceFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3645 xmlChar
*ret
, *xstr
, *ystr
;
3648 xmlXPathSetArityError(ctxt
);
3651 ystr
= xmlXPathPopString(ctxt
);
3652 if (xmlXPathCheckError(ctxt
))
3655 xstr
= xmlXPathPopString(ctxt
);
3656 if (xmlXPathCheckError(ctxt
)) {
3661 ret
= exsltDateDifference(xstr
, ystr
);
3667 xmlXPathReturnEmptyString(ctxt
);
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
3680 exsltDateDurationFunction (xmlXPathParserContextPtr ctxt
, int nargs
)
3683 xmlChar
*number
= NULL
;
3685 if ((nargs
< 0) || (nargs
> 1)) {
3686 xmlXPathSetArityError(ctxt
);
3691 number
= xmlXPathPopString(ctxt
);
3692 if (xmlXPathCheckError(ctxt
)) {
3693 xmlXPathSetTypeError(ctxt
);
3698 ret
= exsltDateDuration(number
);
3704 xmlXPathReturnEmptyString(ctxt
);
3706 xmlXPathReturnString(ctxt
, ret
);
3710 * exsltDateRegister:
3712 * Registers the EXSLT - Dates and Times module
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
);
3727 xsltRegisterExtModuleFunction ((const xmlChar
*) "date-time",
3728 (const xmlChar
*) EXSLT_DATE_NAMESPACE
,
3729 exsltDateDateTimeFunction
);
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
)
3806 && !xmlXPathRegisterNs(ctxt
,
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
)
3822 && !xmlXPathRegisterFuncNS(ctxt
,
3823 (const xmlChar
*) "date-time",
3824 (const xmlChar
*) EXSLT_DATE_NAMESPACE
,
3825 exsltDateDateTimeFunction
)
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
)) {