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