Qore Programming Language 1.19.1
Loading...
Searching...
No Matches
qore_date_private.h
1/* -*- mode: c++; indent-tabs-mode: nil -*- */
2/*
3 qore_date_private.h
4
5 DateTime private implementation
6
7 Qore Programming Language
8
9 Copyright (C) 2003 - 2023 Qore Technologies, s.r.o.
10
11 Permission is hereby granted, free of charge, to any person obtaining a
12 copy of this software and associated documentation files (the "Software"),
13 to deal in the Software without restriction, including without limitation
14 the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 and/or sell copies of the Software, and to permit persons to whom the
16 Software is furnished to do so, subject to the following conditions:
17
18 The above copyright notice and this permission notice shall be included in
19 all copies or substantial portions of the Software.
20
21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 DEALINGS IN THE SOFTWARE.
28
29 Note that the Qore library is released under a choice of three open-source
30 licenses: MIT (as above), LGPL 2+, or GPL 2+; see README-LICENSE for more
31 information.
32*/
33
34#ifndef QORE_QORE_DATE_PRIVATE_H
35#define QORE_QORE_DATE_PRIVATE_H
36
37#include <cmath>
38
39// note: this implementation does not yet take into account leap seconds,
40// even if this information is available in the zoneinfo data
41
42#define SECS_PER_MINUTE 60
43// 3600
44#define SECS_PER_HOUR (SECS_PER_MINUTE * 60)
45// number of seconds in a normal day (no DST) = 86400
46#define SECS_PER_DAY (SECS_PER_HOUR * 24)
47// number of seconds in a normal year (no leap day)
48#define SECS_PER_YEAR (SECS_PER_DAY * 365ll)
49// number of seconds in a leap year
50#define SECS_PER_LEAP_YEAR (SECS_PER_YEAR + SECS_PER_DAY)
51
52#define MICROSECS_PER_SEC 1000000ll
53#define MICROSECS_PER_MINUTE (MICROSECS_PER_SEC * 60)
54#define MICROSECS_PER_HOUR (MICROSECS_PER_MINUTE * 60)
55// number of microseconds in an average day (no DST = 24h)
56#define MICROSECS_PER_AVG_DAY (MICROSECS_PER_HOUR * 24)
57// number of microseconds in a maximum month (31 days)
58#define MICROSECS_PER_MAX_MONTH (MICROSECS_PER_HOUR * 24 * 31)
59// number of microseconds in an average year (365 days)
60#define MICROSECS_PER_AVG_YEAR (MICROSECS_PER_AVG_DAY * 365)
61
62// number of seconds from 1970-01-01 to 2000-01-01, 30 years with 7 leap days: 1972, 1976, 1980, 1984, 1988, 1992, 1996
63#define SECS_TO_2K (SECS_PER_YEAR * 30 + SECS_PER_DAY * 7ll)
64
65// number of seconds from 1970-01-01 to 2000-03-01, with 8 leap days: 1972, 1976, 1980, 1984, 1988, 1992, 1996, 2000
66#define SECS_TO_2KLD (SECS_PER_YEAR * 30 + SECS_PER_DAY * (7ll + 60ll))
67
68// there are 97 leap days every 400 years
69#define SECS_IN_400_YEARS (SECS_PER_YEAR * 400 + SECS_PER_DAY * 97ll)
70// there are 24 leap days every 100 years
71#define SECS_IN_100_YEARS (SECS_PER_YEAR * 100 + SECS_PER_DAY * 24ll)
72// there is 1 leap day every 4 years
73#define SECS_IN_4_YEARS (SECS_PER_YEAR * 4 + SECS_PER_DAY)
74
75// second offset in year for start of leap day (either 03-01 or 02-29)
76#define LEAPDAY_OFFSET (SECS_PER_DAY * 59)
77
78#define SECS_AFTER_LD (SECS_PER_DAY * 306)
79
80template <typename T1, typename T2>
81DLLLOCAL void normalize_units(T1& bigger, T2& smaller, int ratio) {
82 if (smaller <= -ratio || smaller >= ratio) {
83 int64 units = smaller / ratio;
84 bigger += (T1)units;
85 smaller -= (T2)(units * ratio);
86 }
87
88 // perform further sign normalization; ensure signs are the same
89 if (bigger > 0) {
90 if (smaller < 0) {
91 smaller += ratio;
92 --bigger;
93 }
94 } else if (bigger < 0 && smaller > 0) {
95 smaller -= ratio;
96 ++bigger;
97 }
98}
99
100// normalize so that the smaller units are always positive
101template <typename T1, typename T2>
102DLLLOCAL void normalize_units2(T1& bigger, T2& smaller, int ratio) {
103 if (smaller <= -ratio || smaller >= ratio) {
104 int64 units = smaller / ratio;
105 bigger += (T1)units;
106 smaller -= (T2)(units * ratio);
107 }
108
109 // perform further sign normalization
110 if (smaller < 0) {
111 smaller += ratio;
112 --bigger;
113 }
114}
115
116// normalize with second unsigned
117template <typename T1>
118DLLLOCAL void normalize_units3(T1& bigger, unsigned& smaller, unsigned ratio) {
119 if (smaller >= ratio) {
120 int64 units = smaller / ratio;
121 bigger += units;
122 smaller -= (int)(units * ratio);
123 }
124}
125
126hashdecl qore_date_info {
127 // static constants
128 DLLLOCAL static const int month_lengths[];
129 // for calculating the days passed in a year
130 DLLLOCAL static const int positive_months[];
131 DLLLOCAL static const int negative_months[];
132
133 DLLLOCAL static bool isLeapYear(int year);
134
135 // returns the year and the positive number of seconds from the beginning
136 // of the year (even for dates before 1970)
137 // we calculate the based on an offset from a known date, 2000-03-01,
138 // because the leap day calculations are regular from that point, as
139 // this date marks the start of a 400-year cycle, being right after the
140 // last leap day of the previous 400-year cycle
141 DLLLOCAL static void get_epoch_year(int64 &epoch, int& year, bool& ly) {
142 // get second offset from 2000-03-01
143 epoch -= SECS_TO_2KLD;
144
145 // how many 400-year periods are we off of 2000-03-01
146 int64 mult = epoch / SECS_IN_400_YEARS;
147 // remaining seconds
148 epoch %= SECS_IN_400_YEARS;
149
150 // if year is an even multiple of 400
151 if (!epoch) {
152 epoch = LEAPDAY_OFFSET + SECS_PER_DAY;
153 year = (int)(mult * 400 + 2000);
154 ly = true;
155 return;
156 }
157
158 // make sure second offset is positive
159 if (epoch < 0) {
160 --mult;
161 epoch += SECS_IN_400_YEARS;
162 }
163
164 // year offset
165 int yo = 0;
166
167 // get the number of 100-year remaining periods (24 leap days each)
168 int64 d = epoch / SECS_IN_100_YEARS;
169 if (d) {
170 // there can be max 3 100-year periods
171 // if the time is in the extra leap day for the 400=year cycle,
172 // then 4 could be returned
173 if (d == 4)
174 d = 3;
175 epoch -= d * SECS_IN_100_YEARS;
176 yo = (int)(100 * d);
177 }
178
179 //printd(5, "qore_date_info::get_epoch_year() after 100: epoch: %d (%d from %d) year base: %d\n", epoch, d, SECS_IN_100_YEARS, mult * 400 + 2000 + yo);
180
181 // get the number of 4-year periods remaining (1 leap day each)
182 d = epoch / SECS_IN_4_YEARS;
183 if (d) {
184 epoch %= SECS_IN_4_YEARS;
185 yo += d * 4;
186 }
187
188 // target date/time is in a leap year if the second offset from the 4-year period
189 // is less than the number of seconds after a leap day
190 // or greater than the number of seconds in 4 regular years
191 ly = epoch < SECS_AFTER_LD || epoch >= (SECS_PER_YEAR * 4);
192
193 //printd(5, "qore_date_info::get_epoch_year() after 4: epoch: %d (%d from %d) year base: %d (ily: %d)\n", epoch, d, SECS_IN_4_YEARS, mult * 400 + 2000 + yo, ly);
194
195 // get the number of 1-year periods
196 d = epoch / SECS_PER_YEAR;
197 if (d) {
198 // maximum of 3 years
199 if (d == 4)
200 d = 3;
201 epoch -= d * SECS_PER_YEAR;
202 yo += d;
203 }
204
205 year = (int)(mult * 400 + 2000 + yo);
206
207 //printd(5, "qore_date_info::get_epoch_year() after 1: epoch: %d (%d from %d) year base: %d\n", epoch, d, SECS_PER_YEAR, year);
208
209 // check if we are in the current year or the next and align with year start
210 // r is currently the offset from YEAR-03-01
211 if (epoch >= SECS_AFTER_LD) {
212 ++year;
213 epoch -= SECS_AFTER_LD;
214 } else {
215 // move offset start of current year
216 epoch += LEAPDAY_OFFSET;
217 if (ly)
218 epoch += SECS_PER_DAY;
219 }
220
221 //printd(5, "qore_date_info::get_epoch_year() after adj: epoch: %d year: %d\n", epoch, year);
222 }
223
224 // number of leap days from 1970-01-01Z to a certain month and year
225 DLLLOCAL static int leap_days_from_epoch(int year, int month) {
226 assert(month > 0 && month < 13);
227 // 1968-02-29 was the 478th leap day from year 0 assuming a proleptic gregorian calendar
228 int d;
229 if (year >= 1970) {
230 d = year/4 - year/100 + year/400 - 477;
231 if (month < 3 && isLeapYear(year))
232 --d;
233 } else {
234 --year;
235 d = year/4 - year/100 + year/400 - 477;
236 if (year < 0)
237 --d;
238 // first leap year before 1970 is 1968
239 // adjust for negative leap days
240 if (month > 2 && isLeapYear(year + 1))
241 ++d;
242 }
243
244 return d;
245 }
246
247 DLLLOCAL static int getLastDayOfMonth(int month, int year) {
248 assert(month > 0 && month < 13);
249 if (month != 2)
250 return qore_date_info::month_lengths[month];
251 return qore_date_info::isLeapYear(year) ? 29 : 28;
252 }
253
254 DLLLOCAL static int getDayOfWeek(int year, int month, int day) {
255 assert(month > 0 && month < 13);
256 int a = (14 - month) / 12;
257 int y = year - a;
258 int m = month + 12 * a - 2;
259 return (day + y + y / 4 - y / 100 + y / 400 + (31 * m / 12)) % 7;
260 }
261
262 // assumes UTC, returns seconds from 1970-01-01Z
263 DLLLOCAL static int64 getEpochSeconds(int year, int month, int day) {
264 //printd(5, "qore_date_info::getEpochSeconds(year: %d, month: %d, day: %d) leap days from epoch: %d\n", year, month, day, leap_days_from_epoch(year, month));
265 if (month < 1)
266 month = 1;
267 else if (month > 12)
268 month = 12;
269 if (day < 1)
270 day = 1;
271
272 // calculate seconds
273 int64 epoch = (year - 1970) * SECS_PER_YEAR + (positive_months[month - 1] + day - 1
274 + leap_days_from_epoch(year, month)) * SECS_PER_DAY;
275
276 //printd(5, "qore_date_info::getEpochSeconds(year: %d, month: %d, day: %d) epoch: %lld "
277 // "(leap days from epoch: %d)\n", year, month, day, epoch, leap_days_from_epoch(year, month));
278 return epoch;
279 }
280
281 // assumes UTC, returns seconds from 1970-01-01Z
282 DLLLOCAL static int64 getEpochSeconds(int year, int month, int day, int hour, int minute, int second) {
283 int64 secs = getEpochSeconds(year, month, day);
284
285 return secs
286 + (int64)hour * 3600
287 + (int64)minute * 60
288 + (int64)second;
289 }
290
291 DLLLOCAL static int getDayNumber(int year, int month, int day) {
292 return positive_months[(month < 13 ? month : 12) - 1] + day
293 + (month > 2 && qore_date_info::isLeapYear(year) ? 1 : 0);
294 }
295
296 // get month number (0 starting) by its 3 char abbrevation
297 // Or return -1 if the month is not found
298 DLLLOCAL static int getMonthIxFromAbbr(const char* abbr);
299};
300
301// normalize the given date to the last day of the month
302DLLLOCAL void normalize_dm(int& year, int& month, int& day);
303
304// normalize to the correct day, month, and year
305DLLLOCAL void normalize_day(int& year, int& month, int& day);
306
307class qore_relative_time;
308
309DLLLOCAL extern const char *STATIC_UTC;
310
311hashdecl qore_simple_tm {
312protected:
313
314public:
315 int year; // year
316 int month; // month
317 int day; // day
318 int hour; // hours
319 int minute; // minutes
320 int second; // seconds
321 int us; // microseconds
322
323 DLLLOCAL void zero() {
324 year = 0;
325 month = 0;
326 day = 0;
327 hour = 0;
328 minute = 0;
329 second = 0;
330 us = 0;
331 }
332
333 DLLLOCAL void set(int n_year, int n_month, int n_day, int n_hour, int n_minute, int n_second, int n_us) {
334 year = n_year;
335 month = n_month;
336 day = n_day;
337 hour = n_hour;
338 minute = n_minute;
339 second = n_second;
340 us = n_us;
341 }
342
343 // cannot use printd in this function as it is also called when outputting debugging messages
344 DLLLOCAL void set(int64 seconds, unsigned my_us) {
345 normalize_units3<int64>(seconds, my_us, 1000000);
346 us = my_us;
347
348 // leap year flag
349 bool ly;
350
351 //printf("qore_simple_tm::set(seconds: %lld, my_us: %d)\n", seconds, my_us);
352 qore_date_info::get_epoch_year(seconds, year, ly);
353
354 //printf("qore_simple_tm::set() seconds: %lld year: %d (day: %lld, new secs: %lld)\n", seconds, year,
355 // seconds / 86400, seconds % 86400);
356
357 day = (int)(seconds / SECS_PER_DAY);
358 seconds %= SECS_PER_DAY;
359
360 for (month = 1; month < 12; ++month) {
361 int ml = qore_date_info::month_lengths[month];
362 if (ly && month == 2)
363 ml = 29;
364
365 if (ml > day)
366 break;
367
368 day -= ml;
369 }
370
371 ++day;
372
373 second = (int)seconds;
374 hour = second / SECS_PER_HOUR;
375 second %= SECS_PER_HOUR;
376 minute = second / SECS_PER_MINUTE;
377 second %= SECS_PER_MINUTE;
378
379 //printf("qore_simple_tm::set() %04d-%02d-%02d %02d:%02d:%02d.%06d\n", year, month, day, hour, minute, second, us);
380 }
381
382 DLLLOCAL bool hasValue() const {
383 return year || month || day || hour || minute || second || us;
384 }
385};
386
387// for time info
388hashdecl qore_time_info : public qore_simple_tm {
389 const char* zname;
390 int utcoffset;
391 bool isdst;
392 const AbstractQoreZoneInfo* zone;
393
394 DLLLOCAL void set(int64 epoch, unsigned n_us, int n_utcoffset, bool n_isdst, const char* n_zname,
395 const AbstractQoreZoneInfo* n_zone) {
396 zname = n_zname ? n_zname : STATIC_UTC;
397 utcoffset = n_utcoffset;
398 isdst = n_isdst;
399 zone = n_zone;
400 //printf("qore_time_info::set(epoch: %lld n_us: %d n_utcoffset: %d n_isdst: %d, n_zname: %s, n_zone: %p)\n",
401 // epoch, n_us, n_utcoffset, n_isdst, n_zname, n_zone);
402 qore_simple_tm::set(epoch + utcoffset, n_us);
403 }
404
405 DLLLOCAL qore_time_info& operator=(const qore_simple_tm& t) {
406 zname = STATIC_UTC;
407 utcoffset = 0;
408 isdst = false;
409 zone = 0;
410 year = t.year;
411 month = t.month;
412 day = t.day;
413 hour = t.hour;
414 minute = t.minute;
415 second = t.second;
416 us = t.us;
417
418 return *this;
419 }
420
421 DLLLOCAL void copyTo(qore_tm& info) {
422 info.year = year;
423 info.month = month;
424 info.day = day;
425 info.hour = hour;
426 info.minute = minute;
427 info.second = second;
428 info.us = us;
429 info.zone_name = zname;
430 info.utc_secs_east = utcoffset;
431 info.dst = isdst;
432 info.zone = zone;
433 }
434};
435
436// with constructors, for use with absolute dates
437hashdecl qore_simple_tm2 : public qore_simple_tm {
438 DLLLOCAL qore_simple_tm2() {
439 }
440 DLLLOCAL qore_simple_tm2(int n_year, int n_month, int n_day, int n_hour, int n_minute, int n_second, int n_us) {
441 set(year, month, day, hour, minute, second, us);
442 }
443 DLLLOCAL qore_simple_tm2(int64 secs, unsigned my_us) {
444 set(secs, my_us);
445 }
446 DLLLOCAL void setLiteral(int64 date, int usecs) {
447 //printd(5, "qore_simple_tm2::setLiteral(date: %lld, usecs: %d)\n", date, usecs);
448
449 year = (int)(date / 10000000000ll);
450 date -= year* 10000000000ll;
451 month = (int)(date / 100000000ll);
452 date -= month * 100000000ll;
453 day = (int)(date / 1000000ll);
454 date -= day * 1000000ll;
455 hour = (int)(date / 10000ll);
456 date -= hour * 10000ll;
457 minute = (int)(date / 100ll);
458 second = (int)(date - minute* 100ll);
459 us = usecs;
460
461 normalize_units2<int, int>(second, us, 1000000);
462 normalize_units2<int, int>(minute, second, 60);
463 normalize_units2<int, int>(hour, minute, 60);
464 normalize_units2<int, int>(day, hour, 24);
465
466 // adjust month and year
467 if (month > 12) {
468 --month;
469 normalize_units2<int, int>(year, month, 12);
470 ++month;
471 } else if (!month)
472 month = 1;
473
474 if (!day)
475 day = 1;
476
477 // now normalize day
478 normalize_day(year, month, day);
479
480 //printd(5, "qore_simple_tm2::setLiteral() %04d-%02d-%02d %02d:%02d:%02d.%06d\n", year, month, day, hour,
481 // minute, second, us);
482 }
483 DLLLOCAL void getISOWeek(int& yr, int& week, int& wday) const;
484};
485
486DLLLOCAL void concatOffset(int utcoffset, QoreString& str);
487
488class qore_absolute_time {
489 friend class qore_relative_time;
490protected:
491 int64 epoch; // offset in seconds from the epoch (1970-01-01Z)
492 unsigned us; // microseconds
493 const AbstractQoreZoneInfo* zone; // time zone region
494
495 // epoch is set to local time; needs to be converted to UTC
496 DLLLOCAL void setLocalIntern(int n_us) {
497 // normalize units in case us > 1000000 or < 0
498 normalize_units2<int64, int>(epoch, n_us, 1000000);
499 us = n_us;
500
501 // get standard time UTC offset
502 int off = AbstractQoreZoneInfo::getUTCOffset(zone);
503
504 printd(5, "qore_absolute_time::setLocalIntern() epoch: %lld -> %lld (std off: %d)\n", epoch, epoch - off, off);
505 epoch -= off;
506
507 // now get actual UTC offset
508 int aoff = AbstractQoreZoneInfo::getUTCOffset(zone, epoch);
509 if (aoff != off) {
510 printd(5, "qore_absolute_time::setLocalIntern() epoch: %lld -> %lld (aoff: %d diff: %d)\n", epoch,
511 epoch - (aoff - off), aoff, aoff - off);
512 epoch -= (aoff - off);
513 }
514
515 printd(5, "qore_absolute_time::setLocalIntern() epoch: %lld zone: %s\n", epoch,
516 AbstractQoreZoneInfo::getRegionName(zone));
517 }
518
519 DLLLOCAL void setTM(qore_simple_tm2& tm, struct tm& tms, bool dst = false) const {
520 tms.tm_year = tm.year - 1900;
521 tms.tm_mon = tm.month - 1;
522 tms.tm_mday = tm.day;
523 tms.tm_hour = tm.hour;
524 tms.tm_min = tm.minute;
525 tms.tm_sec = tm.second;
526 tms.tm_isdst = 0;
527 tms.tm_wday = qore_date_info::getDayOfWeek(tm.year, tm.month, tm.day);
528 tms.tm_yday = qore_date_info::getDayNumber(tm.year, tm.month, tm.day) - 1;
529 tms.tm_isdst = dst;
530 }
531
532 DLLLOCAL void setNowIntern() {
533 epoch = q_epoch_us((int&)us);
534 }
535
536public:
537 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, const QoreValue v);
538
539 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, int64 n_epoch, int n_us) {
540 zone = n_zone;
541 epoch = n_epoch;
542 normalize_units2<int64, int>(epoch, n_us, 1000000);
543 us = n_us;
544 }
545
546 DLLLOCAL void set(double f, const AbstractQoreZoneInfo* n_zone = currentTZ()) {
547 zone = n_zone;
548 epoch = (int64)f;
549 us = (int)((f - (float)((int)f)) * 1000000);
550 }
551
552 DLLLOCAL void setLocal(const AbstractQoreZoneInfo* n_zone, int64 n_epoch, int n_us) {
553 epoch = n_epoch;
554 zone = n_zone;
555 normalize_units2<int64, int>(epoch, n_us, 1000000);
556 setLocalIntern(n_us);
557 }
558
559 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, int year, int month, int day, int hour, int minute,
560 int second, int n_us) {
561 zone = n_zone;
562 epoch = qore_date_info::getEpochSeconds(year, month, day, hour, minute, second);
563
564 setLocalIntern(n_us);
565
566 //printd(5, "qore_absolute_time::set(zone: %p (%s) %04d-%02d-%02d %02d:%02d:%02d.%06d) epoch: %lld\n", zone,
567 // AbstractQoreZoneInfo::getRegionName(zone), year, month, day, hour, minute, second, n_us, epoch);
568 }
569
570 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, int year, int month, int day, int hour, int minute,
571 int second, int n_us, ExceptionSink* xsink) {
572 zone = n_zone;
573
574 epoch = qore_date_info::getEpochSeconds(year, month, day, hour, minute, second);
575
576 setLocalIntern(n_us);
577
578 // check input
579 if (month < 1 || month > 12) {
580 xsink->raiseException("INVALID-DATE", "invalid month value: %d; expecting 1 - 12 inclusive", month);
581 return;
582 }
583 if (day < 1) {
584 xsink->raiseException("INVALID-DATE", "invalid day value: %d; day must be > 0", day);
585 return;
586 }
587 if (day > 28) {
588 int dom = qore_date_info::getLastDayOfMonth(month, year);
589 if (day > dom) {
590 xsink->raiseException("INVALID-DATE", "invalid day of the month: %d; %04d-%02 has %d days", day, year,
591 month, dom);
592 return;
593 }
594 }
595 if (hour < 0 || hour > 23) {
596 xsink->raiseException("INVALID-DATE", "invalid hour value: %d; expecting 0 - 23 inclusive", hour);
597 return;
598 }
599 if (minute < 0 || minute > 60) {
600 xsink->raiseException("INVALID-DATE", "invalid minute value: %d; expecting 0 - 60 inclusive", minute);
601 return;
602 }
603 if (second < 0 || second > 60) {
604 xsink->raiseException("INVALID-DATE", "invalid second value: %d; expecting 0 - 60 inclusive", second);
605 return;
606 }
607 if (n_us < 0 || n_us > 999999) {
608 xsink->raiseException("INVALID-DATE", "invalid microsecond value: %d; expecting 0 - 999999 inclusive", n_us);
609 return;
610 }
611
612 //printd(5, "qore_absolute_time::set(zone: %p (%s) %04d-%02d-%02d %02d:%02d:%02d.%06d) epoch: %lld\n", zone,
613 // AbstractQoreZoneInfo::getRegionName(zone), year, month, day, hour, minute, second, n_us, epoch);
614 }
615
616 DLLLOCAL void set(const qore_absolute_time& p) {
617 epoch = p.epoch;
618 us = p.us;
619 zone = p.zone;
620 }
621
622 DLLLOCAL void set(const char* str, const AbstractQoreZoneInfo* n_zone = currentTZ(), ExceptionSink* xsink = 0);
623
624 DLLLOCAL void setZone(const AbstractQoreZoneInfo* n_zone) {
625 zone = n_zone;
626 }
627
628 DLLLOCAL void setTime(int h, int m, int s, int usecs) {
629 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
630 //printd(5, "qore_absolute_time::setTime(h: %d, m: %d, s: %d, usecs: %d) %04d-%02d-%02d\n", h, m, s, usecs,
631 // tm.year, tm.month, tm.day);
632
633 normalize_units2<int, int>(s, usecs, 1000000);
634 normalize_units2<int, int>(m, s, 60);
635 normalize_units2<int, int>(h, m, 60);
636
637 if (h < 0)
638 h = 0;
639 else if (h > 23)
640 h = 23;
641
642 epoch = qore_date_info::getEpochSeconds(tm.year, tm.month, tm.day, h, m, s);
643 setLocalIntern(usecs);
644 }
645
646 DLLLOCAL void setLiteral(int64 date, int usecs = 0) {
647 // reset time zone to current time zone
648 zone = currentTZ();
649
650 // get broken down date from literal representation
651 qore_simple_tm2 tm;
652 tm.setLiteral(date, usecs);
653
654 // set local time from date
655 epoch = qore_date_info::getEpochSeconds(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
656 //printd(5, "qore_absolute_date::setLiteral(date: %lld, usecs: %d) epoch: %lld %04d-%02d-%02d "
657 // "%02d:%02d:%02d\n", date, usecs, epoch, tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
658 setLocalIntern(usecs);
659 }
660
661 DLLLOCAL void setNow() {
662 // reset time zone to current time zone
663 zone = currentTZ();
664 setNowIntern();
665 }
666
667 DLLLOCAL void setNow(const AbstractQoreZoneInfo* n_zone) {
668 zone = n_zone;
669 setNowIntern();
670 }
671
672 DLLLOCAL void getISOWeek(int& yr, int& week, int& wday) const {
673 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
674 tm.getISOWeek(yr, week, wday);
675 }
676
677 DLLLOCAL void get(qore_time_info& info) const {
678 const char* zname;
679 bool isdst;
680 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
681 //printf("qore_absolute_time::get() epoch: %lld UTC offset: %d isdst: %d zname: %s\n", epoch, offset, isdst, zname);
682 info.set(epoch, us, offset, isdst, zname, zone);
683 }
684
685 DLLLOCAL void get(const AbstractQoreZoneInfo* z, qore_time_info& info) const {
686 const char* zname;
687 bool isdst;
688 int offset = AbstractQoreZoneInfo::getUTCOffset(z, epoch, isdst, zname);
689 info.set(epoch, us, offset, isdst, zname, zone);
690 }
691
692 DLLLOCAL void getDate(qore_simple_tm& tm) const {
693 int off = AbstractQoreZoneInfo::getUTCOffset(zone, epoch);
694 tm.set(epoch + off, us);
695 }
696
697 DLLLOCAL short getYear() const {
698 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
699 return tm.year;
700 }
701
702 DLLLOCAL int getMonth() const {
703 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
704 return tm.month;
705 }
706
707 DLLLOCAL int getDay() const {
708 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
709 return tm.day;
710 }
711
712 DLLLOCAL int getHour() const {
713 if (epoch >= 0)
714 return (int)(((epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch)) % SECS_PER_DAY) / SECS_PER_HOUR);
715
716 qore_time_info info;
717 const char* zname;
718 bool isdst;
719 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
720 info.set(epoch, us, offset, isdst, zname, zone);
721 return info.hour;
722 }
723
724 DLLLOCAL int getMinute() const {
725 if (epoch >= 0)
726 return (int)(((epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch)) % SECS_PER_HOUR) / SECS_PER_MINUTE);
727
728 qore_time_info info;
729 const char* zname;
730 bool isdst;
731 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
732 info.set(epoch, us, offset, isdst, zname, zone);
733 return info.minute;
734 }
735
736 DLLLOCAL int getSecond() const {
737 if (epoch >= 0)
738 return ((epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch)) % SECS_PER_MINUTE);
739
740 qore_time_info info;
741 const char* zname;
742 bool isdst;
743 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
744 info.set(epoch, us, offset, isdst, zname, zone);
745 return info.second;
746 }
747
748 DLLLOCAL int getMillisecond() const {
749 return us / 1000;
750 }
751
752 DLLLOCAL int getMicrosecond() const {
753 return us;
754 }
755
756 DLLLOCAL int64 getRelativeSeconds() const {
757 return getRelativeMicroseconds() / 1000000;
758 }
759
760 DLLLOCAL int64 getRelativeMilliseconds() const {
761 return getRelativeMicroseconds() / 1000;
762 }
763
764 DLLLOCAL int64 getRelativeMicroseconds() const;
765
766 DLLLOCAL double getRelativeSecondsDouble() const {
767 return ((double)getRelativeMicroseconds()) / 1000000.0;
768 }
769
770 DLLLOCAL void localtime(struct tm& tms) const {
771 bool isdst;
772 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst);
773 qore_simple_tm2 tm(epoch + offset, us);
774
775 setTM(tm, tms, isdst);
776 }
777
778 DLLLOCAL void gmtime(struct tm& tms) const {
779 qore_simple_tm2 tm(epoch, us);
780 setTM(tm, tms, false);
781 }
782
783 DLLLOCAL int compare(const qore_absolute_time& r) const {
784 if (epoch > r.epoch)
785 return 1;
786 if (epoch < r.epoch)
787 return -1;
788 if (us > r.us)
789 return 1;
790 if (us < r.us)
791 return -1;
792 return 0;
793 }
794
795 DLLLOCAL int getDayOfWeek() const {
796 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
797 return qore_date_info::getDayOfWeek(tm.year, tm.month, tm.day);
798 }
799
800 DLLLOCAL int getDayNumber() const {
801 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
802 return qore_date_info::getDayNumber(tm.year, tm.month, tm.day);
803 }
804
805 DLLLOCAL bool hasValue() const {
806 return epoch || us ? true : false;
807 }
808
809 DLLLOCAL int64 getEpochSeconds() const {
810 return epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch);
811 }
812
813 DLLLOCAL int64 getEpochMilliseconds() const {
814 return getEpochSeconds() * 1000 + (us / 1000);
815 }
816
817 DLLLOCAL int64 getEpochMicroseconds() const {
818 return getEpochSeconds() * 1000000 + us;
819 }
820
821 DLLLOCAL int64 getEpochSecondsUTC() const {
822 return epoch;
823 }
824
825 DLLLOCAL int64 getEpochMicrosecondsUTC() const {
826 return epoch * 1000000 + us;
827 }
828
829 DLLLOCAL int64 getEpochMillisecondsUTC() const {
830 return epoch * 1000 + (us / 1000);
831 }
832
833 DLLLOCAL qore_absolute_time& operator+=(const qore_relative_time& dt);
834 DLLLOCAL qore_absolute_time& operator-=(const qore_relative_time& dt);
835
836 DLLLOCAL void getAsString(QoreString& str) const;
837
838 DLLLOCAL void unaryMinus() {
839 epoch = -epoch;
840 us = -us;
841 }
842
843 DLLLOCAL const AbstractQoreZoneInfo* getZone() const {
844 return zone;
845 }
846
847 DLLLOCAL void addSecondsTo(int64 secs, int n_us = 0) {
848 set(zone, epoch + secs, us + n_us);
849 }
850};
851
852class qore_relative_time : public qore_simple_tm {
853friend class qore_absolute_time;
854protected:
855 DLLLOCAL void normalize(bool for_comparison = false) {
856 //printd(5, "DT:cD() sec: %lld ms: %d\n", sec, ms);
857
858 // normalize seconds from microseconds
859 normalize_units<int, int>(second, us, 1000000);
860
861 // normalize minutes from seconds
862 normalize_units<int, int>(minute, second, 60);
863
864 // normalize hours from minutes
865 normalize_units<int, int>(hour, minute, 60);
866
867 // only normalize hours to days and days to months if we are comparing
868 // we use an average year length of 365 days and an maximum month length of 31 days
869 if (for_comparison) {
870 normalize_units<int, int>(day, hour, 24);
871 normalize_units<int, int>(year, day, 365);
872 normalize_units<int, int>(month, day, 31);
873 }
874
875 // normalize years from months
876 normalize_units<int, int>(year, month, 12);
877 }
878
879 DLLLOCAL void setIso8601(const char* str);
880
881public:
882 DLLLOCAL void set(int n_year, int n_month, int n_day, int n_hour, int n_minute, int n_second, int n_us) {
883 qore_simple_tm::set(n_year, n_month, n_day, n_hour, n_minute, n_second, n_us);
884 normalize();
885 }
886
887 DLLLOCAL void set(const QoreValue v);
888
889 DLLLOCAL void set(const char* str);
890
891 DLLLOCAL void set(const qore_relative_time& p) {
892 year = p.year;
893 month = p.month;
894 day = p.day;
895 hour = p.hour;
896 minute = p.minute;
897 second = p.second;
898 us = p.us;
899 }
900
901 // takes the different between seconds.micros - dt and sets this to the relative date/time difference
902 DLLLOCAL void setDifference(int64 seconds, int micros, const qore_absolute_time& dt) {
903 int64 sec = seconds - dt.epoch;
904 us = micros - dt.us;
905
906 year = month = day = hour = minute = 0;
907
908 // normalize seconds from microseconds
909 normalize_units<int64, int>(sec, us, 1000000);
910
911 // do not normalize days, as with DST not all days are 24 hours
912
913 // normalize hours from seconds
914 normalize_units<int, int64>(hour, sec, 3600);
915
916 // normalize minutes from seconds
917 normalize_units<int, int64>(minute, sec, 60);
918
919 second = (int)sec;
920 }
921
922 DLLLOCAL void setLiteral(int64 date, int usecs = 0) {
923 year = (int)(date / 10000000000ll);
924 date -= year* 10000000000ll;
925 month = (int)(date / 100000000ll);
926 date -= month * 100000000ll;
927 day = (int)(date / 1000000ll);
928 date -= day * 1000000ll;
929 hour = (int)(date / 10000ll);
930 date -= hour * 10000ll;
931 minute = (int)(date / 100ll);
932 second = (int)(date - minute* 100ll);
933 us = usecs;
934
935 normalize();
936 }
937
938 DLLLOCAL void addFractionalYear(double d) {
939 d *= 365.0;
940 int dy = (int)d;
941 day += dy;
942 addFractionalDay(d - dy);
943 }
944
945 // this does not make sense because a month does not have a fixed number of days, but we use an approximation of 30 days in a month
946 DLLLOCAL void addFractionalMonth(double d) {
947 d *= 30.0;
948 int dy = (int)d;
949 day += dy;
950 addFractionalDay(d - dy);
951 }
952
953 DLLLOCAL void addFractionalDay(double d) {
954 d *= 24.0;
955 int h = (int)d;
956 hour += h;
957 addFractionalHour(d - h);
958 }
959
960 DLLLOCAL void addFractionalHour(double d) {
961 d *= 60.0;
962 int m = (int)d;
963 minute += m;
964 addFractionalMinute(d - m);
965 }
966
967 DLLLOCAL void addFractionalMinute(double d) {
968 d *= 60.0;
969 int s = (int)d;
970 second += s;
971 addFractionalSecond(d - s);
972 }
973
974 DLLLOCAL void addFractionalSecond(double d) {
975 d *= 1000000.0;
976 us += d;
977 }
978
979 DLLLOCAL void setSeconds(int64 s, int usecs = 0) {
980 year = 0;
981 month = 0;
982 day = 0;
983 hour = s / 3600;
984 if (hour)
985 s -= hour * 3600;
986 minute = s / 60;
987 if (minute)
988 s -= minute * 60;
989 second = s;
990 us = usecs;
991 }
992
993 DLLLOCAL void setTime(int h, int m, int s, int usecs) {
994 hour = h;
995 minute = m;
996 second = s;
997 us = usecs;
998 }
999
1000 DLLLOCAL short getYear() const {
1001 return year;
1002 }
1003
1004 DLLLOCAL int getMonth() const {
1005 return month;
1006 }
1007
1008 DLLLOCAL int getDay() const {
1009 return day;
1010 }
1011
1012 DLLLOCAL int getHour() const {
1013 return hour;
1014 }
1015
1016 DLLLOCAL int getMinute() const {
1017 return minute;
1018 }
1019
1020 DLLLOCAL int getSecond() const {
1021 return second;
1022 }
1023
1024 DLLLOCAL int getMillisecond() const {
1025 return us / 1000;
1026 }
1027
1028 DLLLOCAL int getMicrosecond() const {
1029 return us;
1030 }
1031
1032 DLLLOCAL int compare(const qore_relative_time& rt) const {
1033 // compare normalized values
1034 qore_relative_time l;
1035 l.set(year, month, day, hour, minute, second, us);
1036 l.normalize(true);
1037 qore_relative_time r;
1038 r.set(rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second, rt.us);
1039 r.normalize(true);
1040
1041 if (l.year > r.year)
1042 return 1;
1043 if (l.year < r.year)
1044 return -1;
1045 if (l.month > r.month)
1046 return 1;
1047 if (l.month < r.month)
1048 return -1;
1049 if (l.day > r.day)
1050 return 1;
1051 if (l.day < r.day)
1052 return -1;
1053 if (l.hour > r.hour)
1054 return 1;
1055 if (l.hour < r.hour)
1056 return -1;
1057 if (l.minute > r.minute)
1058 return 1;
1059 if (l.minute < r.minute)
1060 return -1;
1061 if (l.second > r.second)
1062 return 1;
1063 if (l.second < r.second)
1064 return -1;
1065 if (l.us > r.us)
1066 return 1;
1067 if (l.us < r.us)
1068 return -1;
1069 return 0;
1070 }
1071
1072 DLLLOCAL void unaryMinus() {
1073 year = -year;
1074 month = -month;
1075 day = -day;
1076 hour = -hour;
1077 minute = -minute;
1078 second = -second;
1079 us = -us;
1080 }
1081
1082 DLLLOCAL int64 getRelativeSeconds() const {
1083 return getRelativeMicroseconds() / 1000000;
1084 }
1085
1086 DLLLOCAL int64 getRelativeMilliseconds() const {
1087 return getRelativeMicroseconds() / 1000;
1088 }
1089
1090 DLLLOCAL int64 getRelativeMicroseconds() const {
1091 return (int64)us + (int64)second * MICROSECS_PER_SEC
1092 + (int64)minute* MICROSECS_PER_MINUTE
1093 + (int64)hour * MICROSECS_PER_HOUR
1094 + (int64)day * MICROSECS_PER_AVG_DAY
1095 + (month ? (int64)month * MICROSECS_PER_MAX_MONTH : 0ll)
1096 + (year ? (int64)year * MICROSECS_PER_AVG_YEAR : 0ll);
1097 }
1098
1099 DLLLOCAL double getRelativeSecondsDouble() const {
1100 return ((double)getRelativeMicroseconds()) / 1000000.0;
1101 }
1102
1103 DLLLOCAL qore_relative_time& operator+=(const qore_relative_time& dt);
1104 DLLLOCAL qore_relative_time& operator-=(const qore_relative_time& dt);
1105 DLLLOCAL qore_relative_time& operator-=(const qore_absolute_time& dt);
1106
1107 DLLLOCAL void getAsString(QoreString& str) const {
1108 int f = 0;
1109 str.concat("<time:");
1110
1111#define PL(n) (n == 1 ? "" : "s")
1112
1113 if (year)
1114 str.sprintf(" %d year%s", year, PL(year)), f++;
1115 if (month)
1116 str.sprintf(" %d month%s", month, PL(month)), f++;
1117 if (day)
1118 str.sprintf(" %d day%s", day, PL(day)), f++;
1119 if (hour)
1120 str.sprintf(" %d hour%s", hour, PL(hour)), f++;
1121 if (minute)
1122 str.sprintf(" %d minute%s", minute, PL(minute)), f++;
1123 if (second || (!f && !us))
1124 str.sprintf(" %d second%s", second, PL(second));
1125
1126 if (us) {
1127 int ms = us / 1000;
1128 if (ms * 1000 == us)
1129 str.sprintf(" %d millisecond%s", ms, PL(ms));
1130 else
1131 str.sprintf(" %d microsecond%s", us, PL(us));
1132 }
1133
1134#undef PL
1135
1136 str.concat('>');
1137 }
1138
1139 DLLLOCAL void getTM(struct tm& tms) const {
1140 tms.tm_year = year;
1141 tms.tm_mon = month;
1142 tms.tm_mday = day;
1143 tms.tm_hour = hour;
1144 tms.tm_min = minute;
1145 tms.tm_sec = second;
1146 tms.tm_wday = 0;
1147 tms.tm_yday = 0;
1148 tms.tm_isdst = -1;
1149 }
1150
1151 DLLLOCAL void get(qore_time_info& info) const {
1152 info = *this;
1153
1154 info.zname = 0;
1155 info.utcoffset = 0;
1156 info.isdst = false;
1157 info.zone = 0;
1158 }
1159
1160 DLLLOCAL void zero() {
1161 qore_simple_tm::zero();
1162 }
1163
1164 DLLLOCAL bool hasValue() const {
1165 return qore_simple_tm::hasValue();
1166 }
1167
1168 DLLLOCAL void addSecondsTo(double secs) {
1169 addSecondsTo((int64)secs, (int)((secs - (float)((int)secs)) * 1000000));
1170 }
1171
1172 DLLLOCAL void addSecondsTo(int64 secs, int n_us = 0) {
1173 int h = secs / 3600;
1174 if (h)
1175 secs -= (h * 3600);
1176 int m = secs / 60;
1177 if (m)
1178 secs -= (m * 60);
1179
1180 hour += h;
1181 minute += m;
1182 second += secs;
1183 us += n_us;
1184 }
1185};
1186
1187static inline void zero_tm(struct tm& tms) {
1188 tms.tm_year = 70;
1189 tms.tm_mon = 0;
1190 tms.tm_mday = 1;
1191 tms.tm_hour = 0;
1192 tms.tm_min = 0;
1193 tms.tm_sec = 0;
1194 tms.tm_isdst = 0;
1195 tms.tm_wday = 0;
1196 tms.tm_yday = 0;
1197 tms.tm_isdst = -1;
1198}
1199
1200class qore_date_private {
1201friend class qore_absolute_time;
1202friend class qore_relative_time;
1203
1204protected:
1205 // actual data is held in the following union
1206 // unfortunately the original API was designed such that the object must be
1207 // able to change from absolute to relative, so we have a union
1208 union {
1209 qore_absolute_time abs;
1210 qore_relative_time rel;
1211 } d;
1212 bool relative;
1213
1214public:
1215 DLLLOCAL qore_date_private(bool r = false) : relative(r) {
1216 if (r)
1217 d.rel.zero();
1218 else
1219 d.abs.set(currentTZ(), 0, 0);
1220 }
1221
1222 DLLLOCAL qore_date_private(const AbstractQoreZoneInfo* zone, const QoreValue v) : relative(false) {
1223 d.abs.set(zone, v);
1224 }
1225
1226 DLLLOCAL qore_date_private(const AbstractQoreZoneInfo* zone, int64 seconds, int us = 0) : relative(false) {
1227 d.abs.set(zone, seconds, us);
1228 }
1229
1230 DLLLOCAL qore_date_private(const AbstractQoreZoneInfo* zone, int y, int mo, int dy, int h, int mi, int s, int us) : relative(false) {
1231 d.abs.set(zone, y, mo, dy, h, mi, s, us);
1232 }
1233
1234 DLLLOCAL qore_date_private(const AbstractQoreZoneInfo* zone, int y, int mo, int dy, int h, int mi, int s, int us, ExceptionSink* xsink) : relative(false) {
1235 d.abs.set(zone, y, mo, dy, h, mi, s, us, xsink);
1236 }
1237
1238 DLLLOCAL qore_date_private(const QoreValue v) : relative(true) {
1239 d.rel.set(v);
1240 }
1241
1242 // this constructor assumes local time
1243 DLLLOCAL qore_date_private(int y, int mo, int dy, int h, int mi, int s, int us, bool r) : relative(r) {
1244 if (r)
1245 d.rel.set(y, mo, dy, h, mi, s, us);
1246 else
1247 d.abs.set(currentTZ(), y, mo, dy, h, mi, s, us);
1248 }
1249
1250 DLLLOCAL static int compare(const qore_date_private& left, const qore_date_private& right) {
1251 // absolute dates are always larger than relative dates, no matter the value
1252 if (left.relative)
1253 return right.relative ? left.d.rel.compare(right.d.rel) : -1;
1254
1255 return right.relative ? 1 : left.d.abs.compare(right.d.abs);
1256 }
1257
1258 DLLLOCAL qore_date_private& operator=(const qore_date_private& p) {
1259 if (p.relative)
1260 d.rel.set(p.d.rel);
1261 else
1262 d.abs.set(p.d.abs);
1263
1264 relative = p.relative;
1265 return *this;
1266 }
1267
1268 DLLLOCAL void setNow() {
1269 relative = false;
1270 d.abs.setNow();
1271 }
1272
1273 DLLLOCAL void setNow(const AbstractQoreZoneInfo* n_zone) {
1274 relative = false;
1275 d.abs.setNow(n_zone);
1276 }
1277
1278 DLLLOCAL void setDate(const qore_date_private& p) {
1279 *this = p;
1280 }
1281
1282 // assumes local time zone
1283 DLLLOCAL void setDate(const struct tm& tms, int us) {
1284 relative = false;
1285
1286 d.abs.set(currentTZ(), 1900 + tms.tm_year, tms.tm_mon + 1, tms.tm_mday, tms.tm_hour, tms.tm_min, tms.tm_sec, us);
1287 }
1288
1289 DLLLOCAL void setAbsoluteDate(const char* str, const AbstractQoreZoneInfo* zone = currentTZ(), ExceptionSink* xsink = 0);
1290 DLLLOCAL void setRelativeDate(const char* str);
1291
1292 DLLLOCAL void setDate(const char* str);
1293 DLLLOCAL void setDate(const char* str, ExceptionSink* xsink);
1294
1295 DLLLOCAL bool isRelative() const {
1296 return relative;
1297 }
1298
1299 DLLLOCAL void setZone(const AbstractQoreZoneInfo* n_zone) {
1300 if (!relative)
1301 d.abs.setZone(n_zone);
1302 }
1303
1304 DLLLOCAL short getYear() const {
1305 return relative ? d.rel.getYear() : d.abs.getYear();
1306 }
1307
1308 DLLLOCAL int getMonth() const {
1309 return relative ? d.rel.getMonth() : d.abs.getMonth();
1310 }
1311
1312 DLLLOCAL int getDay() const {
1313 return relative ? d.rel.getDay() : d.abs.getDay();
1314 }
1315
1316 DLLLOCAL int getHour() const {
1317 return relative ? d.rel.getHour() : d.abs.getHour();
1318 }
1319
1320 DLLLOCAL int getMinute() const {
1321 return relative ? d.rel.getMinute() : d.abs.getMinute();
1322 }
1323
1324 DLLLOCAL int getSecond() const {
1325 return relative ? d.rel.getSecond() : d.abs.getSecond();
1326 }
1327
1328 DLLLOCAL int getMillisecond() const {
1329 return relative ? d.rel.getMillisecond() : d.abs.getMillisecond();
1330 }
1331
1332 DLLLOCAL int getMicrosecond() const {
1333 return relative ? d.rel.getMicrosecond() : d.abs.getMicrosecond();
1334 }
1335
1336 DLLLOCAL bool hasValue() const {
1337 return relative ? d.rel.hasValue() : d.abs.hasValue();
1338 }
1339
1340 DLLLOCAL int64 getEpochSeconds() const {
1341 return relative ? d.rel.getRelativeSeconds() : d.abs.getEpochSeconds();
1342 }
1343
1344 DLLLOCAL int64 getEpochSecondsUTC() const {
1345 return relative ? d.rel.getRelativeSeconds() : d.abs.getEpochSecondsUTC();
1346 }
1347
1348 DLLLOCAL int64 getEpochMillisecondsUTC() const {
1349 return relative ? d.rel.getRelativeMilliseconds() : d.abs.getEpochMillisecondsUTC();
1350 }
1351
1352 DLLLOCAL int64 getEpochMicrosecondsUTC() const {
1353 return relative ? d.rel.getRelativeMicroseconds() : d.abs.getEpochMicrosecondsUTC();
1354 }
1355
1356 DLLLOCAL int getDayNumber() const {
1357 return relative ? 0 : d.abs.getDayNumber();
1358 }
1359
1360 // it's not legal to call with this=relative and dt=absolute
1361 DLLLOCAL void add(const qore_date_private& dt) {
1362 if (!relative) {
1363 if (dt.relative) {
1364 d.abs += dt.d.rel;
1365 } else {
1366 setDate(getEpochSecondsUTC() + dt.d.abs.getEpochSecondsUTC(), d.abs.getMicrosecond()
1367 + dt.d.abs.getMicrosecond());
1368 }
1369 return;
1370 }
1371
1372 assert(dt.relative);
1373 d.rel += dt.d.rel;
1374 }
1375
1376 DLLLOCAL void unaryMinus() {
1377 if (relative)
1378 d.rel.unaryMinus();
1379 else
1380 d.abs.unaryMinus();
1381 }
1382
1383 // it's not legal to call with this=relative and dt=absolute
1384 DLLLOCAL void subtractBy(const qore_date_private& dt) {
1385 if (!relative) {
1386 if (dt.relative)
1387 d.abs -= dt.d.rel;
1388 else {
1389 int64 secs = d.abs.getEpochSecondsUTC();
1390 int us = d.abs.getMicrosecond();
1391 relative = true;
1392 d.rel.setDifference(secs, us, dt.d.abs);
1393 }
1394 return;
1395 }
1396
1397 if (dt.relative)
1398 d.rel -= dt.d.rel;
1399 else
1400 d.rel -= dt.d.abs;
1401 }
1402
1403 DLLLOCAL void addSecondsTo(int64 secs, int us) {
1404 if (!relative)
1405 d.abs.addSecondsTo(secs, us);
1406 else
1407 d.rel.addSecondsTo(secs, us);
1408 }
1409
1410 DLLLOCAL void setTime(int h, int m, int s, int us) {
1411 if (relative)
1412 d.rel.setTime(h, m, s, us);
1413 else
1414 d.abs.setTime(h, m, s, us);
1415 }
1416
1417 DLLLOCAL void setDate(const AbstractQoreZoneInfo* n_zone, int year, int month, int day, int hour, int minute,
1418 int second, int n_us) {
1419 relative = false;
1420 d.abs.set(n_zone, year, month, day, hour, minute, second, n_us);
1421 }
1422
1423 DLLLOCAL void setDate(const AbstractQoreZoneInfo* zone, int64 seconds, int us = 0) {
1424 relative = false;
1425 d.abs.set(zone, seconds, us);
1426 }
1427
1428 DLLLOCAL void setDate(int64 seconds, int us = 0) {
1429 relative = false;
1430 d.abs.set(currentTZ(), seconds, us);
1431 }
1432
1433 DLLLOCAL void setLocalDate(int64 seconds, int us) {
1434 relative = false;
1435 d.abs.setLocal(currentTZ(), seconds, us);
1436 }
1437
1438 DLLLOCAL void setLocalDate(const AbstractQoreZoneInfo* zone, int64 seconds, int us) {
1439 relative = false;
1440 d.abs.setLocal(zone, seconds, us);
1441 }
1442
1443 DLLLOCAL void setDateLiteral(int64 date, int us = 0) {
1444 relative = false;
1445 d.abs.setLiteral(date, us);
1446 }
1447
1448 DLLLOCAL void setRelativeDateLiteral(int64 date, int us = 0) {
1449 relative = true;
1450 d.rel.setLiteral(date, us);
1451 }
1452
1453 DLLLOCAL void setRelativeDateSeconds(int64 s, int us = 0) {
1454 relative = true;
1455 d.rel.setSeconds(s, us);
1456 }
1457
1458 DLLLOCAL int64 getRelativeSeconds() const {
1459 return relative ? d.rel.getRelativeSeconds() : d.abs.getRelativeSeconds();
1460 }
1461
1462 DLLLOCAL int64 getRelativeMilliseconds() const {
1463 return relative ? d.rel.getRelativeMilliseconds() : d.abs.getRelativeMilliseconds();
1464 }
1465
1466 DLLLOCAL int64 getRelativeMicroseconds() const {
1467 return relative ? d.rel.getRelativeMicroseconds() : d.abs.getRelativeMicroseconds();
1468 }
1469
1470 DLLLOCAL double getRelativeSecondsDouble() const {
1471 return relative ? d.rel.getRelativeSecondsDouble() : d.abs.getRelativeSecondsDouble();
1472 }
1473
1474 DLLLOCAL int getDayOfWeek() const {
1475 return relative ? 0 : d.abs.getDayOfWeek();
1476 }
1477
1478 DLLLOCAL void getISOWeek(int& yr, int& week, int& wday) const {
1479 if (relative) {
1480 yr = 1970;
1481 week = wday = 1;
1482 return;
1483 }
1484 return d.abs.getISOWeek(yr, week, wday);
1485 }
1486
1487 DLLLOCAL bool isEqual(const qore_date_private& dt) const {
1488 return !compare(*this, dt);
1489 }
1490
1491 DLLLOCAL void localtime(struct tm& tms) const {
1492 if (relative)
1493 d.rel.getTM(tms);
1494 else
1495 d.abs.localtime(tms);
1496 }
1497
1498 DLLLOCAL void gmtime(struct tm& tms) const {
1499 if (relative) {
1500 zero_tm(tms);
1501 return;
1502 }
1503 d.abs.gmtime(tms);
1504 }
1505
1506 DLLLOCAL void get(qore_time_info& info) const {
1507 if (relative)
1508 d.rel.get(info);
1509 else
1510 d.abs.get(info);
1511 }
1512
1513 DLLLOCAL void get(const AbstractQoreZoneInfo* zone, qore_time_info& info) const {
1514 if (relative)
1515 d.rel.get(info);
1516 else
1517 d.abs.get(zone, info);
1518 }
1519
1520 DLLLOCAL void format(QoreString& str, const char* fmt) const;
1521
1522 DLLLOCAL void getAsString(QoreString& str) const {
1523 if (!relative)
1524 d.abs.getAsString(str);
1525 else
1526 d.rel.getAsString(str);
1527 }
1528
1529 // note that ISO-8601 week days go from 1 - 7 = Mon - Sun
1530 // return value: 0 = an exception was raised, not 0 = OK
1531 DLLLOCAL static qore_date_private* getDateFromISOWeek(qore_date_private& result, int year, int week, int day,
1532 ExceptionSink* xsink) {
1533 if (week <= 0) {
1534 xsink->raiseException("ISO-8601-INVALID-WEEK", "week numbers must be positive (value passed: %d)", week);
1535 return nullptr;
1536 }
1537
1538 // get day of week of jan 1 of this year
1539 int jan1 = qore_date_info::getDayOfWeek(year, 1, 1);
1540
1541 if (week > 52) {
1542 // get maximum week number in this year
1543 int mw = 52 + ((jan1 == 4 && !qore_date_info::isLeapYear(year))
1544 || (jan1 == 3 && qore_date_info::isLeapYear(year)));
1545 if (week > mw) {
1546 xsink->raiseException("ISO-8601-INVALID-WEEK", "there are only %d calendar weeks in year %d (week "
1547 "value passed: %d)", mw, year, week);
1548 return nullptr;
1549 }
1550 }
1551
1552 if (day < 1 || day > 7) {
1553 xsink->raiseException("ISO-8601-INVALID-DAY", "calendar week days must be between 1 and 7 for Mon - Sun "
1554 "(day value passed: %d)", day);
1555 return nullptr;
1556 }
1557
1558 // get year, month, day for start of iso-8601 calendar year
1559 int y, m, d;
1560 // if jan1 is mon, then the iso-8601 year starts with the normal year
1561 if (jan1 == 1) {
1562 y = year;
1563 m = 1;
1564 d = 1;
1565 }
1566 // if jan1 is tue - thurs, iso-8601 year starts in dec of previous real year
1567 else if (jan1 > 1 && jan1 < 5) {
1568 y = year - 1;
1569 m = 12;
1570 d = 33 - jan1;
1571 } else {
1572 y = year;
1573 m = 1;
1574 // jan1 is fri or saturday
1575 if (jan1)
1576 d = 9 - jan1;
1577 else // jan1 is sunday
1578 d = 2;
1579 }
1580
1581 // get seconds for date of start of iso-8601 calendar year, add seconds for day offset and create new time
1582 result.setLocalDate(qore_date_info::getEpochSeconds(y, m, d) + ((week - 1) * 7 + (day - 1)) * 86400, 0);
1583 return nullptr;
1584 }
1585
1586 DLLLOCAL const AbstractQoreZoneInfo* getZone() const {
1587 return relative ? 0 : d.abs.getZone();
1588 }
1589};
1590
1591#endif
DLLEXPORT int64 q_epoch_us(int &us)
returns the seconds and microseconds from the epoch
container for holding Qore-language exception information and also for registering a "thread_exit" ca...
Definition: ExceptionSink.h:50
DLLEXPORT AbstractQoreNode * raiseException(const char *err, const char *fmt,...)
appends a Qore-language exception to the list
Qore's string type supported by the QoreEncoding class.
Definition: QoreString.h:93
DLLEXPORT void concat(const QoreString *str, ExceptionSink *xsink)
concatenates a string and converts encodings if necessary
DLLEXPORT int sprintf(const char *fmt,...)
this will concatentate a formatted string to the existing string according to the format string and t...
long long int64
64bit integer type, cannot use int64_t here since it breaks the API on some 64-bit systems due to equ...
Definition: common.h:260
DLLEXPORT const AbstractQoreZoneInfo * currentTZ()
returns the current local time zone, note that if 0 = UTC
The main value class in Qore, designed to be passed by value.
Definition: QoreValue.h:276
for returning broken-down time information
Definition: DateTime.h:41