Qore Programming Language 2.1.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 - 2024 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, bool allow_z = false);
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,
505 off);
506 epoch -= off;
507
508 // now get actual UTC offset
509 int aoff = AbstractQoreZoneInfo::getUTCOffset(zone, epoch);
510 if (aoff != off) {
511 printd(5, "qore_absolute_time::setLocalIntern() epoch: %lld -> %lld (aoff: %d diff: %d)\n", epoch,
512 epoch - (aoff - off), aoff, aoff - off);
513 epoch -= (aoff - off);
514 }
515
516 printd(5, "qore_absolute_time::setLocalIntern() epoch: %lld zone: %s\n", epoch,
517 AbstractQoreZoneInfo::getRegionName(zone));
518 }
519
520 DLLLOCAL void setTM(qore_simple_tm2& tm, struct tm& tms, bool dst = false) const {
521 tms.tm_year = tm.year - 1900;
522 tms.tm_mon = tm.month - 1;
523 tms.tm_mday = tm.day;
524 tms.tm_hour = tm.hour;
525 tms.tm_min = tm.minute;
526 tms.tm_sec = tm.second;
527 tms.tm_isdst = 0;
528 tms.tm_wday = qore_date_info::getDayOfWeek(tm.year, tm.month, tm.day);
529 tms.tm_yday = qore_date_info::getDayNumber(tm.year, tm.month, tm.day) - 1;
530 tms.tm_isdst = dst;
531 }
532
533 DLLLOCAL void setNowIntern() {
534 epoch = q_epoch_us((int&)us);
535 }
536
537public:
538 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, const QoreValue v);
539
540 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, int64 n_epoch, int n_us) {
541 zone = n_zone;
542 epoch = n_epoch;
543 normalize_units2<int64, int>(epoch, n_us, 1000000);
544 us = n_us;
545 }
546
547 DLLLOCAL void set(double f, const AbstractQoreZoneInfo* n_zone = currentTZ()) {
548 zone = n_zone;
549 epoch = (int64)f;
550 us = (int)((f - (float)((int)f)) * 1000000);
551 }
552
553 DLLLOCAL void setLocal(const AbstractQoreZoneInfo* n_zone, int64 n_epoch, int n_us) {
554 epoch = n_epoch;
555 zone = n_zone;
556 normalize_units2<int64, int>(epoch, n_us, 1000000);
557 setLocalIntern(n_us);
558 }
559
560 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, int year, int month, int day, int hour, int minute,
561 int second, int n_us) {
562 zone = n_zone;
563 epoch = qore_date_info::getEpochSeconds(year, month, day, hour, minute, second);
564
565 setLocalIntern(n_us);
566
567 //printd(5, "qore_absolute_time::set(zone: %p (%s) %04d-%02d-%02d %02d:%02d:%02d.%06d) epoch: %lld\n", zone,
568 // AbstractQoreZoneInfo::getRegionName(zone), year, month, day, hour, minute, second, n_us, epoch);
569 }
570
571 DLLLOCAL void set(const AbstractQoreZoneInfo* n_zone, int year, int month, int day, int hour, int minute,
572 int second, int n_us, ExceptionSink* xsink) {
573 zone = n_zone;
574
575 epoch = qore_date_info::getEpochSeconds(year, month, day, hour, minute, second);
576
577 setLocalIntern(n_us);
578
579 // check input
580 if (month < 1 || month > 12) {
581 xsink->raiseException("INVALID-DATE", "invalid month value: %d; expecting 1 - 12 inclusive", month);
582 return;
583 }
584 if (day < 1) {
585 xsink->raiseException("INVALID-DATE", "invalid day value: %d; day must be > 0", day);
586 return;
587 }
588 if (day > 28) {
589 int dom = qore_date_info::getLastDayOfMonth(month, year);
590 if (day > dom) {
591 xsink->raiseException("INVALID-DATE", "invalid day of the month: %d; %04d-%02 has %d days", day, year,
592 month, dom);
593 return;
594 }
595 }
596 if (hour < 0 || hour > 23) {
597 xsink->raiseException("INVALID-DATE", "invalid hour value: %d; expecting 0 - 23 inclusive", hour);
598 return;
599 }
600 if (minute < 0 || minute > 60) {
601 xsink->raiseException("INVALID-DATE", "invalid minute value: %d; expecting 0 - 60 inclusive", minute);
602 return;
603 }
604 if (second < 0 || second > 60) {
605 xsink->raiseException("INVALID-DATE", "invalid second value: %d; expecting 0 - 60 inclusive", second);
606 return;
607 }
608 if (n_us < 0 || n_us > 999999) {
609 xsink->raiseException("INVALID-DATE", "invalid microsecond value: %d; expecting 0 - 999999 inclusive", n_us);
610 return;
611 }
612
613 //printd(5, "qore_absolute_time::set(zone: %p (%s) %04d-%02d-%02d %02d:%02d:%02d.%06d) epoch: %lld\n", zone,
614 // AbstractQoreZoneInfo::getRegionName(zone), year, month, day, hour, minute, second, n_us, epoch);
615 }
616
617 DLLLOCAL void set(const qore_absolute_time& p) {
618 epoch = p.epoch;
619 us = p.us;
620 zone = p.zone;
621 }
622
623 DLLLOCAL void set(const char* str, const AbstractQoreZoneInfo* n_zone = currentTZ(), ExceptionSink* xsink = 0);
624
625 DLLLOCAL void setZone(const AbstractQoreZoneInfo* n_zone) {
626 zone = n_zone;
627 }
628
629 DLLLOCAL void setTime(int h, int m, int s, int usecs) {
630 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
631 //printd(5, "qore_absolute_time::setTime(h: %d, m: %d, s: %d, usecs: %d) %04d-%02d-%02d\n", h, m, s, usecs,
632 // tm.year, tm.month, tm.day);
633
634 normalize_units2<int, int>(s, usecs, 1000000);
635 normalize_units2<int, int>(m, s, 60);
636 normalize_units2<int, int>(h, m, 60);
637
638 if (h < 0)
639 h = 0;
640 else if (h > 23)
641 h = 23;
642
643 epoch = qore_date_info::getEpochSeconds(tm.year, tm.month, tm.day, h, m, s);
644 setLocalIntern(usecs);
645 }
646
647 DLLLOCAL void setLiteral(int64 date, int usecs = 0) {
648 // reset time zone to current time zone
649 zone = currentTZ();
650
651 // get broken down date from literal representation
652 qore_simple_tm2 tm;
653 tm.setLiteral(date, usecs);
654
655 // set local time from date
656 epoch = qore_date_info::getEpochSeconds(tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
657 //printd(5, "qore_absolute_date::setLiteral(date: %lld, usecs: %d) epoch: %lld %04d-%02d-%02d "
658 // "%02d:%02d:%02d\n", date, usecs, epoch, tm.year, tm.month, tm.day, tm.hour, tm.minute, tm.second);
659 setLocalIntern(usecs);
660 }
661
662 DLLLOCAL void setNow() {
663 // reset time zone to current time zone
664 zone = currentTZ();
665 setNowIntern();
666 }
667
668 DLLLOCAL void setNow(const AbstractQoreZoneInfo* n_zone) {
669 zone = n_zone;
670 setNowIntern();
671 }
672
673 DLLLOCAL void getISOWeek(int& yr, int& week, int& wday) const {
674 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
675 tm.getISOWeek(yr, week, wday);
676 }
677
678 DLLLOCAL void get(qore_time_info& info) const {
679 const char* zname;
680 bool isdst;
681 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
682 //printf("qore_absolute_time::get() epoch: %lld UTC offset: %d isdst: %d zname: %s\n", epoch, offset, isdst, zname);
683 info.set(epoch, us, offset, isdst, zname, zone);
684 }
685
686 DLLLOCAL void get(const AbstractQoreZoneInfo* z, qore_time_info& info) const {
687 const char* zname;
688 bool isdst;
689 int offset = AbstractQoreZoneInfo::getUTCOffset(z, epoch, isdst, zname);
690 info.set(epoch, us, offset, isdst, zname, zone);
691 }
692
693 DLLLOCAL void getDate(qore_simple_tm& tm) const {
694 int off = AbstractQoreZoneInfo::getUTCOffset(zone, epoch);
695 tm.set(epoch + off, us);
696 }
697
698 DLLLOCAL short getYear() const {
699 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
700 return tm.year;
701 }
702
703 DLLLOCAL int getMonth() const {
704 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
705 return tm.month;
706 }
707
708 DLLLOCAL int getDay() const {
709 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
710 return tm.day;
711 }
712
713 DLLLOCAL int getHour() const {
714 if (epoch >= 0)
715 return (int)(((epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch)) % SECS_PER_DAY) / SECS_PER_HOUR);
716
717 qore_time_info info;
718 const char* zname;
719 bool isdst;
720 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
721 info.set(epoch, us, offset, isdst, zname, zone);
722 return info.hour;
723 }
724
725 DLLLOCAL int getMinute() const {
726 if (epoch >= 0)
727 return (int)(((epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch)) % SECS_PER_HOUR) / SECS_PER_MINUTE);
728
729 qore_time_info info;
730 const char* zname;
731 bool isdst;
732 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
733 info.set(epoch, us, offset, isdst, zname, zone);
734 return info.minute;
735 }
736
737 DLLLOCAL int getSecond() const {
738 if (epoch >= 0)
739 return ((epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch)) % SECS_PER_MINUTE);
740
741 qore_time_info info;
742 const char* zname;
743 bool isdst;
744 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst, zname);
745 info.set(epoch, us, offset, isdst, zname, zone);
746 return info.second;
747 }
748
749 DLLLOCAL int getMillisecond() const {
750 return us / 1000;
751 }
752
753 DLLLOCAL int getMicrosecond() const {
754 return us;
755 }
756
757 DLLLOCAL int64 getRelativeSeconds() const {
758 return getRelativeMicroseconds() / 1000000;
759 }
760
761 DLLLOCAL int64 getRelativeMilliseconds() const {
762 return getRelativeMicroseconds() / 1000;
763 }
764
765 DLLLOCAL int64 getRelativeMicroseconds() const;
766
767 DLLLOCAL double getRelativeSecondsDouble() const {
768 return ((double)getRelativeMicroseconds()) / 1000000.0;
769 }
770
771 DLLLOCAL void localtime(struct tm& tms) const {
772 bool isdst;
773 int offset = AbstractQoreZoneInfo::getUTCOffset(zone, epoch, isdst);
774 qore_simple_tm2 tm(epoch + offset, us);
775
776 setTM(tm, tms, isdst);
777 }
778
779 DLLLOCAL void gmtime(struct tm& tms) const {
780 qore_simple_tm2 tm(epoch, us);
781 setTM(tm, tms, false);
782 }
783
784 DLLLOCAL int compare(const qore_absolute_time& r) const {
785 if (epoch > r.epoch)
786 return 1;
787 if (epoch < r.epoch)
788 return -1;
789 if (us > r.us)
790 return 1;
791 if (us < r.us)
792 return -1;
793 return 0;
794 }
795
796 DLLLOCAL int getDayOfWeek() const {
797 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
798 return qore_date_info::getDayOfWeek(tm.year, tm.month, tm.day);
799 }
800
801 DLLLOCAL int getDayNumber() const {
802 qore_simple_tm2 tm(epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch), us);
803 return qore_date_info::getDayNumber(tm.year, tm.month, tm.day);
804 }
805
806 DLLLOCAL bool hasValue() const {
807 return epoch || us ? true : false;
808 }
809
810 DLLLOCAL int64 getEpochSeconds() const {
811 return epoch + AbstractQoreZoneInfo::getUTCOffset(zone, epoch);
812 }
813
814 DLLLOCAL int64 getEpochMilliseconds() const {
815 return getEpochSeconds() * 1000 + (us / 1000);
816 }
817
818 DLLLOCAL int64 getEpochMicroseconds() const {
819 return getEpochSeconds() * 1000000 + us;
820 }
821
822 DLLLOCAL int64 getEpochSecondsUTC() const {
823 return epoch;
824 }
825
826 DLLLOCAL int64 getEpochMicrosecondsUTC() const {
827 return epoch * 1000000 + us;
828 }
829
830 DLLLOCAL int64 getEpochMillisecondsUTC() const {
831 return epoch * 1000 + (us / 1000);
832 }
833
834 DLLLOCAL qore_absolute_time& operator+=(const qore_relative_time& dt);
835 DLLLOCAL qore_absolute_time& operator-=(const qore_relative_time& dt);
836
837 DLLLOCAL void getAsString(QoreString& str) const;
838
839 DLLLOCAL void unaryMinus() {
840 epoch = -epoch;
841 us = -us;
842 }
843
844 DLLLOCAL const AbstractQoreZoneInfo* getZone() const {
845 return zone;
846 }
847
848 DLLLOCAL void addSecondsTo(int64 secs, int n_us = 0) {
849 set(zone, epoch + secs, us + n_us);
850 }
851};
852
853class qore_relative_time : public qore_simple_tm {
854friend class qore_absolute_time;
855protected:
856 DLLLOCAL void normalize(bool for_comparison = false) {
857 //printd(5, "DT:cD() sec: %lld ms: %d\n", sec, ms);
858
859 // normalize seconds from microseconds
860 normalize_units<int, int>(second, us, 1000000);
861
862 // normalize minutes from seconds
863 normalize_units<int, int>(minute, second, 60);
864
865 // normalize hours from minutes
866 normalize_units<int, int>(hour, minute, 60);
867
868 // only normalize hours to days and days to months if we are comparing
869 // we use an average year length of 365 days and an maximum month length of 31 days
870 if (for_comparison) {
871 normalize_units<int, int>(day, hour, 24);
872 normalize_units<int, int>(year, day, 365);
873 normalize_units<int, int>(month, day, 31);
874 }
875
876 // normalize years from months
877 normalize_units<int, int>(year, month, 12);
878 }
879
880 DLLLOCAL void setIso8601(const char* str);
881
882public:
883 DLLLOCAL void set(int n_year, int n_month, int n_day, int n_hour, int n_minute, int n_second, int n_us) {
884 qore_simple_tm::set(n_year, n_month, n_day, n_hour, n_minute, n_second, n_us);
885 normalize();
886 }
887
888 DLLLOCAL void set(const QoreValue v);
889
890 DLLLOCAL void set(const char* str);
891
892 DLLLOCAL void set(const qore_relative_time& p) {
893 year = p.year;
894 month = p.month;
895 day = p.day;
896 hour = p.hour;
897 minute = p.minute;
898 second = p.second;
899 us = p.us;
900 }
901
902 // takes the different between seconds.micros - dt and sets this to the relative date/time difference
903 DLLLOCAL void setDifference(int64 seconds, int micros, const qore_absolute_time& dt) {
904 int64 sec = seconds - dt.epoch;
905 us = micros - dt.us;
906
907 year = month = day = hour = minute = 0;
908
909 // normalize seconds from microseconds
910 normalize_units<int64, int>(sec, us, 1000000);
911
912 // do not normalize days, as with DST not all days are 24 hours
913
914 // normalize hours from seconds
915 normalize_units<int, int64>(hour, sec, 3600);
916
917 // normalize minutes from seconds
918 normalize_units<int, int64>(minute, sec, 60);
919
920 second = (int)sec;
921 }
922
923 DLLLOCAL void setLiteral(int64 date, int usecs = 0) {
924 year = (int)(date / 10000000000ll);
925 date -= year* 10000000000ll;
926 month = (int)(date / 100000000ll);
927 date -= month * 100000000ll;
928 day = (int)(date / 1000000ll);
929 date -= day * 1000000ll;
930 hour = (int)(date / 10000ll);
931 date -= hour * 10000ll;
932 minute = (int)(date / 100ll);
933 second = (int)(date - minute* 100ll);
934 us = usecs;
935
936 normalize();
937 }
938
939 DLLLOCAL void addFractionalYear(double d) {
940 d *= 365.0;
941 int dy = (int)d;
942 day += dy;
943 addFractionalDay(d - dy);
944 }
945
946 // 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
947 DLLLOCAL void addFractionalMonth(double d) {
948 d *= 30.0;
949 int dy = (int)d;
950 day += dy;
951 addFractionalDay(d - dy);
952 }
953
954 DLLLOCAL void addFractionalDay(double d) {
955 d *= 24.0;
956 int h = (int)d;
957 hour += h;
958 addFractionalHour(d - h);
959 }
960
961 DLLLOCAL void addFractionalHour(double d) {
962 d *= 60.0;
963 int m = (int)d;
964 minute += m;
965 addFractionalMinute(d - m);
966 }
967
968 DLLLOCAL void addFractionalMinute(double d) {
969 d *= 60.0;
970 int s = (int)d;
971 second += s;
972 addFractionalSecond(d - s);
973 }
974
975 DLLLOCAL void addFractionalSecond(double d) {
976 d *= 1000000.0;
977 us += d;
978 }
979
980 DLLLOCAL void setSeconds(int64 s, int usecs = 0) {
981 year = 0;
982 month = 0;
983 day = 0;
984 hour = s / 3600;
985 if (hour)
986 s -= hour * 3600;
987 minute = s / 60;
988 if (minute)
989 s -= minute * 60;
990 second = s;
991 us = usecs;
992 }
993
994 DLLLOCAL void setTime(int h, int m, int s, int usecs) {
995 hour = h;
996 minute = m;
997 second = s;
998 us = usecs;
999 }
1000
1001 DLLLOCAL short getYear() const {
1002 return year;
1003 }
1004
1005 DLLLOCAL int getMonth() const {
1006 return month;
1007 }
1008
1009 DLLLOCAL int getDay() const {
1010 return day;
1011 }
1012
1013 DLLLOCAL int getHour() const {
1014 return hour;
1015 }
1016
1017 DLLLOCAL int getMinute() const {
1018 return minute;
1019 }
1020
1021 DLLLOCAL int getSecond() const {
1022 return second;
1023 }
1024
1025 DLLLOCAL int getMillisecond() const {
1026 return us / 1000;
1027 }
1028
1029 DLLLOCAL int getMicrosecond() const {
1030 return us;
1031 }
1032
1033 DLLLOCAL int compare(const qore_relative_time& rt) const {
1034 // compare normalized values
1035 qore_relative_time l;
1036 l.set(year, month, day, hour, minute, second, us);
1037 l.normalize(true);
1038 qore_relative_time r;
1039 r.set(rt.year, rt.month, rt.day, rt.hour, rt.minute, rt.second, rt.us);
1040 r.normalize(true);
1041
1042 if (l.year > r.year)
1043 return 1;
1044 if (l.year < r.year)
1045 return -1;
1046 if (l.month > r.month)
1047 return 1;
1048 if (l.month < r.month)
1049 return -1;
1050 if (l.day > r.day)
1051 return 1;
1052 if (l.day < r.day)
1053 return -1;
1054 if (l.hour > r.hour)
1055 return 1;
1056 if (l.hour < r.hour)
1057 return -1;
1058 if (l.minute > r.minute)
1059 return 1;
1060 if (l.minute < r.minute)
1061 return -1;
1062 if (l.second > r.second)
1063 return 1;
1064 if (l.second < r.second)
1065 return -1;
1066 if (l.us > r.us)
1067 return 1;
1068 if (l.us < r.us)
1069 return -1;
1070 return 0;
1071 }
1072
1073 DLLLOCAL void unaryMinus() {
1074 year = -year;
1075 month = -month;
1076 day = -day;
1077 hour = -hour;
1078 minute = -minute;
1079 second = -second;
1080 us = -us;
1081 }
1082
1083 DLLLOCAL int64 getRelativeSeconds() const {
1084 return getRelativeMicroseconds() / 1000000;
1085 }
1086
1087 DLLLOCAL int64 getRelativeMilliseconds() const {
1088 return getRelativeMicroseconds() / 1000;
1089 }
1090
1091 DLLLOCAL int64 getRelativeMicroseconds() const {
1092 return (int64)us + (int64)second * MICROSECS_PER_SEC
1093 + (int64)minute* MICROSECS_PER_MINUTE
1094 + (int64)hour * MICROSECS_PER_HOUR
1095 + (int64)day * MICROSECS_PER_AVG_DAY
1096 + (month ? (int64)month * MICROSECS_PER_MAX_MONTH : 0ll)
1097 + (year ? (int64)year * MICROSECS_PER_AVG_YEAR : 0ll);
1098 }
1099
1100 DLLLOCAL double getRelativeSecondsDouble() const {
1101 return ((double)getRelativeMicroseconds()) / 1000000.0;
1102 }
1103
1104 DLLLOCAL qore_relative_time& operator+=(const qore_relative_time& dt);
1105 DLLLOCAL qore_relative_time& operator-=(const qore_relative_time& dt);
1106 DLLLOCAL qore_relative_time& operator-=(const qore_absolute_time& dt);
1107
1108 DLLLOCAL void getAsString(QoreString& str) const {
1109 int f = 0;
1110 str.concat("<time:");
1111
1112#define PL(n) (n == 1 ? "" : "s")
1113
1114 if (year)
1115 str.sprintf(" %d year%s", year, PL(year)), f++;
1116 if (month)
1117 str.sprintf(" %d month%s", month, PL(month)), f++;
1118 if (day)
1119 str.sprintf(" %d day%s", day, PL(day)), f++;
1120 if (hour)
1121 str.sprintf(" %d hour%s", hour, PL(hour)), f++;
1122 if (minute)
1123 str.sprintf(" %d minute%s", minute, PL(minute)), f++;
1124 if (second || (!f && !us))
1125 str.sprintf(" %d second%s", second, PL(second));
1126
1127 if (us) {
1128 int ms = us / 1000;
1129 if (ms * 1000 == us)
1130 str.sprintf(" %d millisecond%s", ms, PL(ms));
1131 else
1132 str.sprintf(" %d microsecond%s", us, PL(us));
1133 }
1134
1135#undef PL
1136
1137 str.concat('>');
1138 }
1139
1140 DLLLOCAL void getTM(struct tm& tms) const {
1141 tms.tm_year = year;
1142 tms.tm_mon = month;
1143 tms.tm_mday = day;
1144 tms.tm_hour = hour;
1145 tms.tm_min = minute;
1146 tms.tm_sec = second;
1147 tms.tm_wday = 0;
1148 tms.tm_yday = 0;
1149 tms.tm_isdst = -1;
1150 }
1151
1152 DLLLOCAL void get(qore_time_info& info) const {
1153 info = *this;
1154
1155 info.zname = 0;
1156 info.utcoffset = 0;
1157 info.isdst = false;
1158 info.zone = 0;
1159 }
1160
1161 DLLLOCAL void zero() {
1162 qore_simple_tm::zero();
1163 }
1164
1165 DLLLOCAL bool hasValue() const {
1166 return qore_simple_tm::hasValue();
1167 }
1168
1169 DLLLOCAL void addSecondsTo(double secs) {
1170 addSecondsTo((int64)secs, (int)((secs - (float)((int)secs)) * 1000000));
1171 }
1172
1173 DLLLOCAL void addSecondsTo(int64 secs, int n_us = 0) {
1174 int h = secs / 3600;
1175 if (h)
1176 secs -= (h * 3600);
1177 int m = secs / 60;
1178 if (m)
1179 secs -= (m * 60);
1180
1181 hour += h;
1182 minute += m;
1183 second += secs;
1184 us += n_us;
1185 }
1186};
1187
1188static inline void zero_tm(struct tm& tms) {
1189 tms.tm_year = 70;
1190 tms.tm_mon = 0;
1191 tms.tm_mday = 1;
1192 tms.tm_hour = 0;
1193 tms.tm_min = 0;
1194 tms.tm_sec = 0;
1195 tms.tm_isdst = 0;
1196 tms.tm_wday = 0;
1197 tms.tm_yday = 0;
1198 tms.tm_isdst = -1;
1199}
1200
1201class qore_date_private {
1202friend class qore_absolute_time;
1203friend class qore_relative_time;
1204
1205protected:
1206 // actual data is held in the following union
1207 // unfortunately the original API was designed such that the object must be
1208 // able to change from absolute to relative, so we have a union
1209 union {
1210 qore_absolute_time abs;
1211 qore_relative_time rel;
1212 } d;
1213 bool relative;
1214
1215public:
1216 DLLLOCAL qore_date_private(bool r = false) : relative(r) {
1217 if (r)
1218 d.rel.zero();
1219 else
1220 d.abs.set(currentTZ(), 0, 0);
1221 }
1222
1223 DLLLOCAL qore_date_private(const AbstractQoreZoneInfo* zone, const QoreValue v) : relative(false) {
1224 d.abs.set(zone, v);
1225 }
1226
1227 DLLLOCAL qore_date_private(const AbstractQoreZoneInfo* zone, int64 seconds, int us = 0) : relative(false) {
1228 d.abs.set(zone, seconds, us);
1229 }
1230
1231 DLLLOCAL qore_date_private(const AbstractQoreZoneInfo* zone, int y, int mo, int dy, int h, int mi, int s, int us) : relative(false) {
1232 d.abs.set(zone, y, mo, dy, h, mi, s, us);
1233 }
1234
1235 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) {
1236 d.abs.set(zone, y, mo, dy, h, mi, s, us, xsink);
1237 }
1238
1239 DLLLOCAL qore_date_private(const QoreValue v) : relative(true) {
1240 d.rel.set(v);
1241 }
1242
1243 // this constructor assumes local time
1244 DLLLOCAL qore_date_private(int y, int mo, int dy, int h, int mi, int s, int us, bool r) : relative(r) {
1245 if (r)
1246 d.rel.set(y, mo, dy, h, mi, s, us);
1247 else
1248 d.abs.set(currentTZ(), y, mo, dy, h, mi, s, us);
1249 }
1250
1251 DLLLOCAL static int compare(const qore_date_private& left, const qore_date_private& right) {
1252 // absolute dates are always larger than relative dates, no matter the value
1253 if (left.relative)
1254 return right.relative ? left.d.rel.compare(right.d.rel) : -1;
1255
1256 return right.relative ? 1 : left.d.abs.compare(right.d.abs);
1257 }
1258
1259 DLLLOCAL qore_date_private& operator=(const qore_date_private& p) {
1260 if (p.relative)
1261 d.rel.set(p.d.rel);
1262 else
1263 d.abs.set(p.d.abs);
1264
1265 relative = p.relative;
1266 return *this;
1267 }
1268
1269 DLLLOCAL void setNow() {
1270 relative = false;
1271 d.abs.setNow();
1272 }
1273
1274 DLLLOCAL void setNow(const AbstractQoreZoneInfo* n_zone) {
1275 relative = false;
1276 d.abs.setNow(n_zone);
1277 }
1278
1279 DLLLOCAL void setDate(const qore_date_private& p) {
1280 *this = p;
1281 }
1282
1283 // assumes local time zone
1284 DLLLOCAL void setDate(const struct tm& tms, int us) {
1285 relative = false;
1286
1287 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);
1288 }
1289
1290 DLLLOCAL void setAbsoluteDate(const char* str, const AbstractQoreZoneInfo* zone = currentTZ(), ExceptionSink* xsink = 0);
1291 DLLLOCAL void setRelativeDate(const char* str);
1292
1293 DLLLOCAL void setDate(const char* str);
1294 DLLLOCAL void setDate(const char* str, ExceptionSink* xsink);
1295
1296 DLLLOCAL bool isRelative() const {
1297 return relative;
1298 }
1299
1300 DLLLOCAL void setZone(const AbstractQoreZoneInfo* n_zone) {
1301 if (!relative)
1302 d.abs.setZone(n_zone);
1303 }
1304
1305 DLLLOCAL short getYear() const {
1306 return relative ? d.rel.getYear() : d.abs.getYear();
1307 }
1308
1309 DLLLOCAL int getMonth() const {
1310 return relative ? d.rel.getMonth() : d.abs.getMonth();
1311 }
1312
1313 DLLLOCAL int getDay() const {
1314 return relative ? d.rel.getDay() : d.abs.getDay();
1315 }
1316
1317 DLLLOCAL int getHour() const {
1318 return relative ? d.rel.getHour() : d.abs.getHour();
1319 }
1320
1321 DLLLOCAL int getMinute() const {
1322 return relative ? d.rel.getMinute() : d.abs.getMinute();
1323 }
1324
1325 DLLLOCAL int getSecond() const {
1326 return relative ? d.rel.getSecond() : d.abs.getSecond();
1327 }
1328
1329 DLLLOCAL int getMillisecond() const {
1330 return relative ? d.rel.getMillisecond() : d.abs.getMillisecond();
1331 }
1332
1333 DLLLOCAL int getMicrosecond() const {
1334 return relative ? d.rel.getMicrosecond() : d.abs.getMicrosecond();
1335 }
1336
1337 DLLLOCAL bool hasValue() const {
1338 return relative ? d.rel.hasValue() : d.abs.hasValue();
1339 }
1340
1341 DLLLOCAL int64 getEpochSeconds() const {
1342 return relative ? d.rel.getRelativeSeconds() : d.abs.getEpochSeconds();
1343 }
1344
1345 DLLLOCAL int64 getEpochSecondsUTC() const {
1346 return relative ? d.rel.getRelativeSeconds() : d.abs.getEpochSecondsUTC();
1347 }
1348
1349 DLLLOCAL int64 getEpochMillisecondsUTC() const {
1350 return relative ? d.rel.getRelativeMilliseconds() : d.abs.getEpochMillisecondsUTC();
1351 }
1352
1353 DLLLOCAL int64 getEpochMicrosecondsUTC() const {
1354 return relative ? d.rel.getRelativeMicroseconds() : d.abs.getEpochMicrosecondsUTC();
1355 }
1356
1357 DLLLOCAL int getDayNumber() const {
1358 return relative ? 0 : d.abs.getDayNumber();
1359 }
1360
1361 // it's not legal to call with this=relative and dt=absolute
1362 DLLLOCAL void add(const qore_date_private& dt) {
1363 if (!relative) {
1364 if (dt.relative) {
1365 d.abs += dt.d.rel;
1366 } else {
1367 setDate(getEpochSecondsUTC() + dt.d.abs.getEpochSecondsUTC(), d.abs.getMicrosecond()
1368 + dt.d.abs.getMicrosecond());
1369 }
1370 return;
1371 }
1372
1373 assert(dt.relative);
1374 d.rel += dt.d.rel;
1375 }
1376
1377 DLLLOCAL void unaryMinus() {
1378 if (relative)
1379 d.rel.unaryMinus();
1380 else
1381 d.abs.unaryMinus();
1382 }
1383
1384 // it's not legal to call with this=relative and dt=absolute
1385 DLLLOCAL void subtractBy(const qore_date_private& dt) {
1386 if (!relative) {
1387 if (dt.relative)
1388 d.abs -= dt.d.rel;
1389 else {
1390 int64 secs = d.abs.getEpochSecondsUTC();
1391 int us = d.abs.getMicrosecond();
1392 relative = true;
1393 d.rel.setDifference(secs, us, dt.d.abs);
1394 }
1395 return;
1396 }
1397
1398 if (dt.relative)
1399 d.rel -= dt.d.rel;
1400 else
1401 d.rel -= dt.d.abs;
1402 }
1403
1404 DLLLOCAL void addSecondsTo(int64 secs, int us) {
1405 if (!relative)
1406 d.abs.addSecondsTo(secs, us);
1407 else
1408 d.rel.addSecondsTo(secs, us);
1409 }
1410
1411 DLLLOCAL void setTime(int h, int m, int s, int us) {
1412 if (relative)
1413 d.rel.setTime(h, m, s, us);
1414 else
1415 d.abs.setTime(h, m, s, us);
1416 }
1417
1418 DLLLOCAL void setDate(const AbstractQoreZoneInfo* n_zone, int year, int month, int day, int hour, int minute,
1419 int second, int n_us) {
1420 relative = false;
1421 d.abs.set(n_zone, year, month, day, hour, minute, second, n_us);
1422 }
1423
1424 DLLLOCAL void setDate(const AbstractQoreZoneInfo* zone, int64 seconds, int us = 0) {
1425 relative = false;
1426 d.abs.set(zone, seconds, us);
1427 }
1428
1429 DLLLOCAL void setDate(int64 seconds, int us = 0) {
1430 relative = false;
1431 d.abs.set(currentTZ(), seconds, us);
1432 }
1433
1434 DLLLOCAL void setLocalDate(int64 seconds, int us) {
1435 relative = false;
1436 d.abs.setLocal(currentTZ(), seconds, us);
1437 }
1438
1439 DLLLOCAL void setLocalDate(const AbstractQoreZoneInfo* zone, int64 seconds, int us) {
1440 relative = false;
1441 d.abs.setLocal(zone, seconds, us);
1442 }
1443
1444 DLLLOCAL void setDateLiteral(int64 date, int us = 0) {
1445 relative = false;
1446 d.abs.setLiteral(date, us);
1447 }
1448
1449 DLLLOCAL void setRelativeDateLiteral(int64 date, int us = 0) {
1450 relative = true;
1451 d.rel.setLiteral(date, us);
1452 }
1453
1454 DLLLOCAL void setRelativeDateSeconds(int64 s, int us = 0) {
1455 relative = true;
1456 d.rel.setSeconds(s, us);
1457 }
1458
1459 DLLLOCAL int64 getRelativeSeconds() const {
1460 return relative ? d.rel.getRelativeSeconds() : d.abs.getRelativeSeconds();
1461 }
1462
1463 DLLLOCAL int64 getRelativeMilliseconds() const {
1464 return relative ? d.rel.getRelativeMilliseconds() : d.abs.getRelativeMilliseconds();
1465 }
1466
1467 DLLLOCAL int64 getRelativeMicroseconds() const {
1468 return relative ? d.rel.getRelativeMicroseconds() : d.abs.getRelativeMicroseconds();
1469 }
1470
1471 DLLLOCAL double getRelativeSecondsDouble() const {
1472 return relative ? d.rel.getRelativeSecondsDouble() : d.abs.getRelativeSecondsDouble();
1473 }
1474
1475 DLLLOCAL int getDayOfWeek() const {
1476 return relative ? 0 : d.abs.getDayOfWeek();
1477 }
1478
1479 DLLLOCAL void getISOWeek(int& yr, int& week, int& wday) const {
1480 if (relative) {
1481 yr = 1970;
1482 week = wday = 1;
1483 return;
1484 }
1485 return d.abs.getISOWeek(yr, week, wday);
1486 }
1487
1488 DLLLOCAL bool isEqual(const qore_date_private& dt) const {
1489 return !compare(*this, dt);
1490 }
1491
1492 DLLLOCAL void localtime(struct tm& tms) const {
1493 if (relative)
1494 d.rel.getTM(tms);
1495 else
1496 d.abs.localtime(tms);
1497 }
1498
1499 DLLLOCAL void gmtime(struct tm& tms) const {
1500 if (relative) {
1501 zero_tm(tms);
1502 return;
1503 }
1504 d.abs.gmtime(tms);
1505 }
1506
1507 DLLLOCAL void get(qore_time_info& info) const {
1508 if (relative)
1509 d.rel.get(info);
1510 else
1511 d.abs.get(info);
1512 }
1513
1514 DLLLOCAL void get(const AbstractQoreZoneInfo* zone, qore_time_info& info) const {
1515 if (relative)
1516 d.rel.get(info);
1517 else
1518 d.abs.get(zone, info);
1519 }
1520
1521 DLLLOCAL void format(QoreString& str, const char* fmt) const;
1522
1523 DLLLOCAL void getAsString(QoreString& str) const {
1524 if (!relative)
1525 d.abs.getAsString(str);
1526 else
1527 d.rel.getAsString(str);
1528 }
1529
1530 // note that ISO-8601 week days go from 1 - 7 = Mon - Sun
1531 // return value: 0 = an exception was raised, not 0 = OK
1532 DLLLOCAL static qore_date_private* getDateFromISOWeek(qore_date_private& result, int year, int week, int day,
1533 ExceptionSink* xsink) {
1534 if (week <= 0) {
1535 xsink->raiseException("ISO-8601-INVALID-WEEK", "week numbers must be positive (value passed: %d)", week);
1536 return nullptr;
1537 }
1538
1539 // get day of week of jan 1 of this year
1540 int jan1 = qore_date_info::getDayOfWeek(year, 1, 1);
1541
1542 if (week > 52) {
1543 // get maximum week number in this year
1544 int mw = 52 + ((jan1 == 4 && !qore_date_info::isLeapYear(year))
1545 || (jan1 == 3 && qore_date_info::isLeapYear(year)));
1546 if (week > mw) {
1547 xsink->raiseException("ISO-8601-INVALID-WEEK", "there are only %d calendar weeks in year %d (week "
1548 "value passed: %d)", mw, year, week);
1549 return nullptr;
1550 }
1551 }
1552
1553 if (day < 1 || day > 7) {
1554 xsink->raiseException("ISO-8601-INVALID-DAY", "calendar week days must be between 1 and 7 for Mon - Sun "
1555 "(day value passed: %d)", day);
1556 return nullptr;
1557 }
1558
1559 // get year, month, day for start of iso-8601 calendar year
1560 int y, m, d;
1561 // if jan1 is mon, then the iso-8601 year starts with the normal year
1562 if (jan1 == 1) {
1563 y = year;
1564 m = 1;
1565 d = 1;
1566 }
1567 // if jan1 is tue - thurs, iso-8601 year starts in dec of previous real year
1568 else if (jan1 > 1 && jan1 < 5) {
1569 y = year - 1;
1570 m = 12;
1571 d = 33 - jan1;
1572 } else {
1573 y = year;
1574 m = 1;
1575 // jan1 is fri or saturday
1576 if (jan1)
1577 d = 9 - jan1;
1578 else // jan1 is sunday
1579 d = 2;
1580 }
1581
1582 // get seconds for date of start of iso-8601 calendar year, add seconds for day offset and create new time
1583 result.setLocalDate(qore_date_info::getEpochSeconds(y, m, d) + ((week - 1) * 7 + (day - 1)) * 86400, 0);
1584 return nullptr;
1585 }
1586
1587 DLLLOCAL const AbstractQoreZoneInfo* getZone() const {
1588 return relative ? 0 : d.abs.getZone();
1589 }
1590};
1591
1592#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:266
The main value class in Qore, designed to be passed by value.
Definition QoreValue.h:279
for returning broken-down time information
Definition DateTime.h:41