1 /*
2 * Copyright 2006-2008 The FLWOR Foundation.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "stdafx.h"
17
18 #include <string>
19 #include <exception>
20 #include <cassert>
21 #include <memory>
22
23 #ifndef WIN32
24 #include <sys/time.h>
25 #else
26 #include <sys/timeb.h>
27 #include <time.h>
28 #endif
29
30 #include "zorbautils/hashfun.h"
31 #include <zorbatypes/datetime.h>
32 #include <zorbatypes/duration.h>
33 #include <zorbatypes/timezone.h>
34 #include <zorbatypes/zorbatypes_decl.h>
35 #include <zorbatypes/zstring.h>
36
37 #include "zorbatypes/datetime/parse.h"
38
39 #include "util/ascii_util.h"
40
41
42 namespace zorba
43 {
44
45 static const char separators[] = { '-', '-', 'T', ':', ':', '.'};
46
47 static const char min_length[] = { 4, 2, 2, 2, 2, 2, 0};
48
49
50 const int DateTime::FACET_MEMBERS[][8] =
51 {
52 { 1, 1, 1, 1, 1, 1, 1, 0}, // DATETIME_FACET = 0,
53 { 1, 1, 1, 0, 0, 0, 0, 0}, // DATE_FACET = 1,
54 { 0, 0, 0, 1, 1, 1, 1, 0}, // TIME_FACET = 2,
55 { 1, 1, 0, 0, 0, 0, 0, 0}, // GYEARMONTH_FACET = 3
56 { 1, 0, 0, 0, 0, 0, 0, 0}, // GYEAR_FACET = 4
57 { 0, 1, 0, 0, 0, 0, 0, 0}, // GMONTH_FACET = 5
58 { 0, 1, 1, 0, 0, 0, 0, 0}, // GMONTHDAY_FACET = 6
59 { 0, 0, 1, 0, 0, 0, 0, 0} // GDAY_FACET = 7
60 };
61
62
63 const int DateTime::FRAC_SECONDS_UPPER_LIMIT = 1000000;
64
65
DateTime()66 DateTime::DateTime()
67 :
68 facet(DATETIME_FACET)
69 {
70 init();
71 }
72
73
init()74 void DateTime::init()
75 {
76 facet = DATETIME_FACET;
77
78 for (int i = YEAR_DATA; i <= DAY_DATA; i++)
79 data[i] = 1;
80
81 for (int i = HOUR_DATA; i <= FRACSECONDS_DATA; i++)
82 data[i] = 0;
83
84 the_time_zone = TimeZone();
85 }
86
87
createDateTime(const DateTime * date,const DateTime * time,DateTime & result)88 int DateTime::createDateTime(
89 const DateTime* date,
90 const DateTime* time,
91 DateTime& result)
92 {
93 if (!date->getTimezone().timeZoneNotSet() &&
94 !time->getTimezone().timeZoneNotSet() &&
95 !(date->getTimezone() == time->getTimezone()))
96 return 2;
97
98 int res = createDateTime(date->getYear(),
99 date->getMonth(),
100 date->getDay(),
101 time->getHours(),
102 time->getMinutes(),
103 time->getIntSeconds(),
104 time->getFractionalSeconds(),
105 result);
106
107 if (res == 0)
108 {
109 if (!date->getTimezone().timeZoneNotSet())
110 result.the_time_zone = date->getTimezone();
111 else if (!time->getTimezone().timeZoneNotSet())
112 result.the_time_zone = time->getTimezone();
113 }
114
115 return res;
116 }
117
118
createDateTime(int years,int months,int days,int hours,int minutes,int seconds,int fractional_seconds,DateTime & dt)119 int DateTime::createDateTime(
120 int years,
121 int months,
122 int days,
123 int hours,
124 int minutes,
125 int seconds,
126 int fractional_seconds,
127 DateTime& dt)
128 {
129 dt.facet = DATETIME_FACET;
130 dt.data[YEAR_DATA] = years;
131 dt.data[MONTH_DATA] = abs<int>(months);
132 dt.data[DAY_DATA] = abs<int>(days);
133 dt.data[HOUR_DATA] = abs<int>(hours);
134 dt.data[MINUTE_DATA] = abs<int>(minutes);
135 dt.data[SECONDS_DATA] = abs<int>(seconds);
136 dt.data[FRACSECONDS_DATA] = abs<int>(fractional_seconds);
137 return 0;
138 }
139
140
createDateTime(int years,int months,int days,int hours,int minutes,double seconds,const TimeZone * tz,DateTime & dt)141 int DateTime::createDateTime(
142 int years,
143 int months,
144 int days,
145 int hours,
146 int minutes,
147 double seconds,
148 const TimeZone* tz,
149 DateTime& dt)
150 {
151 dt.facet = DATETIME_FACET;
152 dt.data[YEAR_DATA] = years;
153 dt.data[MONTH_DATA] = abs<int>(months);
154 dt.data[DAY_DATA] = abs<int>(days);
155 dt.data[HOUR_DATA] = abs<int>(hours);
156 dt.data[MINUTE_DATA] = abs<int>(minutes);
157 dt.data[SECONDS_DATA] = floor<double>(abs<double>(seconds));
158 dt.data[FRACSECONDS_DATA] = round(frac(abs<double>(seconds)) * FRAC_SECONDS_UPPER_LIMIT);
159
160 if (tz != NULL)
161 dt.the_time_zone = *tz;
162
163 return 0;
164 }
165
166
createDateTime(int years,int months,int days,int hours,int minutes,int seconds,int fractional_seconds,const TimeZone * tz,DateTime & dt)167 int DateTime::createDateTime(
168 int years,
169 int months,
170 int days,
171 int hours,
172 int minutes,
173 int seconds,
174 int fractional_seconds,
175 const TimeZone* tz,
176 DateTime& dt)
177 {
178 dt.facet = DATETIME_FACET;
179 dt.data[YEAR_DATA] = years;
180 dt.data[MONTH_DATA] = abs<int>(months);
181 dt.data[DAY_DATA] = abs<int>(days);
182 dt.data[HOUR_DATA] = abs<int>(hours);
183 dt.data[MINUTE_DATA] = abs<int>(minutes);
184 dt.data[SECONDS_DATA] = abs<int>(seconds);
185 dt.data[FRACSECONDS_DATA] = abs<int>(fractional_seconds);
186
187 if (tz != NULL)
188 dt.the_time_zone = *tz;
189
190 return 0;
191 }
192
193
createDate(int years,int months,int days,const TimeZone * tz,DateTime & dt)194 int DateTime::createDate(
195 int years,
196 int months,
197 int days,
198 const TimeZone* tz,
199 DateTime& dt)
200 {
201 dt.facet = DATE_FACET;
202 dt.data[YEAR_DATA] = years;
203 dt.data[MONTH_DATA] = abs<int>(months);
204 dt.data[DAY_DATA] = abs<int>(days);
205 dt.data[HOUR_DATA] = 0;
206 dt.data[MINUTE_DATA] = 0;
207 dt.data[SECONDS_DATA] = 0;
208 dt.data[FRACSECONDS_DATA] = 0;
209
210 if (tz != NULL)
211 dt.the_time_zone = *tz;
212
213 return 0;
214 }
215
216
createTime(int hours,int minutes,double seconds,const TimeZone * tz,DateTime & dt)217 int DateTime::createTime(
218 int hours,
219 int minutes,
220 double seconds,
221 const TimeZone* tz,
222 DateTime& dt)
223 {
224 dt.facet = TIME_FACET;
225 dt.data[YEAR_DATA] = 1;
226 dt.data[MONTH_DATA] = 1;
227 dt.data[DAY_DATA] = 1;
228 dt.data[HOUR_DATA] = abs<int>(hours);
229 dt.data[MINUTE_DATA] = abs<int>(minutes);
230 dt.data[SECONDS_DATA] = floor<double>(abs<double>(seconds));
231 dt.data[FRACSECONDS_DATA] = round(frac(abs<double>(seconds)) * FRAC_SECONDS_UPPER_LIMIT);
232
233 if (tz != NULL)
234 dt.the_time_zone = *tz;
235
236 return 0;
237 }
238
239
createGYearMonth(int years,int months,DateTime & dt)240 int DateTime::createGYearMonth(int years, int months, DateTime& dt)
241 {
242 dt.facet = GYEARMONTH_FACET;
243 dt.data[YEAR_DATA] = years;
244 dt.data[MONTH_DATA] = abs<int>(months);
245 dt.data[DAY_DATA] = 1;
246 dt.data[HOUR_DATA] = 0;
247 dt.data[MINUTE_DATA] = 0;
248 dt.data[SECONDS_DATA] = 0;
249 dt.data[FRACSECONDS_DATA] = 0;
250
251 return 0;
252 }
253
254
createGYear(int years,DateTime & dt)255 int DateTime::createGYear(int years, DateTime& dt)
256 {
257 dt.facet = GYEAR_FACET;
258 dt.data[YEAR_DATA] = years;
259 dt.data[MONTH_DATA] = 1;
260 dt.data[DAY_DATA] = 1;
261 dt.data[HOUR_DATA] = 0;
262 dt.data[MINUTE_DATA] = 0;
263 dt.data[SECONDS_DATA] = 0;
264 dt.data[FRACSECONDS_DATA] = 0;
265
266 return 0;
267 }
268
269
createGMonth(int months,DateTime & dt)270 int DateTime::createGMonth(int months, DateTime& dt)
271 {
272 dt.facet = GMONTH_FACET;
273 dt.data[YEAR_DATA] = 1;
274 dt.data[MONTH_DATA] = abs<int>(months);
275 dt.data[DAY_DATA] = 1;
276 dt.data[HOUR_DATA] = 0;
277 dt.data[MINUTE_DATA] = 0;
278 dt.data[SECONDS_DATA] = 0;
279 dt.data[FRACSECONDS_DATA] = 0;
280
281 return 0;
282 }
283
284
createGMonthDay(int months,int days,DateTime & dt)285 int DateTime::createGMonthDay(int months, int days, DateTime& dt)
286 {
287 dt.facet = GMONTHDAY_FACET;
288 dt.data[YEAR_DATA] = 1;
289 dt.data[MONTH_DATA] = abs<int>(months);
290 dt.data[DAY_DATA] = abs<int>(days);
291 dt.data[HOUR_DATA] = 0;
292 dt.data[MINUTE_DATA] = 0;
293 dt.data[SECONDS_DATA] = 0;
294 dt.data[FRACSECONDS_DATA] = 0;
295
296 return 0;
297 }
298
299
createGDay(int days,DateTime & dt)300 int DateTime::createGDay(int days, DateTime& dt)
301 {
302 dt.facet = GDAY_FACET;
303 dt.data[YEAR_DATA] = 1;
304 dt.data[MONTH_DATA] = 1;
305 dt.data[DAY_DATA] = abs<int>(days);
306 dt.data[HOUR_DATA] = 0;
307 dt.data[MINUTE_DATA] = 0;
308 dt.data[SECONDS_DATA] = 0;
309 dt.data[FRACSECONDS_DATA] = 0;
310
311 return 0;
312 }
313
314
getLocalTime(DateTime & dt)315 int DateTime::getLocalTime(DateTime& dt)
316 {
317 // TODO: check code on windows
318 #ifndef WIN32
319 struct timeval tv;
320 gettimeofday(&tv, NULL);
321 struct tm curr;
322 localtime_r(&tv.tv_sec, &curr);
323 return createDateTime(curr.tm_year + 1900, curr.tm_mon + 1, curr.tm_mday,
324 curr.tm_hour, curr.tm_min, curr.tm_sec,
325 round((tv.tv_usec / 1000000.0) * FRAC_SECONDS_UPPER_LIMIT), dt);
326 #else
327 #ifndef WINCE
328 struct _timeb tb;
329 _ftime_s(&tb);
330 #else
331 struct timeb tb;
332 ftime(&tb);
333 #endif
334 struct tm curr;
335 _localtime64_s(&curr, &tb.time);
336 return createDateTime(curr.tm_year + 1900, curr.tm_mon + 1, curr.tm_mday,
337 curr.tm_hour, curr.tm_min, curr.tm_sec,
338 round((tb.millitm / 1000.0) * FRAC_SECONDS_UPPER_LIMIT), dt);
339 #endif
340
341 }
342
343
parseDateTime(const char * str,ascii::size_type strlen,DateTime & dt)344 int DateTime::parseDateTime(const char* str, ascii::size_type strlen, DateTime& dt)
345 {
346 ascii::size_type pos = 0;
347
348 // DateTime is of form: '-'? yyyy '-' mm '-' dd 'T' hh ':' mm ':' ss ('.' s+)? (zzzzzz)?
349
350 ascii::skip_whitespace(str, strlen, &pos);
351
352 dt.facet = DATETIME_FACET;
353
354 if (parse_date(str,
355 strlen,
356 pos,
357 dt.data[YEAR_DATA],
358 dt.data[MONTH_DATA],
359 dt.data[DAY_DATA]))
360 return 1;
361
362 if (pos == strlen || str[pos++] != 'T')
363 return 1;
364
365 if (parse_time(str,
366 strlen,
367 pos,
368 dt.data[HOUR_DATA],
369 dt.data[MINUTE_DATA],
370 dt.data[SECONDS_DATA],
371 dt.data[FRACSECONDS_DATA]))
372 return 1;
373
374 ascii::size_type savepos = pos;
375
376 ascii::skip_whitespace(str, strlen, &pos);
377
378 if (savepos != pos && pos != strlen)
379 return 1;
380
381 if (pos < strlen)
382 {
383 if (0 != TimeZone::parseTimeZone(str + pos,
384 strlen - pos,
385 dt.the_time_zone))
386 return 1;
387 }
388
389 if (dt.data[HOUR_DATA] == 24)
390 {
391 dt.data[HOUR_DATA] = 0;
392 std::auto_ptr<DateTime> tmp(dt.addDuration(Duration(Duration::DAYTIMEDURATION_FACET,
393 false, 0, 0, 1, 0, 0, 0)));
394 dt = *tmp;
395 }
396
397 return 0;
398 }
399
400
parseDate(const char * str,ascii::size_type strlen,DateTime & dt)401 int DateTime::parseDate(const char* str, ascii::size_type strlen, DateTime& dt)
402 {
403 TimeZone tz;
404 ascii::size_type pos = 0;
405
406 ascii::skip_whitespace(str, strlen, &pos);
407
408 dt.facet = DATE_FACET;
409
410 if (parse_date(str,
411 strlen,
412 pos,
413 dt.data[YEAR_DATA],
414 dt.data[MONTH_DATA],
415 dt.data[DAY_DATA]))
416 return 1;
417
418 ascii::size_type savepos = pos;
419
420 ascii::skip_whitespace(str, strlen, &pos);
421
422 if (savepos != pos && pos != strlen)
423 return 1;
424
425 if (pos < strlen)
426 {
427 if (0 != TimeZone::parseTimeZone(str + pos, strlen - pos, dt.the_time_zone))
428 return 1;
429 }
430
431 return 0;
432 }
433
434
parseTime(const char * str,ascii::size_type strlen,DateTime & dt)435 int DateTime::parseTime(const char* str, ascii::size_type strlen, DateTime& dt)
436 {
437 ascii::size_type pos = 0;
438
439 ascii::skip_whitespace(str, strlen, &pos);
440
441 dt.facet = TIME_FACET;
442
443 if (parse_time(str, strlen, pos,
444 dt.data[HOUR_DATA],
445 dt.data[MINUTE_DATA],
446 dt.data[SECONDS_DATA],
447 dt.data[FRACSECONDS_DATA]))
448 return 1;
449
450 ascii::size_type savepos = pos;
451
452 ascii::skip_whitespace(str, strlen, &pos);
453
454 if (savepos != pos && pos != strlen)
455 return 1;
456
457 if (pos < strlen)
458 {
459 if (0 != TimeZone::parseTimeZone(str + pos, strlen - pos, dt.the_time_zone))
460 return 1;
461 }
462
463 if (dt.data[HOUR_DATA] == 24)
464 dt.data[HOUR_DATA] = 0;
465
466 return 0;
467 }
468
469
parseGYearMonth(const char * str,ascii::size_type strlen,DateTime & dt)470 int DateTime::parseGYearMonth(const char* str, ascii::size_type strlen, DateTime& dt)
471 {
472 ascii::size_type pos = 0;
473 ascii::size_type temp_pos = 0;
474 zstring temp;
475
476 // GYearMonth of form: '-'? yyyy '-' mm zzzzzz?
477
478 ascii::skip_whitespace(str, strlen, &pos);
479
480 dt.facet = GYEARMONTH_FACET;
481
482 if (str[pos] == '-')
483 {
484 temp.append(str + pos, (8 < strlen - pos ? 8 : strlen - pos));
485 ++pos;
486 }
487 else
488 {
489 temp.append(str + pos, (7 < strlen - pos ? 7 : strlen - pos));
490 }
491
492 temp += "-01";
493
494 if (parse_date(temp.c_str(),
495 (ulong)temp.size(),
496 temp_pos,
497 dt.data[YEAR_DATA],
498 dt.data[MONTH_DATA],
499 dt.data[DAY_DATA]))
500 return 1;
501
502 pos += 7;
503
504 ascii::size_type savepos = pos;
505
506 ascii::skip_whitespace(str, strlen, &pos);
507
508 if (savepos != pos && pos != strlen)
509 return 1;
510
511 if (pos < strlen)
512 {
513 if (0 != TimeZone::parseTimeZone(str + pos, strlen - pos, dt.the_time_zone))
514 return 1;
515 }
516
517 return 0;
518 }
519
520
parseGYear(const char * str,ascii::size_type strlen,DateTime & dt)521 int DateTime::parseGYear(const char* str, ascii::size_type strlen, DateTime& dt)
522 {
523 ascii::size_type pos = 0;
524 ascii::size_type temp_pos = 0;
525 zstring temp;
526
527 // GYear of form: '-'? yyyy zzzzzz?
528
529 ascii::skip_whitespace(str, strlen, &pos);
530
531 dt.facet = GYEAR_FACET;
532
533 temp.reserve(12);
534
535 if (str[pos] == '-')
536 {
537 temp.append(str + pos, (5 < strlen - pos ? 5 : strlen - pos));
538 ++pos;
539 }
540 else
541 {
542 temp.append(str + pos, (4 < strlen - pos ? 4 : strlen - pos));
543 }
544
545 temp += "-01-01";
546
547 if (parse_date(temp.c_str(),
548 (ulong)temp.size(),
549 temp_pos,
550 dt.data[YEAR_DATA],
551 dt.data[MONTH_DATA],
552 dt.data[DAY_DATA]))
553 return 1;
554
555 pos += 4;
556
557 ascii::size_type savepos = pos;
558
559 ascii::skip_whitespace(str, strlen, &pos);
560
561 if (savepos != pos && pos != strlen)
562 return 1;
563
564 if (pos < strlen)
565 {
566 if (0 != TimeZone::parseTimeZone(str + pos, strlen - pos, dt.the_time_zone))
567 return 1;
568 }
569
570 return 0;
571 }
572
573
parseGMonth(const char * str,ascii::size_type strlen,DateTime & dt)574 int DateTime::parseGMonth(const char* str, ascii::size_type strlen, DateTime& dt)
575 {
576 ascii::size_type pos = 0;
577 ascii::size_type temp_pos = 0;
578 zstring temp;
579
580 // GMonth of form: --MM zzzzzz?
581 // preceding - is not allowed.
582
583 ascii::skip_whitespace(str, strlen, &pos);
584
585 dt.facet = GMONTH_FACET;
586
587 if (str[pos++] != '-')
588 return 1;
589
590 temp.reserve(12);
591 temp = "0001";
592 temp.append(str + pos, 3);
593 temp += "-01";
594
595 if (parse_date(temp.c_str(),
596 (ulong)temp.size(),
597 temp_pos,
598 dt.data[YEAR_DATA],
599 dt.data[MONTH_DATA],
600 dt.data[DAY_DATA]))
601 return 1;
602
603 pos += 3;
604
605 ascii::size_type savepos = pos;
606
607 ascii::skip_whitespace(str, strlen, &pos);
608
609 if (savepos != pos && pos != strlen)
610 return 1;
611
612 if (pos < strlen)
613 {
614 if (0 != TimeZone::parseTimeZone(str + pos, strlen - pos, dt.the_time_zone))
615 return 1;
616 }
617
618 return 0;
619 }
620
621
parseGMonthDay(const char * str,ascii::size_type strlen,DateTime & dt)622 int DateTime::parseGMonthDay(const char* str, ascii::size_type strlen, DateTime& dt)
623 {
624 ascii::size_type pos = 0;
625 ascii::size_type temp_pos = 0;
626 zstring temp;
627
628 // GMonthDay of form: --MM-DD zzzzzz?
629 // preceding - is not allowed.
630
631 ascii::skip_whitespace(str, strlen, &pos);
632
633 dt.facet = GMONTHDAY_FACET;
634
635 if (str[pos++] != '-')
636 return 1;
637
638 temp.reserve(12);
639 temp = "0004";
640 temp.append(str + pos, 6); // Year 4 to make it a leap year, to allow the MonthDay of 29 February
641
642 if (parse_date(temp.c_str(),
643 (ulong)temp.size(),
644 temp_pos,
645 dt.data[YEAR_DATA],
646 dt.data[MONTH_DATA],
647 dt.data[DAY_DATA]))
648 return 1;
649
650 dt.data[YEAR_DATA] = 1;
651
652 pos += 6;
653
654 ascii::size_type savepos = pos;
655
656 ascii::skip_whitespace(str, strlen, &pos);
657
658 if (savepos != pos && pos != strlen)
659 return 1;
660
661 if (pos < strlen)
662 {
663 if (0 != TimeZone::parseTimeZone(str + pos, strlen - pos, dt.the_time_zone))
664 return 1;
665 }
666
667 return 0;
668 }
669
670
parseGDay(const char * str,ascii::size_type strlen,DateTime & dt)671 int DateTime::parseGDay(const char* str, ascii::size_type strlen, DateTime& dt)
672 {
673 ascii::size_type pos = 0;
674 ascii::size_type temp_pos = 0;
675 zstring temp;
676
677 // GDay of form: ---DD zzzzzz?
678 // preceding - is not allowed.
679
680 ascii::skip_whitespace(str, strlen, &pos);
681
682 dt.facet = GDAY_FACET;
683
684 if (str[pos++] != '-')
685 return 1;
686
687 if (str[pos++] != '-')
688 return 1;
689
690 temp = "0001-01";
691 temp.append(str + pos, 3);
692
693 if (parse_date(temp.c_str(),
694 (ulong)temp.size(),
695 temp_pos,
696 dt.data[YEAR_DATA],
697 dt.data[MONTH_DATA],
698 dt.data[DAY_DATA]))
699 return 1;
700
701 pos += 3;
702
703 ascii::size_type savepos = pos;
704
705 ascii::skip_whitespace(str, strlen, &pos);
706
707 if (savepos != pos && pos != strlen)
708 return 1;
709
710 if (pos < strlen)
711 {
712 if (0 != TimeZone::parseTimeZone(str + pos, strlen - pos, dt.the_time_zone))
713 return 1;
714 }
715
716 return 0;
717 }
718
719
720 // Returns 0 on success
parse_date(const char * str,ascii::size_type strlen,ascii::size_type & pos,long & year,long & month,long & day)721 int DateTime::parse_date(
722 const char* str,
723 ascii::size_type strlen,
724 ascii::size_type& pos,
725 long& year,
726 long& month,
727 long& day)
728 {
729 bool is_negative = false;
730 ascii::size_type temp_pos;
731
732 if (pos == strlen)
733 return 1;
734
735 if (str[pos] == '-')
736 {
737 is_negative = true;
738 ++pos;
739 }
740
741 // Parse year
742 temp_pos = pos;
743
744 if (pos == strlen || parse_long(str, strlen, pos, year, 4))
745 return 1;
746
747 if (pos - temp_pos > 4 && str[temp_pos] == '0')
748 return 1;
749
750 if (is_negative)
751 year = -year;
752
753 if (pos == strlen || str[pos++] != '-')
754 return 1;
755
756 // Parse month
757 if (pos == strlen || parse_long(str, strlen, pos, month, 2, 2))
758 return 1;
759
760 if (pos == strlen || str[pos++] != '-')
761 return 1;
762
763 // Parse day
764 if (pos == strlen || parse_long(str, strlen, pos, day, 2, 2))
765 return 1;
766
767 // Validate the date
768 // year may not be 0
769 if (year == 0)
770 return 1;
771
772 if (month < 1 || month > 12)
773 return 1;
774
775 if (day < 1 || day > get_last_day(year, month))
776 return 1;
777
778 return 0;
779 }
780
781
782 // Returns 0 on success
parse_time(const char * str,ascii::size_type strlen,ascii::size_type & position,long & hour,long & minute,long & seconds,long & frac_seconds)783 int DateTime::parse_time(
784 const char* str,
785 ascii::size_type strlen,
786 ascii::size_type& position,
787 long& hour,
788 long& minute,
789 long& seconds,
790 long& frac_seconds)
791 {
792 if (position == strlen)
793 return 1;
794
795 // Parse hour
796 if (position == strlen || parse_long(str, strlen, position, hour, 2, 2))
797 return 1;
798
799 if (position == strlen || str[position++] != ':')
800 return 1;
801
802 // Parse minute
803 if (position == strlen || parse_long(str, strlen, position, minute, 2, 2))
804 return 1;
805
806 if (position == strlen || str[position++] != ':')
807 return 1;
808
809 // Parse seconds
810 if (position == strlen || parse_long(str, strlen, position, seconds, 2, 2))
811 return 1;
812
813 if (position < strlen && str[position] == '.')
814 {
815 double temp_frac_seconds;
816 position++;
817
818 if (parse_frac(str, strlen, position, temp_frac_seconds))
819 return 1;
820
821 frac_seconds = round(temp_frac_seconds * FRAC_SECONDS_UPPER_LIMIT);
822 }
823 else
824 {
825 frac_seconds = 0;
826 }
827
828 // Validate the time
829 if (hour > 24)
830 return 1;
831
832 if (minute > 59)
833 return 1;
834
835 if (hour == 24 && minute != 0)
836 return 1;
837
838 if (seconds > 59)
839 return 1;
840
841 if (hour == 24 && (seconds != 0 || frac_seconds != 0))
842 return 1;
843
844 return 0;
845 }
846
847
848
operator =(const DateTime * dt)849 DateTime& DateTime::operator=(const DateTime* dt)
850 {
851 facet = dt->facet;
852
853 for (int i = 0; i < 7; ++i)
854 data[i] = dt->data[i];
855
856 the_time_zone = dt->the_time_zone;
857 return *this;
858 }
859
860
createWithNewFacet(FACET_TYPE new_facet,DateTime & dt) const861 int DateTime::createWithNewFacet(FACET_TYPE new_facet, DateTime& dt) const
862 {
863 dt = *this;
864 dt.setFacet(new_facet);
865 return 0;
866 }
867
868
toString() const869 zstring DateTime::toString() const
870 {
871 zstring result;
872
873 // output sign
874 if (FACET_MEMBERS[facet][0])
875 if (data[YEAR_DATA] < 0)
876 result.append("-", 1);
877
878 // output preceding '-' for Gregorian dates, when needed
879 if (facet == GMONTH_FACET || facet == GMONTHDAY_FACET)
880 result.append("--", 2);
881 if (facet == GDAY_FACET)
882 result.append("---", 3);
883
884 for (int i=0; i<=5; i++)
885 {
886 if (FACET_MEMBERS[facet][i])
887 {
888 result.append(to_string(abs<int>(data[i]), min_length[i]));
889 if (FACET_MEMBERS[facet][i+1] && i<=4)
890 result.push_back(separators[i]);
891 }
892 }
893
894 if (FACET_MEMBERS[facet][FRACSECONDS_DATA] && (data[FRACSECONDS_DATA] != 0))
895 {
896 int temp;
897 result.append(".", 1);
898
899 // print leading 0s, if any
900 temp = FRAC_SECONDS_UPPER_LIMIT / 10;
901 while (temp > data[FRACSECONDS_DATA] && temp > 0)
902 {
903 result.append("0", 1);
904 temp /= 10;
905 }
906
907 // strip trailing 0s, if any
908 temp = data[FRACSECONDS_DATA];
909 while (temp%10 == 0 && temp > 0)
910 temp = temp / 10;
911
912 result.append(to_string(temp));
913 }
914
915 result.append(the_time_zone.toString());
916
917 return result;
918 }
919
920
getDate() const921 DateTime* DateTime::getDate() const
922 {
923 DateTime* dt = new DateTime(*this);
924 dt->setFacet(DATE_FACET);
925 return dt;
926 }
927
928
getTime() const929 DateTime* DateTime::getTime() const
930 {
931 DateTime* dt = new DateTime(*this);
932 dt->setFacet(TIME_FACET);
933 return dt;
934 }
935
936
getYear() const937 int DateTime::getYear() const
938 {
939 return data[YEAR_DATA];
940 }
941
942
getMonth() const943 int DateTime::getMonth() const
944 {
945 assert(data[MONTH_DATA] >= 0);
946 return data[MONTH_DATA];
947 }
948
949
getDay() const950 int DateTime::getDay() const
951 {
952 assert(data[DAY_DATA] >= 0);
953 return data[DAY_DATA];
954 }
955
956
getHours() const957 int DateTime::getHours() const
958 {
959 assert(data[HOUR_DATA] >= 0);
960 return data[HOUR_DATA];
961 }
962
963
getMinutes() const964 int DateTime::getMinutes() const
965 {
966 assert(data[MINUTE_DATA] >= 0);
967 return data[MINUTE_DATA];
968 }
969
970
getSeconds() const971 xs_decimal DateTime::getSeconds() const
972 {
973 return xs_decimal(data[SECONDS_DATA])
974 + (xs_decimal(data[FRACSECONDS_DATA])
975 / Integer(FRAC_SECONDS_UPPER_LIMIT)
976 );
977 }
978
979
getIntSeconds() const980 int DateTime::getIntSeconds() const
981 {
982 assert(data[SECONDS_DATA] >= 0);
983 return data[SECONDS_DATA];
984 }
985
986
getFractionalSeconds() const987 int DateTime::getFractionalSeconds() const
988 {
989 assert(data[FRACSECONDS_DATA] >= 0);
990 return data[FRACSECONDS_DATA];
991 }
992
993
getTimezone() const994 TimeZone DateTime::getTimezone() const
995 {
996 return the_time_zone;
997 }
998
999
compare(const DateTime * dt,long timezone_seconds) const1000 int DateTime::compare(const DateTime* dt, long timezone_seconds) const
1001 {
1002 std::auto_ptr<DateTime> d1_t;
1003 std::auto_ptr<DateTime> d2_t;
1004
1005 d1_t.reset(normalizeTimeZone(timezone_seconds));
1006 d2_t.reset(dt->normalizeTimeZone(timezone_seconds));
1007
1008 if (d1_t->data[YEAR_DATA] < d2_t->data[YEAR_DATA])
1009 return -1;
1010 else if (d1_t->data[YEAR_DATA] > d2_t->data[YEAR_DATA])
1011 return 1;
1012
1013 // compare the rest of the data
1014 if (d1_t->data[YEAR_DATA] < 0 && d2_t->data[YEAR_DATA] < 0)
1015 {
1016 for (int i=1; i<7; i++)
1017 {
1018 if (d1_t->data[i] > d2_t->data[i])
1019 return -1;
1020 else if (d1_t->data[i] < d2_t->data[i])
1021 return 1;
1022 }
1023 }
1024 else
1025 {
1026 for (int i=1; i<7; i++)
1027 {
1028 if (d1_t->data[i] < d2_t->data[i])
1029 return -1;
1030 else if (d1_t->data[i] > d2_t->data[i])
1031 return 1;
1032 }
1033 }
1034
1035 return 0;
1036 }
1037
1038
hash(int implicit_timezone_seconds) const1039 uint32_t DateTime::hash(int implicit_timezone_seconds) const
1040 {
1041 uint32_t hval = 0;
1042 std::auto_ptr<DateTime> dt(normalizeTimeZone(implicit_timezone_seconds));
1043
1044 hval = hashfun::h32<int>((int)dt->facet, hval);
1045 hval = hashfun::h32<int>(dt->data[YEAR_DATA], hval);
1046 hval = hashfun::h32<int>(dt->data[MONTH_DATA], hval);
1047 hval = hashfun::h32<int>(dt->data[DAY_DATA], hval);
1048 hval = hashfun::h32<int>(dt->data[HOUR_DATA], hval);
1049 hval = hashfun::h32<int>(dt->data[MINUTE_DATA], hval);
1050 hval = hashfun::h32<int>(dt->data[SECONDS_DATA], hval);
1051 hval = hashfun::h32<int>(dt->data[FRACSECONDS_DATA], hval);
1052
1053 hval = dt->the_time_zone.hash(hval);
1054
1055 return hval;
1056 }
1057
1058
toDayTimeDuration() const1059 Duration* DateTime::toDayTimeDuration() const
1060 {
1061 if (data[YEAR_DATA] >= 0)
1062 return new Duration(Duration::DAYTIMEDURATION_FACET, false, 0, 0,
1063 365 * (abs<int>(data[YEAR_DATA]) - 1) +
1064 leap_years_count(data[YEAR_DATA]) +
1065 DateTime::getDayOfYear(data[YEAR_DATA],
1066 data[MONTH_DATA],
1067 data[DAY_DATA])-1,
1068 data[HOUR_DATA],
1069 data[MINUTE_DATA],
1070 data[SECONDS_DATA],
1071 data[FRACSECONDS_DATA]);
1072 else
1073 {
1074 Duration days(Duration::DAYTIMEDURATION_FACET, true, 0, 0,
1075 365 * abs<int>(data[YEAR_DATA]) -
1076 leap_years_count(data[YEAR_DATA]) -
1077 DateTime::getDayOfYear(data[YEAR_DATA],
1078 data[MONTH_DATA],
1079 data[DAY_DATA])-1,
1080 0, 0, 0, 0);
1081
1082 Duration remainder(Duration::DAYTIMEDURATION_FACET, false, 0, 0, 0,
1083 data[HOUR_DATA],
1084 data[MINUTE_DATA],
1085 data[SECONDS_DATA],
1086 data[FRACSECONDS_DATA]);
1087
1088 return days + remainder;
1089 }
1090 }
1091
1092
addDuration(const Duration & d,bool adjust_facet) const1093 DateTime* DateTime::addDuration(const Duration& d, bool adjust_facet) const
1094 {
1095 DateTime* new_dt = NULL;
1096 int years, months, days, hours, minutes, int_seconds, frac_seconds, temp_days, carry;
1097 int temp_frac_seconds, total_seconds;
1098
1099 // For the algorithm, see XML Schema 2 spec, Appendix E
1100 // http://www.w3.org/TR/xmlschema-2/#adding-durations-to-dateTimes
1101
1102 months = modulo<int>(data[MONTH_DATA] + d.getMonths() - 1, 12) + 1;
1103
1104 years = data[YEAR_DATA] + d.getYears() +
1105 quotient<int>(data[MONTH_DATA] + d.getMonths() - 1, 12);
1106
1107 //int_seconds = modulo<int>(floor(getSeconds() + d.getSeconds()), 60);
1108 temp_frac_seconds = getFractionalSeconds() + d.getFractionalSeconds();
1109 total_seconds = getIntSeconds() + d.getIntSeconds() + quotient<int>(temp_frac_seconds, DateTime::FRAC_SECONDS_UPPER_LIMIT);
1110 int_seconds = modulo<int>(total_seconds, 60);
1111
1112 frac_seconds = modulo<int>(temp_frac_seconds, DateTime::FRAC_SECONDS_UPPER_LIMIT);
1113
1114 minutes = data[MINUTE_DATA] + d.getMinutes() + quotient<int>(total_seconds, 60);
1115
1116 hours = data[HOUR_DATA] + d.getHours() + quotient<int>(minutes, 60);
1117
1118 minutes = modulo<int>(minutes, 60);
1119
1120 carry = quotient<int>(hours, 24);
1121
1122 hours = modulo<int>(hours, 24);
1123
1124 if (data[DAY_DATA] > get_last_day(years, months))
1125 temp_days = get_last_day(years, months);
1126 else if (data[DAY_DATA] < 1)
1127 temp_days = 1;
1128 else
1129 temp_days = data[DAY_DATA];
1130
1131 days = d.getDays() + temp_days + carry;
1132 while (1)
1133 {
1134 if (days <1)
1135 {
1136 days = days + get_last_day(years,months-1);
1137 carry = -1;
1138 }
1139 else if (days > get_last_day(years, months))
1140 {
1141 days = days - get_last_day(years, months);
1142 carry = 1;
1143 }
1144 else
1145 break;
1146
1147 years = years + quotient<int>(months + carry-1, 12);
1148 months = modulo<int>(months + carry -1, 12) + 1;
1149 }
1150
1151 if (data[YEAR_DATA] > 0 && d.isNegative() && years <= 0)
1152 years--;
1153 if (data[YEAR_DATA] < 0 && !d.isNegative() && years >= 0)
1154 years++;
1155
1156 new_dt = new DateTime();
1157
1158 if (DateTime::createDateTime(years, months, days, hours, minutes,
1159 int_seconds, frac_seconds, &the_time_zone,
1160 *new_dt))
1161 assert(0);
1162
1163 new_dt->facet = facet;
1164 if (adjust_facet)
1165 new_dt->adjustToFacet();
1166
1167 return new_dt;
1168 }
1169
1170
subtractDuration(const Duration & d,bool adjust_facet) const1171 DateTime* DateTime::subtractDuration(const Duration& d, bool adjust_facet) const
1172 {
1173 std::auto_ptr<Duration> negD(d.toNegDuration());
1174 return addDuration(*negD, adjust_facet);
1175 }
1176
1177
subtractDateTime(const DateTime * dt,int implicit_timezone_seconds) const1178 Duration* DateTime::subtractDateTime(
1179 const DateTime* dt,
1180 int implicit_timezone_seconds) const
1181 {
1182 std::auto_ptr<DateTime> dt1(normalizeTimeZone(implicit_timezone_seconds));
1183 std::auto_ptr<DateTime> dt2(dt->normalizeTimeZone(implicit_timezone_seconds));
1184 std::auto_ptr<Duration> dur1(dt1->toDayTimeDuration());
1185 std::auto_ptr<Duration> dur2(dt2->toDayTimeDuration());
1186 return *dur1 - *dur2;
1187 }
1188
1189
normalizeTimeZone(int tz_seconds) const1190 DateTime* DateTime::normalizeTimeZone(int tz_seconds) const
1191 {
1192 DateTime* dt;
1193 Duration d;
1194
1195 if( the_time_zone.timeZoneNotSet() )
1196 {
1197 // validate timezone value (-14 .. +14 H)
1198 if (tz_seconds > 14*3600 || tz_seconds < -14*3600)
1199 throw InvalidTimezoneException();
1200
1201 d = Duration(Duration::DAYTIMEDURATION_FACET,
1202 (tz_seconds < 0), 0, 0, 0, 0, 0, tz_seconds, 0);
1203 }
1204 else
1205 {
1206 if (0 != Duration::fromTimezone(the_time_zone, d))
1207 assert(0);
1208 }
1209
1210 dt = subtractDuration(d, false); // do not adjust to facet
1211 dt->the_time_zone = TimeZone(0);
1212
1213 return dt;
1214 }
1215
1216
adjustToTimeZone(int tz_seconds) const1217 DateTime* DateTime::adjustToTimeZone(int tz_seconds) const
1218 {
1219 std::auto_ptr<Duration> dtduration;
1220 std::auto_ptr<Duration> context_tz;
1221 std::auto_ptr<DateTime> dt;
1222
1223 // validate timezone value (-14 .. +14 H)
1224 if (tz_seconds > 14*3600 || tz_seconds < -14*3600)
1225 throw InvalidTimezoneException();
1226
1227 // If $timezone is not specified, then $timezone is the value of the implicit timezone in the dynamic context.
1228 context_tz = std::auto_ptr<Duration>(new Duration(Duration::DAYTIMEDURATION_FACET, (tz_seconds<0), 0, 0, 0, 0, 0, tz_seconds, 0));
1229
1230 dt = std::auto_ptr<DateTime>(new DateTime(*this));
1231
1232 // If $arg does not have a timezone component and $timezone is not the empty sequence,
1233 // then the result is $arg with $timezone as the timezone component.
1234 if (the_time_zone.timeZoneNotSet())
1235 {
1236 if (TimeZone::createTimeZone(context_tz->getHours(), context_tz->getMinutes(), context_tz->getIntSeconds(), dt->the_time_zone))
1237 assert(0);
1238 }
1239 else
1240 {
1241 // If $arg has a timezone component and $timezone is not the empty sequence, then
1242 // the result is an xs:dateTime value with a timezone component of $timezone that is equal to $arg.
1243 dtduration = std::auto_ptr<Duration>(new Duration(Duration::DAYTIMEDURATION_FACET,
1244 the_time_zone.isNegative(),
1245 0, 0, 0,
1246 the_time_zone.getHours(),
1247 the_time_zone.getMinutes(),
1248 the_time_zone.getIntSeconds(),
1249 0));
1250
1251 dtduration = std::auto_ptr<Duration>(*context_tz - *dtduration);
1252 dt = std::auto_ptr<DateTime>(dt->addDuration(*dtduration));
1253 if (TimeZone::createTimeZone(context_tz->getHours(), context_tz->getMinutes(), context_tz->getIntSeconds(), dt->the_time_zone))
1254 assert(0);
1255 }
1256
1257 return dt.release();
1258 }
1259
1260
adjustToTimeZone(const Duration * d) const1261 DateTime* DateTime::adjustToTimeZone(const Duration* d) const
1262 {
1263 std::auto_ptr<Duration> dtduration;
1264 std::auto_ptr<const Duration> context_tz;
1265 std::auto_ptr<DateTime> dt;
1266
1267 // A dynamic error is raised [err:FODT0003] if $timezone is less than -PT14H
1268 // or greater than PT14H or if does not contain an integral number of minutes.
1269
1270 dt = std::auto_ptr<DateTime>(new DateTime(*this));
1271
1272 if (d == NULL)
1273 {
1274 if (!the_time_zone.timeZoneNotSet())
1275 dt->the_time_zone = TimeZone();
1276 }
1277 else
1278 {
1279 // validate timezone value (-14 .. +14 H)
1280 if (d->getYears() != 0 || d->getMonths() != 0 ||
1281 d->getDays() != 0 ||
1282 d->getSeconds() != Integer::zero() ||
1283 d->getHours()*3600 + d->getMinutes()*60 > 14*3600 ||
1284 d->getHours()*3600 + d->getMinutes()*60 < -14*3600)
1285 throw InvalidTimezoneException();
1286
1287 // If $arg does not have a timezone component and $timezone is not the
1288 // empty sequence, then the result is $arg with $timezone as the timezone
1289 // component.
1290 if (the_time_zone.timeZoneNotSet())
1291 {
1292 if (TimeZone::createTimeZone(d->getHours(), d->getMinutes(), d->getIntSeconds(), dt->the_time_zone))
1293 assert(0);
1294 }
1295 else
1296 {
1297 // If $arg has a timezone component and $timezone is not the empty sequence, then
1298 // the result is an xs:dateTime value with a timezone component of $timezone that is equal to $arg.
1299 dtduration = std::auto_ptr<Duration>(new Duration(Duration::DAYTIMEDURATION_FACET,
1300 the_time_zone.isNegative(),
1301 0, 0, 0,
1302 the_time_zone.getHours(),
1303 the_time_zone.getMinutes(),
1304 the_time_zone.getIntSeconds(),
1305 0));
1306
1307 context_tz = std::auto_ptr<Duration>(new Duration(*d));
1308 if (context_tz.get() == NULL)
1309 assert(0);
1310
1311 dtduration = std::auto_ptr<Duration>(*context_tz - *dtduration);
1312 dt.reset(dt->addDuration(*dtduration));
1313
1314 if (TimeZone::createTimeZone(context_tz->getHours(),
1315 context_tz->getMinutes(),
1316 context_tz->getIntSeconds(),
1317 dt->the_time_zone))
1318 assert(0);
1319 }
1320 }
1321
1322 return dt.release();
1323 }
1324
1325
setFacet(FACET_TYPE a_facet)1326 void DateTime::setFacet(FACET_TYPE a_facet)
1327 {
1328 facet = a_facet;
1329 adjustToFacet();
1330 }
1331
1332
adjustToFacet()1333 void DateTime::adjustToFacet()
1334 {
1335 switch (facet)
1336 {
1337 case DATETIME_FACET:
1338 // do nothing;
1339 break;
1340 case DATE_FACET:
1341 for (int i=HOUR_DATA; i<=FRACSECONDS_DATA; i++)
1342 data[i] = 0;
1343 break;
1344 case TIME_FACET:
1345 for (int i=YEAR_DATA; i<=DAY_DATA; i++)
1346 data[i] = 1;
1347 break;
1348 case GYEARMONTH_FACET:
1349 data[DAY_DATA] = 1;
1350 for (int i=HOUR_DATA; i<=FRACSECONDS_DATA; i++)
1351 data[i] = 0;
1352 break;
1353 case GYEAR_FACET:
1354 data[MONTH_DATA] = 1;
1355 data[DAY_DATA] = 1;
1356 for (int i=HOUR_DATA; i<=FRACSECONDS_DATA; i++)
1357 data[i] = 0;
1358 break;
1359 case GMONTH_FACET:
1360 data[YEAR_DATA] = 1;
1361 data[DAY_DATA] = 1;
1362 for (int i=HOUR_DATA; i<=FRACSECONDS_DATA; i++)
1363 data[i] = 0;
1364 break;
1365 case GMONTHDAY_FACET:
1366 data[YEAR_DATA] = 1;
1367 for (int i=HOUR_DATA; i<=FRACSECONDS_DATA; i++)
1368 data[i] = 0;
1369 break;
1370 case GDAY_FACET:
1371 data[YEAR_DATA] = 1;
1372 data[MONTH_DATA] = 1;
1373 for (int i=HOUR_DATA; i<=FRACSECONDS_DATA; i++)
1374 data[i] = 0;
1375 break;
1376 }
1377 }
1378
1379
getDayOfWeek(int year,int month,int day)1380 int DateTime::getDayOfWeek(int year, int month, int day)
1381 {
1382 if (month < 3)
1383 {
1384 month = month + 12;
1385 year = year - 1;
1386 }
1387
1388 return (day
1389 + (2 * month)
1390 + int(6 * (month + 1) / 10)
1391 + year
1392 + int(year / 4)
1393 - int(year / 100)
1394 + int(year / 400)
1395 + 1 // CalendarSystem, 1 for Gregorian
1396 ) % 7;
1397 }
1398
1399
getWeekInYear(int year,int month,int day)1400 int DateTime::getWeekInYear(int year, int month, int day)
1401 {
1402 int day_of_year = DateTime::getDayOfYear(year, month, day);
1403 int year_first_day_of_week = DateTime::getDayOfWeek(year, 1, 1);
1404
1405 if (year_first_day_of_week > 4 && (year_first_day_of_week + day_of_year) <= 8)
1406 return getWeekInYear(year-1, 12, 31);
1407
1408 return ((day_of_year + year_first_day_of_week - 2) / 7) + year_first_day_of_week < 5 ? 1 : 0;
1409 }
1410
1411
getDayOfYear(int year,int month,int day)1412 int DateTime::getDayOfYear(int year, int month, int day)
1413 {
1414 static const int days[] = {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365};
1415
1416 if (month > 12)
1417 return -1;
1418
1419 if (isLeapYear(year) && month >= 3)
1420 day++;
1421
1422 return days[month-1] + day;
1423 }
1424
1425
isLeapYear(int year)1426 bool DateTime::isLeapYear(int year)
1427 {
1428 if (((year%4 == 0) && (year%100 != 0))
1429 ||
1430 (year%400 == 0))
1431 return true;
1432 else
1433 return false;
1434 }
1435
1436
getWeekInMonth(int year,int month,int day)1437 int DateTime::getWeekInMonth(int year, int month, int day)
1438 {
1439 int first_day_of_week = DateTime::getDayOfWeek(year, month, 1);
1440 return ((day + first_day_of_week - 2) / 7) + (first_day_of_week < 5 ? 1 : 0);
1441 }
1442
1443
isLeapYear() const1444 bool DateTime::isLeapYear() const
1445 {
1446 return isLeapYear(data[YEAR_DATA]);
1447 }
1448
1449
getDayOfWeek() const1450 int DateTime::getDayOfWeek() const
1451 {
1452 return getDayOfWeek(data[YEAR_DATA], data[MONTH_DATA], data[DAY_DATA]);
1453 }
1454
1455
getDayOfYear() const1456 int DateTime::getDayOfYear() const
1457 {
1458 return getDayOfYear(data[YEAR_DATA], data[MONTH_DATA], data[DAY_DATA]);
1459 }
1460
1461
getWeekInYear() const1462 int DateTime::getWeekInYear() const
1463 {
1464 return getWeekInYear(data[YEAR_DATA], data[MONTH_DATA], data[DAY_DATA]);
1465 }
1466
1467
getWeekInMonth() const1468 int DateTime::getWeekInMonth() const
1469 {
1470 return getWeekInMonth(data[YEAR_DATA], data[MONTH_DATA], data[DAY_DATA]);
1471 }
1472
1473 } // namespace xqp
1474 /* vim:set et sw=2 ts=2: */
1475