LCOV - code coverage report
Current view: top level - gdk - gdk_time.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 448 508 88.2 %
Date: 2020-06-29 20:00:14 Functions: 47 48 97.9 %

          Line data    Source code
       1             : /*
       2             :  * This Source Code Form is subject to the terms of the Mozilla Public
       3             :  * License, v. 2.0.  If a copy of the MPL was not distributed with this
       4             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       5             :  *
       6             :  * Copyright 1997 - July 2008 CWI, August 2008 - 2020 MonetDB B.V.
       7             :  */
       8             : 
       9             : #include "monetdb_config.h"
      10             : #include "gdk.h"
      11             : #include "gdk_time.h"
      12             : 
      13             : #define YEAR_MIN                (-4712) /* 4713 BC */
      14             : 
      15             : #define YEAR_OFFSET             (-YEAR_MIN)
      16             : #define DTDAY_WIDTH             5               /* 1..28/29/30/31, depending on month/year */
      17             : #define DTDAY_SHIFT             0
      18             : #define DTMONTH_WIDTH   21              /* enough for 174761 years (and 8 months) */
      19             : #define DTMONTH_SHIFT   (DTDAY_WIDTH+DTDAY_SHIFT)
      20             : 
      21             : #define YEAR_MAX                (YEAR_MIN+(1<<DTMONTH_WIDTH)/12-1)
      22             : 
      23             : #define isdate(y, m, d) ((m) > 0 && (m) <= 12 && (d) > 0 && (y) >= YEAR_MIN && (y) <= YEAR_MAX && (d) <= monthdays(y, m))
      24             : #define mkdate(y, m, d) ((date) (((uint32_t) (((y) + YEAR_OFFSET) * 12 + (m) - 1) << DTMONTH_SHIFT) \
      25             :                                  | ((uint32_t) (d) << DTDAY_SHIFT)))
      26             : #define date_extract_day(dt)    ((int) (((uint32_t) (dt) >> DTDAY_SHIFT) & ((1 << DTDAY_WIDTH) - 1)))
      27             : #define date_extract_month(dt)  ((int) ((((uint32_t) (dt) >> DTMONTH_SHIFT) & ((1 << DTMONTH_WIDTH) - 1)) % 12 + 1))
      28             : #define date_extract_year(dt)   ((int) ((((uint32_t) (dt) >> DTMONTH_SHIFT) & ((1 << DTMONTH_WIDTH) - 1)) / 12 - YEAR_OFFSET))
      29             : 
      30             : #define istime(h,m,s,u) ((h) >= 0 && (h) < 24 && (m) >= 0 && (m) < 60 && (s) >= 0 && (s) <= 60 && (u) >= 0 && (u) < 1000000)
      31             : #define mkdaytime(h,m,s,u)      (((((daytime) (h) * 60 + (m)) * 60) + (s)) * LL_CONSTANT(1000000) + (u))
      32             : 
      33             : #define daytime_extract_hour(tm)        ((int) (tm / HOUR_USEC))
      34             : #define daytime_extract_minute(tm)      ((int) ((tm / 60000000) % 60))
      35             : #define daytime_extract_usecond(tm)     ((int) (tm % 60000000)) /* includes seconds */
      36             : 
      37             : #define TSTIME_WIDTH    37              /* [0..24*60*60*1000000) */
      38             : #define TSTIME_SHIFT    0
      39             : #define TSDATE_WIDTH    (DTDAY_WIDTH+DTMONTH_WIDTH)
      40             : #define TSDATE_SHIFT    (TSTIME_SHIFT+TSTIME_WIDTH)
      41             : #define ts_time(ts)             ((daytime) (((uint64_t) (ts) >> TSTIME_SHIFT) & ((LL_CONSTANT(1) << TSTIME_WIDTH) - 1)))
      42             : #define ts_date(ts)             ((date) (((uint64_t) (ts) >> TSDATE_SHIFT) & ((1 << TSDATE_WIDTH) - 1)))
      43             : #define mktimestamp(d, t)       ((timestamp) (((uint64_t) (d) << TSDATE_SHIFT) | \
      44             :                                               ((uint64_t) (t) << TSTIME_SHIFT)))
      45             : 
      46             : static const int leapdays[13] = { /* days per month in leap year */
      47             :         0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
      48             : };
      49             : static const int cumdays[13] = { /* cumulative days in non leap year */
      50             :         0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365
      51             : };
      52             : #define isleapyear(y)           ((y) % 4 == 0 && ((y) % 100 != 0 || (y) % 400 == 0))
      53             : #define monthdays(y, m)         (leapdays[m] - ((m) == 2 && !isleapyear(y)))
      54             : 
      55             : const timestamp unixepoch = mktimestamp(mkdate(1970, 1, 1), mkdaytime(0, 0, 0, 0));
      56             : 
      57             : date
      58      639886 : date_create(int year, int month, int day)
      59             : {
      60             :         /* note that isdate returns false if any argument is nil */
      61     1250280 :         return isdate(year, month, day) ? mkdate(year, month, day) : date_nil;
      62             : }
      63             : 
      64             : int
      65          25 : date_century(date dt)
      66             : {
      67          25 :         int yr;
      68          25 :         if (is_date_nil(dt))
      69             :                 return int_nil;
      70          24 :         yr = date_extract_year(dt);
      71          24 :         if (yr > 0)
      72          24 :                 return (yr - 1) / 100 + 1;
      73             :         else
      74           0 :                 return -((-yr - 1) / 100 + 1);
      75             : }
      76             : 
      77             : int
      78           7 : date_decade(date dt)
      79             : {
      80           7 :         if (is_date_nil(dt))
      81             :                 return int_nil;
      82           7 :         return date_extract_year(dt) / 10;
      83             : }
      84             : 
      85             : int
      86        6785 : date_year(date dt)
      87             : {
      88        6785 :         if (is_date_nil(dt))
      89             :                 return int_nil;
      90        6762 :         return date_extract_year(dt);
      91             : }
      92             : 
      93             : int
      94          24 : date_quarter(date dt)
      95             : {
      96          24 :         if (is_date_nil(dt))
      97             :                 return int_nil;
      98          23 :         return (date_extract_month(dt) - 1) / 3 + 1;
      99             : }
     100             : 
     101             : int
     102         870 : date_month(date dt)
     103             : {
     104         870 :         if (is_date_nil(dt))
     105             :                 return int_nil;
     106         658 :         return date_extract_month(dt);
     107             : }
     108             : 
     109             : int
     110         136 : date_day(date dt)
     111             : {
     112         136 :         if (is_date_nil(dt))
     113             :                 return int_nil;
     114         110 :         return date_extract_day(dt);
     115             : }
     116             : 
     117             : date
     118         962 : date_add_day(date dt, int days)
     119             : {
     120         962 :         if (is_date_nil(dt) || is_int_nil(days))
     121             :                 return date_nil;
     122             : 
     123         962 :         if (abs(days) >= 1 << (DTDAY_WIDTH + DTMONTH_WIDTH))
     124             :                 return date_nil;                /* overflow for sure */
     125             : 
     126         962 :         int y = date_extract_year(dt);
     127         962 :         int m = date_extract_month(dt);
     128         962 :         int d = date_extract_day(dt);
     129             : 
     130         962 :         d += days;
     131        1719 :         while (d <= 0) {
     132         757 :                 if (--m == 0) {
     133          66 :                         m = 12;
     134          66 :                         if (--y < YEAR_MIN)
     135             :                                 return date_nil;
     136             :                 }
     137        1492 :                 d += monthdays(y, m);
     138             :         }
     139       71765 :         while (d > monthdays(y, m)) {
     140       36106 :                 d -= monthdays(y, m);
     141       36106 :                 if (++m > 12) {
     142        3009 :                         m = 1;
     143        3009 :                         if (++y > YEAR_MAX)
     144             :                                 return date_nil;
     145             :                 }
     146             :         }
     147         962 :         return mkdate(y, m, d);
     148             : }
     149             : 
     150             : date
     151         771 : date_add_month(date dt, int months)
     152             : {
     153         771 :         if (is_date_nil(dt) || is_int_nil(months))
     154             :                 return date_nil;
     155             : 
     156         649 :         if (abs(months) >= 1 << DTMONTH_WIDTH)
     157             :                 return date_nil;                /* overflow for sure */
     158             : 
     159         649 :         int y = date_extract_year(dt);
     160         649 :         int m = date_extract_month(dt);
     161         649 :         int d = date_extract_day(dt);
     162         649 :         m += months;
     163         649 :         if (m <= 0) {
     164          80 :                 y -= (12 - m) / 12;
     165          80 :                 if (y < YEAR_MIN)
     166             :                         return date_nil;
     167          80 :                 m = 12 - (-m % 12);
     168         569 :         } else if (m > 12) {
     169          70 :                 y += (m - 1) / 12;
     170          70 :                 if (y > YEAR_MAX)
     171             :                         return date_nil;
     172          70 :                 m = (m - 1) % 12 + 1;
     173             :         }
     174        1254 :         if (d > monthdays(y, m)) {
     175           3 :                 d -= monthdays(y, m);
     176           3 :                 if (++m > 12) {
     177           0 :                         m = 1;
     178           0 :                         if (++y > YEAR_MAX)
     179             :                                 return date_nil;
     180             :                 }
     181             :         }
     182         649 :         return mkdate(y, m, d);
     183             : }
     184             : 
     185             : /* count days (including leap days) since some time before YEAR_MIN */
     186             : #define CNT_OFF         (((YEAR_OFFSET+399)/400)*400)
     187             : static inline int
     188         658 : date_countdays(date dt)
     189             : {
     190         658 :         static_assert(CNT_OFF % 400 == 0, /* for leapyear function to work */
     191             :                       "CNT_OFF must be multiple of 400");
     192         658 :         assert(!is_date_nil(dt));
     193         658 :         int y = date_extract_year(dt);
     194         658 :         int m = date_extract_month(dt);
     195         658 :         int y1 = y + CNT_OFF - 1;
     196         658 :         return date_extract_day(dt)
     197         658 :                 + (y+CNT_OFF)*365 + y1/4 - y1/100 + y1/400
     198         658 :                 + cumdays[m-1] + (m > 2 && isleapyear(y));
     199             : }
     200             : 
     201             : /* return the difference in days between the two dates */
     202             : int
     203         194 : date_diff(date d1, date d2)
     204             : {
     205         194 :         if (is_date_nil(d1) || is_date_nil(d2))
     206             :                 return int_nil;
     207         189 :         return date_countdays(d1) - date_countdays(d2);
     208             : }
     209             : 
     210             : /* 21 April 2019 is a Sunday, we can calculate the offset for the
     211             :  * day-of-week calculation below from this fact */
     212             : #define DOW_OFF (7 - (((21 + (2019+CNT_OFF)*365 + (2019+CNT_OFF-1)/4 - (2019+CNT_OFF-1)/100 + (2019+CNT_OFF-1)/400 + 90) % 7) + 1))
     213             : /* return day of week of given date; Monday = 1, Sunday = 7 */
     214             : int
     215          49 : date_dayofweek(date dt)
     216             : {
     217          49 :         if (is_date_nil(dt))
     218             :                 return int_nil;
     219             :         /* calculate number of days since the start of the year -CNT_OFF */
     220          46 :         int d = date_countdays(dt);
     221             :         /* then simply take the remainder from 7 and convert to correct
     222             :          * weekday */
     223          46 :         return (d + DOW_OFF) % 7 + 1;
     224             : }
     225             : 
     226             : /* week 1 is the week (Monday to Sunday) in which January 4 falls; if
     227             :  * January 1 to 3 fall in the week before the 4th, they are in the
     228             :  * last week of the previous year; the last days of the year may fall
     229             :  * in week 1 of the following year */
     230             : int
     231         125 : date_weekofyear(date dt)
     232             : {
     233         125 :         if (is_date_nil(dt))
     234             :                 return int_nil;
     235         116 :         int y = date_extract_year(dt);
     236         116 :         int m = date_extract_month(dt);
     237         116 :         int d = date_extract_day(dt);
     238         116 :         int cnt1 = date_countdays(mkdate(y, 1, 4));
     239         116 :         int wd1 = (cnt1 + DOW_OFF) % 7 + 1; /* date_dayofweek(mkdate(y, 1, 4)) */
     240         116 :         int cnt2 = date_countdays(dt);
     241         116 :         int wd2 = (cnt2 + DOW_OFF) % 7 + 1; /* date_dayofweek(dt) */
     242         116 :         if (wd2 > wd1 && m == 1 && d < 4) {
     243             :                 /* last week of previous year */
     244           2 :                 cnt1 = date_countdays(mkdate(y - 1, 1, 4));
     245           2 :                 wd1 = (cnt1 + DOW_OFF) % 7 + 1; /* date_dayofweek(mkdate(y-1, 1, 4)) */
     246         114 :         } else if (m == 12 && wd2 + 31 - d < 4)
     247             :                 return 1;
     248         116 :         if (wd2 < wd1)
     249          70 :                 cnt2 += 6;
     250         116 :         return (cnt2 - cnt1) / 7 + 1;
     251             : }
     252             : 
     253             : int
     254          38 : date_dayofyear(date dt)
     255             : {
     256          38 :         if (is_date_nil(dt))
     257             :                 return int_nil;
     258          35 :         int m = date_extract_month(dt);
     259          35 :         return date_extract_day(dt) + cumdays[m-1]
     260          62 :                 + (m > 2 && isleapyear(date_extract_year(dt)));
     261             : }
     262             : 
     263             : daytime
     264       71760 : daytime_create(int hour, int min, int sec, int usec)
     265             : {
     266       71760 :         return istime(hour, min, sec, usec) ? mkdaytime(hour, min, sec, usec) : daytime_nil;
     267             : }
     268             : 
     269             : int
     270         111 : daytime_hour(daytime tm)
     271             : {
     272         111 :         if (is_daytime_nil(tm))
     273          26 :                 return int_nil;
     274          85 :         return daytime_extract_hour(tm);
     275             : }
     276             : 
     277             : int
     278         109 : daytime_min(daytime tm)
     279             : {
     280         109 :         if (is_daytime_nil(tm))
     281          26 :                 return int_nil;
     282          83 :         return daytime_extract_minute(tm);
     283             : }
     284             : 
     285             : int
     286          28 : daytime_sec(daytime tm)
     287             : {
     288          28 :         if (is_daytime_nil(tm))
     289          16 :                 return int_nil;
     290          12 :         return (int) ((tm / 1000000) % 60);
     291             : }
     292             : 
     293             : int
     294          22 : daytime_usec(daytime tm)
     295             : {
     296          22 :         if (is_daytime_nil(tm))
     297          16 :                 return int_nil;
     298           6 :         return (int) (tm % 1000000);
     299             : }
     300             : 
     301             : int
     302          82 : daytime_sec_usec(daytime tm)
     303             : {
     304          82 :         if (is_daytime_nil(tm))
     305          10 :                 return int_nil;
     306          72 :         return daytime_extract_usecond(tm);
     307             : }
     308             : 
     309             : daytime
     310         171 : daytime_add_usec(daytime t, lng usec)
     311             : {
     312         171 :         if (is_daytime_nil(t) || is_lng_nil(usec))
     313             :                 return daytime_nil;
     314         171 :         if (llabs(usec) >= DAY_USEC)
     315             :                 return daytime_nil;             /* overflow for sure */
     316         171 :         t += usec;
     317         171 :         if (t < 0 || t >= DAY_USEC)
     318           4 :                 return daytime_nil;
     319             :         return t;
     320             : }
     321             : 
     322             : daytime
     323         243 : daytime_add_usec_modulo(daytime t, lng usec)
     324             : {
     325         243 :         if (is_daytime_nil(t) || is_lng_nil(usec))
     326             :                 return daytime_nil;
     327             :         /* if usec < 0, usec%DAY_USEC < 0 */
     328         243 :         t += usec % DAY_USEC;
     329         243 :         if (t < 0)
     330           6 :                 t += DAY_USEC;
     331         237 :         else if (t >= DAY_USEC)
     332          34 :                 t -= DAY_USEC;
     333             :         return t;
     334             : }
     335             : 
     336             : /* convert a value returned by the system time() function to a timestamp */
     337             : timestamp
     338       48760 : timestamp_fromtime(time_t timeval)
     339             : {
     340       48760 :         struct tm tm = (struct tm) {0};
     341       48760 :         date d;
     342       48760 :         daytime t;
     343             : 
     344       48760 :         if (timeval == (time_t) -1 || gmtime_r(&timeval, &tm) == NULL)
     345           0 :                 return timestamp_nil;
     346       48760 :         if (tm.tm_sec >= 60)
     347           0 :                 tm.tm_sec = 59;                 /* ignore leap seconds */
     348       48760 :         d = date_create(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
     349       48760 :         t = daytime_create(tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
     350       48760 :         if (is_date_nil(d) || is_daytime_nil(t))
     351           0 :                 return timestamp_nil;
     352       48760 :         return mktimestamp(d, t);
     353             : }
     354             : 
     355             : /* convert a value returned by GDKusec() to a timestamp */
     356             : timestamp
     357           0 : timestamp_fromusec(lng usec)
     358             : {
     359           0 :         if (is_lng_nil(usec))
     360             :                 return timestamp_nil;
     361           0 :         return timestamp_add_usec(mktimestamp(mkdate(1970, 1, 1),
     362             :                                               mkdaytime(0, 0, 0, 0)),
     363             :                                   usec);
     364             : }
     365             : 
     366             : timestamp
     367         181 : timestamp_fromdate(date dt)
     368             : {
     369         181 :         if (is_date_nil(dt))
     370          11 :                 return timestamp_nil;
     371         170 :         return mktimestamp(dt, mkdaytime(0, 0, 0, 0));
     372             : }
     373             : 
     374             : timestamp
     375       69466 : timestamp_create(date dt, daytime tm)
     376             : {
     377       69466 :         if (is_date_nil(dt) || is_daytime_nil(tm))
     378       66243 :                 return timestamp_nil;
     379        3223 :         return mktimestamp(dt, tm);
     380             : }
     381             : 
     382             : /* return the current time in UTC */
     383             : timestamp
     384       48739 : timestamp_current(void)
     385             : {
     386             : #if defined(_MSC_VER)
     387             :         FILETIME ft;
     388             :         ULARGE_INTEGER l;
     389             :         GetSystemTimeAsFileTime(&ft);
     390             :         l.LowPart = ft.dwLowDateTime;
     391             :         l.HighPart = ft.dwHighDateTime;
     392             :         return timestamp_add_usec(mktimestamp(mkdate(1601, 1, 1),
     393             :                                               mkdaytime(0, 0, 0, 0)),
     394             :                                   (lng) (l.QuadPart / 10));
     395             : #elif defined(HAVE_CLOCK_GETTIME)
     396       48739 :         struct timespec ts;
     397       48739 :         clock_gettime(CLOCK_REALTIME, &ts);
     398       48739 :         return timestamp_add_usec(timestamp_fromtime(ts.tv_sec),
     399       48739 :                                   (lng) (ts.tv_nsec / 1000));
     400             : #elif defined(HAVE_GETTIMEOFDAY)
     401             :         struct timeval tv;
     402             :         gettimeofday(&tv, NULL);
     403             :         return timestamp_add_usec(timestamp_fromtime(tv.tv_sec), (lng) tv.tv_usec);
     404             : #else
     405             :         return timestamp_fromtime(time(NULL));
     406             : #endif
     407             : }
     408             : 
     409             : timestamp
     410       70705 : timestamp_add_usec(timestamp t, lng usec)
     411             : {
     412       70705 :         if (is_timestamp_nil(t) || is_lng_nil(usec))
     413             :                 return timestamp_nil;
     414             : 
     415       70705 :         daytime tm = ts_time(t);
     416       70705 :         date dt = ts_date(t);
     417             : 
     418       70705 :         tm += usec;
     419       70705 :         if (tm < 0) {
     420         141 :                 int add = (int) ((DAY_USEC - 1 - tm) / DAY_USEC);
     421         141 :                 tm += add * DAY_USEC;
     422         141 :                 dt = date_add_day(dt, -add);
     423       70564 :         } else if (tm >= DAY_USEC) {
     424         232 :                 dt = date_add_day(dt, (int) (tm / DAY_USEC));
     425         232 :                 tm %= DAY_USEC;
     426             :         }
     427       70705 :         if (is_date_nil(dt))
     428             :                 return timestamp_nil;
     429       70705 :         return mktimestamp(dt, tm);
     430             : }
     431             : 
     432             : timestamp
     433         441 : timestamp_add_month(timestamp t, int m)
     434             : {
     435         441 :         if (is_timestamp_nil(t) || is_int_nil(m))
     436             :                 return timestamp_nil;
     437             : 
     438         333 :         daytime tm = ts_time(t);
     439         333 :         date dt = ts_date(t);
     440             : 
     441         333 :         dt = date_add_month(dt, m);
     442         333 :         if (is_date_nil(dt))
     443             :                 return timestamp_nil;
     444         333 :         return mktimestamp(dt, tm);
     445             : }
     446             : 
     447             : date
     448       72204 : timestamp_date(timestamp t)
     449             : {
     450       72204 :         if (is_timestamp_nil(t))
     451       66464 :                 return date_nil;
     452        5740 :         return ts_date(t);
     453             : }
     454             : 
     455             : daytime
     456       71204 : timestamp_daytime(timestamp t)
     457             : {
     458       71204 :         if (is_timestamp_nil(t))
     459             :                 return daytime_nil;
     460        4931 :         return ts_time(t);
     461             : }
     462             : 
     463             : lng
     464         134 : timestamp_diff(timestamp t1, timestamp t2)
     465             : {
     466         134 :         if (is_timestamp_nil(t1) || is_timestamp_nil(t2))
     467             :                 return lng_nil;
     468         130 :         return ts_time(t1) - ts_time(t2) + DAY_USEC * date_diff(ts_date(t1), ts_date(t2));
     469             : }
     470             : 
     471             : /* GDK level atom functions with some helpers */
     472             : static ssize_t
     473       24564 : fleximatch(const char *s, const char *pat, size_t min)
     474             : {
     475       24564 :         size_t hit;
     476       24564 :         bool spacy = false;
     477             : 
     478       24564 :         if (min == 0) {
     479       22842 :                 min = (int) strlen(pat);        /* default minimum required hits */
     480             :         }
     481       25322 :         for (hit = 0; *pat; hit++) {
     482       25302 :                 if (tolower((unsigned char) s[hit]) != (unsigned char) *pat) {
     483       24544 :                         if (GDKisspace(s[hit]) && spacy) {
     484           0 :                                 min++;
     485           0 :                                 continue;               /* extra spaces */
     486             :                         }
     487             :                         break;
     488             :                 }
     489         758 :                 spacy = GDKisspace(*pat);
     490         758 :                 pat++;
     491             :         }
     492       24564 :         return (hit >= min) ? hit : 0;
     493             : }
     494             : 
     495             : static ssize_t
     496         293 : parse_substr(int *ret, const char *s, size_t min, const char *list[], int size)
     497             : {
     498         293 :         ssize_t j = 0;
     499         293 :         int i = 0;
     500             : 
     501         293 :         *ret = int_nil;
     502        1816 :         while (++i <= size) {
     503        1722 :                 if ((j = fleximatch(s, list[i], min)) > 0) {
     504         199 :                         *ret = i;
     505         199 :                         break;
     506             :                 }
     507             :         }
     508         293 :         return j;
     509             : }
     510             : 
     511             : static const char *MONTHS[13] = {
     512             :         NULL, "january", "february", "march", "april", "may", "june",
     513             :         "july", "august", "september", "october", "november", "december"
     514             : };
     515             : 
     516             : static ssize_t
     517      588089 : parse_date(const char *buf, date *d, bool external)
     518             : {
     519      588089 :         int day = 0, month = int_nil;
     520      588089 :         int year = 0;
     521      588089 :         bool yearneg, yearlast = false;
     522      588089 :         ssize_t pos = 0;
     523      588089 :         int sep;
     524             : 
     525      588089 :         *d = date_nil;
     526     1176180 :         if (strNil(buf))
     527             :                 return 1;
     528      591704 :         if (external && strncmp(buf, "nil", 3) == 0)
     529             :                 return 3;
     530      591704 :         if ((yearneg = (buf[0] == '-')))
     531           8 :                 buf++;
     532      591704 :         if (!yearneg && !GDKisdigit(buf[0])) {
     533             :                 yearlast = true;
     534             :                 sep = ' ';
     535             :         } else {
     536     2953190 :                 for (pos = 0; GDKisdigit(buf[pos]); pos++) {
     537     2361590 :                         year = (buf[pos] - '0') + year * 10;
     538     2361590 :                         if (year > YEAR_MAX)
     539             :                                 break;
     540             :                 }
     541      591622 :                 sep = (unsigned char) buf[pos++];
     542      591622 :                 sep = tolower(sep);
     543      591622 :                 if (sep >= 'a' && sep <= 'z') {
     544             :                         sep = 0;
     545      591036 :                 } else if (sep == ' ') {
     546          42 :                         while (buf[pos] == ' ')
     547           0 :                                 pos++;
     548      590994 :                 } else if (sep != '-' && sep != '/' && sep != '\\') {
     549          55 :                         GDKerror("Syntax error in date.\n");
     550          55 :                         return -1;
     551             :                 }
     552             :         }
     553      591649 :         if (GDKisdigit(buf[pos])) {
     554      591356 :                 month = buf[pos++] - '0';
     555      591356 :                 if (GDKisdigit(buf[pos])) {
     556      591001 :                         month = (buf[pos++] - '0') + month * 10;
     557             :                 }
     558             :         } else {
     559         293 :                 pos += parse_substr(&month, buf + pos, 3, MONTHS, 12);
     560             :         }
     561      591649 :         if (is_int_nil(month) || (sep && buf[pos++] != sep)) {
     562         104 :                 GDKerror("Syntax error in date.\n");
     563         104 :                 return -1;
     564             :         }
     565      591545 :         if (sep == ' ') {
     566         198 :                 while (buf[pos] == ' ')
     567           0 :                         pos++;
     568             :         }
     569      591545 :         if (!GDKisdigit(buf[pos])) {
     570          12 :                 GDKerror("Syntax error in date.\n");
     571          12 :                 return -1;
     572             :         }
     573     1773280 :         while (GDKisdigit(buf[pos])) {
     574     1181800 :                 day = (buf[pos++] - '0') + day * 10;
     575     1181800 :                 if (day > 31)
     576             :                         break;
     577             :         }
     578      591533 :         if (yearlast && (buf[pos] == ',' || buf[pos] == ' ')) {
     579         162 :                 while (buf[++pos] == ' ')
     580         162 :                         ;
     581         156 :                 if (buf[pos] == '-') {
     582           0 :                         yearneg = true;
     583           0 :                         pos++;
     584             :                 }
     585         476 :                 while (GDKisdigit(buf[pos])) {
     586         320 :                         year = (buf[pos++] - '0') + year * 10;
     587         320 :                         if (year > YEAR_MAX)
     588             :                                 break;
     589             :                 }
     590             :         }
     591             :         /* handle semantic error here */
     592      591533 :         *d = date_create(yearneg ? -year : year, month, day);
     593      591533 :         if (is_date_nil(*d)) {
     594          67 :                 GDKerror("Semantic error in date.\n");
     595          67 :                 return -1;
     596             :         }
     597      591466 :         return pos + yearneg;
     598             : }
     599             : 
     600             : ssize_t
     601      561223 : date_fromstr(const char *buf, size_t *len, date **d, bool external)
     602             : {
     603      561223 :         if (*len < sizeof(date) || *d == NULL) {
     604        2678 :                 GDKfree(*d);
     605        2678 :                 *d = (date *) GDKmalloc(*len = sizeof(date));
     606        2678 :                 if( *d == NULL)
     607             :                         return -1;
     608             :         }
     609      561223 :         return parse_date(buf, *d, external);
     610             : }
     611             : 
     612             : static ssize_t
     613        5509 : do_date_tostr(char *buf, size_t len, const date *val, bool external)
     614             : {
     615        5509 :         assert(len >= 15);
     616        5509 :         if (is_date_nil(*val)) {
     617           0 :                 if (external) {
     618           0 :                         strcpy(buf, "nil");
     619           0 :                         return 3;
     620             :                 }
     621           0 :                 strcpy(buf, str_nil);
     622           0 :                 return 1;
     623             :         }
     624        5509 :         return (ssize_t) snprintf(buf, len, "%d-%02d-%02d",
     625        5509 :                                   date_extract_year(*val),
     626        5509 :                                   date_extract_month(*val),
     627             :                                   date_extract_day(*val));
     628             : }
     629             : 
     630             : ssize_t
     631        5236 : date_tostr(str *buf, size_t *len, const date *val, bool external)
     632             : {
     633             :         /* 15 bytes is more than enough */
     634        5236 :         if (*len < 15 || *buf == NULL) {
     635          49 :                 GDKfree(*buf);
     636          49 :                 *buf = GDKmalloc(15);
     637          49 :                 if( *buf == NULL)
     638             :                         return -1;
     639          49 :                 *len = 15;
     640             :         }
     641        5236 :         return do_date_tostr(*buf, *len, val, external);
     642             : }
     643             : 
     644             : static ssize_t
     645       22795 : parse_daytime(const char *buf, daytime *dt, bool external)
     646             : {
     647       22795 :         unsigned int hour, min, sec = 0, usec = 0;
     648       22795 :         int n1, n2;
     649       22795 :         ssize_t pos = 0;
     650             : 
     651       22795 :         *dt = daytime_nil;
     652       45590 :         if (strNil(buf))
     653             :                 return 1;
     654       22795 :         if (external && strncmp(buf, "nil", 3) == 0)
     655             :                 return 3;
     656             :         /* accept plenty (6) of digits, but the range is still limited */
     657       22795 :         switch (sscanf(buf, "%6u:%6u%n:%6u%n", &hour, &min, &n1, &sec, &n2)) {
     658          18 :         default:
     659          18 :                 GDKerror("Syntax error in time.\n");
     660          18 :                 return -1;
     661         230 :         case 2:
     662             :                 /* read hour and min, but not sec */
     663         230 :                 if (hour >= 24 || min >= 60) {
     664           0 :                         GDKerror("Syntax error in time.\n");
     665           0 :                         return -1;
     666             :                 }
     667         230 :                 pos += n1;
     668         230 :                 break;
     669       22547 :         case 3:
     670             :                 /* read hour, min, and sec */
     671       22547 :                 if (hour >= 24 || min >= 60 || sec > 60) {
     672           0 :                         GDKerror("Syntax error in time.\n");
     673           0 :                         return -1;
     674             :                 }
     675       22547 :                 pos += n2;
     676       22547 :                 if (buf[pos] == '.' && GDKisdigit(buf[pos+1])) {
     677       18348 :                         if (sscanf(buf + pos + 1, "%7u%n", &usec, &n1) < 1) {
     678             :                                 /* cannot happen: buf[pos+1] is a digit */
     679           0 :                                 GDKerror("Syntax error in time.\n");
     680           0 :                                 return -1;
     681             :                         }
     682       18348 :                         pos += n1 + 1;
     683       19100 :                         while (n1 < 6) {
     684         752 :                                 usec *= 10;
     685         752 :                                 n1++;
     686             :                         }
     687       18348 :                         if (n1 == 7) {
     688             : #ifdef TRUNCATE_NUMBERS
     689             :                                 usec /= 10;
     690             : #else
     691           1 :                                 usec = (usec + 5) / 10;
     692           1 :                                 if (usec == 1000000) {
     693           0 :                                         usec = 0;
     694           0 :                                         if (++sec == 60) {
     695           0 :                                                 sec = 0;
     696           0 :                                                 if (++min == 60) {
     697           0 :                                                         min = 0;
     698           0 :                                                         if (++hour == 24) {
     699           0 :                                                                 hour = 23;
     700           0 :                                                                 min = 59;
     701           0 :                                                                 sec = 59;
     702           0 :                                                                 usec = 999999;
     703             :                                                         }
     704             :                                                 }
     705             :                                         }
     706             :                                 }
     707             : #endif
     708             :                         }
     709             :                         /* ignore excess digits */
     710       18348 :                         while (GDKisdigit(buf[pos]))
     711           0 :                                 pos++;
     712             :                 }
     713             :                 break;
     714             :         }
     715       22777 :         *dt = daytime_create(hour, min, sec, usec);
     716       22777 :         if (is_daytime_nil(*dt)) {
     717           0 :                 GDKerror("Semantic error in time.\n");
     718           0 :                 return -1;
     719             :         }
     720             :         return pos;
     721             : }
     722             : 
     723             : ssize_t
     724        2224 : daytime_fromstr(const char *buf, size_t *len, daytime **ret, bool external)
     725             : {
     726        2224 :         if (*len < sizeof(daytime) || *ret == NULL) {
     727        2108 :                 GDKfree(*ret);
     728        2108 :                 *ret = (daytime *) GDKmalloc(*len = sizeof(daytime));
     729        2108 :                 if (*ret == NULL)
     730             :                         return -1;
     731             :         }
     732        2224 :         return parse_daytime(buf, *ret, external);
     733             : }
     734             : 
     735             : ssize_t
     736        2164 : daytime_tz_fromstr(const char *buf, size_t *len, daytime **ret, bool external)
     737             : {
     738        2164 :         const char *s = buf;
     739        2164 :         ssize_t pos;
     740        2164 :         daytime val;
     741        2164 :         int offset = 0;
     742             : 
     743        2164 :         pos = daytime_fromstr(s, len, ret, external);
     744        2164 :         if (pos < 0 || is_daytime_nil(**ret))
     745             :                 return pos;
     746             : 
     747        2152 :         s = buf + pos;
     748        2152 :         pos = 0;
     749        2176 :         while (GDKisspace(*s))
     750          24 :                 s++;
     751             :         /* for GMT we need to add the time zone */
     752        2152 :         if (fleximatch(s, "gmt", 0) == 3) {
     753           0 :                 s += 3;
     754             :         }
     755        2152 :         if ((s[0] == '-' || s[0] == '+') &&
     756          33 :             GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     757          17 :             ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     758          17 :                 offset = (((s[1] - '0') * 10 + (s[2] - '0')) * 60 + (s[pos] - '0') * 10 + (s[pos + 1] - '0')) * 60;
     759          17 :                 pos += 2;
     760          17 :                 if (s[0] == '+')
     761          14 :                         offset = -offset;       /* East of Greenwich */
     762          17 :                 s += pos;
     763             :         }
     764             :         /* convert to UTC */
     765        2152 :         val = **ret + offset * LL_CONSTANT(1000000);
     766        2152 :         if (val < 0)
     767           0 :                 val += DAY_USEC;
     768        2152 :         else if (val >= DAY_USEC)
     769           0 :                 val -= DAY_USEC;
     770             :         /* and return */
     771        2152 :         **ret = val;
     772        2152 :         return (ssize_t) (s - buf);
     773             : }
     774             : 
     775             : static ssize_t
     776        4538 : do_daytime_precision_tostr(char *buf, size_t len, const daytime dt,
     777             :                            int precision, bool external)
     778             : {
     779        4538 :         int hour, min, sec, usec;
     780             : 
     781        4538 :         if (precision < 0)
     782             :                 precision = 0;
     783        4538 :         if (len < 10 + (size_t) precision) {
     784             :                 return -1;
     785             :         }
     786        4538 :         if (is_daytime_nil(dt)) {
     787           0 :                 if (external) {
     788           0 :                         strcpy(buf, "nil");
     789           0 :                         return 3;
     790             :                 }
     791           0 :                 strcpy(buf, str_nil);
     792           0 :                 return 1;
     793             :         }
     794        4538 :         usec = (int) (dt % 1000000);
     795        4538 :         sec = (int) (dt / 1000000);
     796        4538 :         hour = sec / 3600;
     797        4538 :         min = (sec % 3600) / 60;
     798        4538 :         sec %= 60;
     799             : 
     800        4538 :         if (precision == 0)
     801        2314 :                 return snprintf(buf, len, "%02d:%02d:%02d", hour, min, sec);
     802        2224 :         else if (precision < 6) {
     803        3484 :                 for (int i = 6; i > precision; i--)
     804        2602 :                         usec /= 10;
     805         882 :                 return snprintf(buf, len, "%02d:%02d:%02d.%0*d", hour, min, sec, precision, usec);
     806             :         } else {
     807        1342 :                 ssize_t l = snprintf(buf, len, "%02d:%02d:%02d.%06d", hour, min, sec, usec);
     808        1342 :                 while (precision > 6) {
     809           0 :                         precision--;
     810           0 :                         buf[l++] = '0';
     811             :                 }
     812        1342 :                 buf[l] = '\0';
     813        1342 :                 return l;
     814             :         }
     815             : }
     816             : 
     817             : ssize_t
     818        4265 : daytime_precision_tostr(str *buf, size_t *len, const daytime dt,
     819             :                         int precision, bool external)
     820             : {
     821        4265 :         if (precision < 0)
     822             :                 precision = 0;
     823        4265 :         if (*len < 10 + (size_t) precision || *buf == NULL) {
     824           3 :                 GDKfree(*buf);
     825           3 :                 *buf = (str) GDKmalloc(*len = 10 + (size_t) precision);
     826           3 :                 if( *buf == NULL)
     827             :                         return -1;
     828             :         }
     829        4265 :         return do_daytime_precision_tostr(*buf, *len, dt, precision, external);
     830             : }
     831             : 
     832             : ssize_t
     833           9 : daytime_tostr(str *buf, size_t *len, const daytime *val, bool external)
     834             : {
     835           9 :         return daytime_precision_tostr(buf, len, *val, 6, external);
     836             : }
     837             : 
     838             : ssize_t
     839       20929 : timestamp_fromstr(const char *buf, size_t *len, timestamp **ret, bool external)
     840             : {
     841       20929 :         const char *s = buf;
     842       20929 :         ssize_t pos;
     843       20929 :         date dt;
     844       20929 :         daytime tm;
     845             : 
     846       20929 :         if (*len < sizeof(timestamp) || *ret == NULL) {
     847         420 :                 GDKfree(*ret);
     848         420 :                 *ret = (timestamp *) GDKmalloc(*len = sizeof(timestamp));
     849         420 :                 if (*ret == NULL)
     850             :                         return -1;
     851             :         }
     852       20929 :         pos = parse_date(buf, &dt, external);
     853       20929 :         if (pos < 0)
     854             :                 return pos;
     855       20782 :         if (is_date_nil(dt)) {
     856           0 :                 **ret = timestamp_nil;
     857           0 :                 return pos;
     858             :         }
     859       20782 :         s += pos;
     860       20782 :         if (*s == '@' || *s == ' ' || *s == '-' || *s == 'T') {
     861       20571 :                 while (*++s == ' ')
     862       20571 :                         ;
     863       20571 :                 pos = parse_daytime(s, &tm, external);
     864       20571 :                 if (pos < 0)
     865             :                         return pos;
     866       20571 :                 s += pos;
     867       20571 :                 if (is_daytime_nil(tm)) {
     868           0 :                         **ret = timestamp_nil;
     869           0 :                         return (ssize_t) (s - buf);
     870             :                 }
     871         211 :         } else if (*s) {
     872         136 :                 tm = daytime_nil;
     873             :         } else {
     874          75 :                 tm = mkdaytime(0, 0, 0, 0);
     875             :         }
     876       20782 :         if (is_date_nil(dt) || is_daytime_nil(tm)) {
     877         136 :                 **ret = timestamp_nil;
     878             :         } else {
     879       20646 :                 lng offset = 0;
     880             : 
     881       20646 :                 **ret = mktimestamp(dt, tm);
     882       20689 :                 while (GDKisspace(*s))
     883          43 :                         s++;
     884             :                 /* in case of gmt we need to add the time zone */
     885       20646 :                 if (fleximatch(s, "gmt", 0) == 3) {
     886          14 :                         s += 3;
     887             :                 }
     888       20646 :                 if ((s[0] == '-' || s[0] == '+') &&
     889          60 :                     GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     890          46 :                     ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     891          46 :                         offset = (((s[1] - '0') * LL_CONSTANT(10) + (s[2] - '0')) * LL_CONSTANT(60) + (s[pos] - '0') * LL_CONSTANT(10) + (s[pos + 1] - '0')) * LL_CONSTANT(60000000);
     892          46 :                         pos += 2;
     893          46 :                         if (s[0] != '-')
     894          30 :                                 offset = -offset;
     895          46 :                         s += pos;
     896             :                 }
     897       20646 :                 **ret = timestamp_add_usec(**ret, offset);
     898             :         }
     899       20782 :         return (ssize_t) (s - buf);
     900             : }
     901             : 
     902             : ssize_t
     903         162 : timestamp_tz_fromstr(const char *buf, size_t *len, timestamp **ret, bool external)
     904             : {
     905         162 :         const char *s = buf;
     906         162 :         ssize_t pos = timestamp_fromstr(s, len, ret, external);
     907         162 :         lng offset = 0;
     908             : 
     909         162 :         if (pos < 0 || is_timestamp_nil(**ret))
     910             :                 return pos;
     911             : 
     912          44 :         s = buf + pos;
     913          44 :         pos = 0;
     914          46 :         while (GDKisspace(*s))
     915           2 :                 s++;
     916             :         /* in case of gmt we need to add the time zone */
     917          44 :         if (fleximatch(s, "gmt", 0) == 3) {
     918           0 :                 s += 3;
     919             :         }
     920          44 :         if ((s[0] == '-' || s[0] == '+') &&
     921           8 :             GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     922           0 :             ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     923           0 :                 offset = (((s[1] - '0') * LL_CONSTANT(10) + (s[2] - '0')) * LL_CONSTANT(60) + (s[pos] - '0') * LL_CONSTANT(10) + (s[pos + 1] - '0')) * LL_CONSTANT(60000000);
     924           0 :                 pos += 2;
     925           0 :                 if (s[0] != '-')
     926           0 :                         offset = -offset;
     927           0 :                 s += pos;
     928             :         }
     929          44 :         **ret = timestamp_add_usec(**ret, offset);
     930          44 :         return (ssize_t) (s - buf);
     931             : }
     932             : 
     933             : ssize_t
     934         285 : timestamp_precision_tostr(str *buf, size_t *len, timestamp val, int precision, bool external)
     935             : {
     936         285 :         ssize_t len1, len2;
     937         285 :         char buf1[128], buf2[128];
     938         285 :         date dt;
     939         285 :         daytime tm;
     940             : 
     941         285 :         if (is_timestamp_nil(val)) {
     942          12 :                 if (*len < 4 || *buf == NULL) {
     943           5 :                         GDKfree(*buf);
     944           5 :                         *buf = GDKmalloc(*len = 4);
     945           5 :                         if( *buf == NULL)
     946             :                                 return -1;
     947             :                 }
     948          12 :                 if (external) {
     949           3 :                         strcpy(*buf, "nil");
     950           3 :                         return 3;
     951             :                 }
     952           9 :                 strcpy(*buf, str_nil);
     953           9 :                 return 1;
     954             :         }
     955             : 
     956         273 :         dt = ts_date(val);
     957         273 :         tm = ts_time(val);
     958         273 :         len1 = do_date_tostr(buf1, sizeof(buf1), &dt, false);
     959         273 :         len2 = do_daytime_precision_tostr(buf2, sizeof(buf2), tm,
     960             :                                           precision, false);
     961         273 :         if (len1 < 0 || len2 < 0)
     962             :                 return -1;
     963             : 
     964         273 :         if (*len < 2 + (size_t) len1 + (size_t) len2 || *buf == NULL) {
     965         273 :                 GDKfree(*buf);
     966         273 :                 *buf = GDKmalloc(*len = (size_t) len1 + (size_t) len2 + 2);
     967         273 :                 if( *buf == NULL)
     968             :                         return -1;
     969             :         }
     970         273 :         return (ssize_t) strconcat_len(*buf, *len, buf1, " ", buf2, NULL);
     971             : }
     972             : 
     973             : ssize_t
     974         284 : timestamp_tostr(str *buf, size_t *len, const timestamp *val, bool external)
     975             : {
     976         284 :         return timestamp_precision_tostr(buf, len, *val, 6, external);
     977             : }

Generated by: LCOV version 1.14