LCOV - code coverage report
Current view: top level - gdk - gdk_time.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 411 481 85.4 %
Date: 2021-09-14 19:48:19 Functions: 48 50 96.0 %

          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 - 2021 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     4129661 : date_create(int year, int month, int day)
      59             : {
      60             :         /* note that isdate returns false if any argument is nil */
      61     6515652 :         return isdate(year, month, day) ? mkdate(year, month, day) : date_nil;
      62             : }
      63             : 
      64             : int
      65          25 : date_century(date dt)
      66             : {
      67             :         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     3225686 : date_year(date dt)
      87             : {
      88     3225686 :         if (is_date_nil(dt))
      89             :                 return int_nil;
      90     1836418 :         return date_extract_year(dt);
      91             : }
      92             : 
      93             : int
      94          30 : date_quarter(date dt)
      95             : {
      96          30 :         if (is_date_nil(dt))
      97             :                 return int_nil;
      98          29 :         return (date_extract_month(dt) - 1) / 3 + 1;
      99             : }
     100             : 
     101             : int
     102     3218450 : date_month(date dt)
     103             : {
     104     3218450 :         if (is_date_nil(dt))
     105             :                 return int_nil;
     106     1831647 :         return date_extract_month(dt);
     107             : }
     108             : 
     109             : int
     110     3385083 : date_day(date dt)
     111             : {
     112     3385083 :         if (is_date_nil(dt))
     113             :                 return int_nil;
     114     1926470 :         return date_extract_day(dt);
     115             : }
     116             : 
     117             : date
     118         829 : date_add_day(date dt, int days)
     119             : {
     120         829 :         if (is_date_nil(dt) || is_int_nil(days))
     121             :                 return date_nil;
     122             : 
     123         829 :         if (abs(days) >= 1 << (DTDAY_WIDTH + DTMONTH_WIDTH))
     124             :                 return date_nil;                /* overflow for sure */
     125             : 
     126         829 :         int y = date_extract_year(dt);
     127         829 :         int m = date_extract_month(dt);
     128         829 :         int d = date_extract_day(dt);
     129             : 
     130         829 :         d += days;
     131         897 :         while (d <= 0) {
     132          68 :                 if (--m == 0) {
     133             :                         m = 12;
     134           8 :                         if (--y < YEAR_MIN)
     135             :                                 return date_nil;
     136             :                 }
     137         135 :                 d += monthdays(y, m);
     138             :         }
     139       49477 :         while (d > monthdays(y, m)) {
     140       24717 :                 d -= monthdays(y, m);
     141       24717 :                 if (++m > 12) {
     142             :                         m = 1;
     143        2071 :                         if (++y > YEAR_MAX)
     144             :                                 return date_nil;
     145             :                 }
     146             :         }
     147         829 :         return mkdate(y, m, d);
     148             : }
     149             : 
     150             : date
     151         268 : date_add_month(date dt, int months)
     152             : {
     153         268 :         if (is_date_nil(dt) || is_int_nil(months))
     154             :                 return date_nil;
     155             : 
     156         268 :         if (abs(months) >= 1 << DTMONTH_WIDTH)
     157             :                 return date_nil;                /* overflow for sure */
     158             : 
     159         268 :         int y = date_extract_year(dt);
     160         268 :         int m = date_extract_month(dt);
     161         268 :         int d = date_extract_day(dt);
     162         268 :         m += months;
     163         268 :         if (m <= 0) {
     164          23 :                 y -= (12 - m) / 12;
     165          23 :                 if (y < YEAR_MIN)
     166             :                         return date_nil;
     167          23 :                 m = 12 - (-m % 12);
     168         245 :         } else if (m > 12) {
     169           6 :                 y += (m - 1) / 12;
     170           6 :                 if (y > YEAR_MAX)
     171             :                         return date_nil;
     172           6 :                 m = (m - 1) % 12 + 1;
     173             :         }
     174         518 :         if (d > monthdays(y, m)) {
     175           1 :                 d -= monthdays(y, m);
     176           1 :                 if (++m > 12) {
     177             :                         m = 1;
     178           0 :                         if (++y > YEAR_MAX)
     179             :                                 return date_nil;
     180             :                 }
     181             :         }
     182         268 :         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         720 : date_countdays(date dt)
     189             : {
     190             :         static_assert(CNT_OFF % 400 == 0, /* for leapyear function to work */
     191             :                       "CNT_OFF must be multiple of 400");
     192         720 :         assert(!is_date_nil(dt));
     193         720 :         int y = date_extract_year(dt);
     194         720 :         int m = date_extract_month(dt);
     195         720 :         int y1 = y + CNT_OFF - 1;
     196         720 :         return date_extract_day(dt)
     197         720 :                 + (y+CNT_OFF)*365 + y1/4 - y1/100 + y1/400
     198         720 :                 + cumdays[m-1] + (m > 2 && isleapyear(y));
     199             : }
     200             : 
     201             : /* return the difference in days between the two dates */
     202             : int
     203         223 : date_diff(date d1, date d2)
     204             : {
     205         223 :         if (is_date_nil(d1) || is_date_nil(d2))
     206             :                 return int_nil;
     207         218 :         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          53 : date_dayofweek(date dt)
     216             : {
     217          53 :         if (is_date_nil(dt))
     218             :                 return int_nil;
     219             :         /* calculate number of days since the start of the year -CNT_OFF */
     220          50 :         int d = date_countdays(dt);
     221             :         /* then simply take the remainder from 7 and convert to correct
     222             :          * weekday */
     223          50 :         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             : /* In the US they have to do it differently, of course.
     254             :  * Week 1 is the week (Sunday to Saturday) in which January 1 falls */
     255             : int
     256           0 : date_usweekofyear(date dt)
     257             : {
     258           0 :         if (is_date_nil(dt))
     259             :                 return int_nil;
     260           0 :         int y = date_extract_year(dt);
     261           0 :         int m = date_extract_month(dt);
     262             :         /* day of year (date_dayofyear without nil check) */
     263           0 :         int doy = date_extract_day(dt) + cumdays[m-1]
     264           0 :                 + (m > 2 && isleapyear(y));
     265           0 :         int jan1 = mkdate(y, 1, 1);
     266           0 :         int jan1days = date_countdays(jan1);
     267           0 :         int jan1dow = (jan1days + DOW_OFF + 1) % 7; /* Sunday=0, Saturday=6 */
     268           0 :         return (doy + jan1dow - 1) / 7 + 1;
     269             : }
     270             : 
     271             : int
     272          43 : date_dayofyear(date dt)
     273             : {
     274          43 :         if (is_date_nil(dt))
     275             :                 return int_nil;
     276          40 :         int m = date_extract_month(dt);
     277          40 :         return date_extract_day(dt) + cumdays[m-1]
     278          73 :                 + (m > 2 && isleapyear(date_extract_year(dt)));
     279             : }
     280             : 
     281             : daytime
     282     3949910 : daytime_create(int hour, int min, int sec, int usec)
     283             : {
     284     3949910 :         return istime(hour, min, sec, usec) ? mkdaytime(hour, min, sec, usec) : daytime_nil;
     285             : }
     286             : 
     287             : /* return the difference in milliseconds between the two daytimes */
     288             : lng
     289          26 : daytime_diff(daytime d1, daytime d2)
     290             : {
     291          26 :         if (is_daytime_nil(d1) || is_daytime_nil(d2))
     292             :                 return lng_nil;
     293          20 :         return (d1 - d2) / 1000;
     294             : }
     295             : 
     296             : int
     297     3237630 : daytime_hour(daytime tm)
     298             : {
     299     3237630 :         if (is_daytime_nil(tm))
     300      630473 :                 return int_nil;
     301     2607157 :         return daytime_extract_hour(tm);
     302             : }
     303             : 
     304             : int
     305     3700751 : daytime_min(daytime tm)
     306             : {
     307     3700751 :         if (is_daytime_nil(tm))
     308      769426 :                 return int_nil;
     309     2931325 :         return daytime_extract_minute(tm);
     310             : }
     311             : 
     312             : int
     313          32 : daytime_sec(daytime tm)
     314             : {
     315          32 :         if (is_daytime_nil(tm))
     316          16 :                 return int_nil;
     317          16 :         return (int) ((tm / 1000000) % 60);
     318             : }
     319             : 
     320             : int
     321          22 : daytime_usec(daytime tm)
     322             : {
     323          22 :         if (is_daytime_nil(tm))
     324          16 :                 return int_nil;
     325           6 :         return (int) (tm % 1000000);
     326             : }
     327             : 
     328             : int
     329     3603700 : daytime_sec_usec(daytime tm)
     330             : {
     331     3603700 :         if (is_daytime_nil(tm))
     332      786155 :                 return int_nil;
     333     2817545 :         return daytime_extract_usecond(tm);
     334             : }
     335             : 
     336             : daytime
     337         124 : daytime_add_usec(daytime t, lng usec)
     338             : {
     339         124 :         if (is_daytime_nil(t) || is_lng_nil(usec))
     340             :                 return daytime_nil;
     341         124 :         if (llabs(usec) >= DAY_USEC)
     342             :                 return daytime_nil;             /* overflow for sure */
     343         124 :         t += usec;
     344         124 :         if (t < 0 || t >= DAY_USEC)
     345           4 :                 return daytime_nil;
     346             :         return t;
     347             : }
     348             : 
     349             : daytime
     350         188 : daytime_add_usec_modulo(daytime t, lng usec)
     351             : {
     352         188 :         if (is_daytime_nil(t) || is_lng_nil(usec))
     353             :                 return daytime_nil;
     354             :         /* if usec < 0, usec%DAY_USEC < 0 */
     355         184 :         t += usec % DAY_USEC;
     356         184 :         if (t < 0)
     357           0 :                 t += DAY_USEC;
     358         184 :         else if (t >= DAY_USEC)
     359          30 :                 t -= DAY_USEC;
     360             :         return t;
     361             : }
     362             : 
     363             : /* convert a value returned by the system time() function to a timestamp */
     364             : timestamp
     365        3890 : timestamp_fromtime(time_t timeval)
     366             : {
     367        3890 :         struct tm tm = (struct tm) {0};
     368             :         date d;
     369             :         daytime t;
     370             : 
     371        3890 :         if (timeval == (time_t) -1 || gmtime_r(&timeval, &tm) == NULL)
     372           0 :                 return timestamp_nil;
     373        3890 :         if (tm.tm_sec >= 60)
     374           0 :                 tm.tm_sec = 59;                 /* ignore leap seconds */
     375        3890 :         d = date_create(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
     376        3890 :         t = daytime_create(tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
     377        3890 :         if (is_date_nil(d) || is_daytime_nil(t))
     378           0 :                 return timestamp_nil;
     379        3890 :         return mktimestamp(d, t);
     380             : }
     381             : 
     382             : /* convert a value returned by GDKusec() to a timestamp */
     383             : timestamp
     384           0 : timestamp_fromusec(lng usec)
     385             : {
     386           0 :         if (is_lng_nil(usec))
     387           0 :                 return timestamp_nil;
     388           0 :         return timestamp_add_usec(mktimestamp(mkdate(1970, 1, 1),
     389             :                                               mkdaytime(0, 0, 0, 0)),
     390             :                                   usec);
     391             : }
     392             : 
     393             : timestamp
     394         377 : timestamp_fromdate(date dt)
     395             : {
     396         377 :         if (is_date_nil(dt))
     397          17 :                 return timestamp_nil;
     398         360 :         return mktimestamp(dt, mkdaytime(0, 0, 0, 0));
     399             : }
     400             : 
     401             : timestamp
     402     2003526 : timestamp_create(date dt, daytime tm)
     403             : {
     404     2003526 :         if (is_date_nil(dt) || is_daytime_nil(tm))
     405      855164 :                 return timestamp_nil;
     406     1148362 :         return mktimestamp(dt, tm);
     407             : }
     408             : 
     409             : /* return the current time in UTC */
     410             : timestamp
     411         878 : timestamp_current(void)
     412             : {
     413             : #if defined(_MSC_VER)
     414             :         FILETIME ft;
     415             :         ULARGE_INTEGER l;
     416             :         GetSystemTimeAsFileTime(&ft);
     417             :         l.LowPart = ft.dwLowDateTime;
     418             :         l.HighPart = ft.dwHighDateTime;
     419             :         return timestamp_add_usec(mktimestamp(mkdate(1601, 1, 1),
     420             :                                               mkdaytime(0, 0, 0, 0)),
     421             :                                   (lng) (l.QuadPart / 10));
     422             : #elif defined(HAVE_CLOCK_GETTIME)
     423             :         struct timespec ts;
     424         878 :         clock_gettime(CLOCK_REALTIME, &ts);
     425         878 :         return timestamp_add_usec(timestamp_fromtime(ts.tv_sec),
     426         878 :                                   (lng) (ts.tv_nsec / 1000));
     427             : #elif defined(HAVE_GETTIMEOFDAY)
     428             :         struct timeval tv;
     429             :         gettimeofday(&tv, NULL);
     430             :         return timestamp_add_usec(timestamp_fromtime(tv.tv_sec), (lng) tv.tv_usec);
     431             : #else
     432             :         return timestamp_fromtime(time(NULL));
     433             : #endif
     434             : }
     435             : 
     436             : timestamp
     437       23960 : timestamp_add_usec(timestamp t, lng usec)
     438             : {
     439       23960 :         if (is_timestamp_nil(t) || is_lng_nil(usec))
     440             :                 return timestamp_nil;
     441             : 
     442       23960 :         daytime tm = ts_time(t);
     443       23960 :         date dt = ts_date(t);
     444             : 
     445       23960 :         tm += usec;
     446       23960 :         if (tm < 0) {
     447         113 :                 int add = (int) ((DAY_USEC - 1 - tm) / DAY_USEC);
     448         113 :                 tm += add * DAY_USEC;
     449         113 :                 dt = date_add_day(dt, -add);
     450       23847 :         } else if (tm >= DAY_USEC) {
     451         201 :                 dt = date_add_day(dt, (int) (tm / DAY_USEC));
     452         201 :                 tm %= DAY_USEC;
     453             :         }
     454       23960 :         if (is_date_nil(dt))
     455             :                 return timestamp_nil;
     456       23960 :         return mktimestamp(dt, tm);
     457             : }
     458             : 
     459             : timestamp
     460         112 : timestamp_add_month(timestamp t, int m)
     461             : {
     462         112 :         if (is_timestamp_nil(t) || is_int_nil(m))
     463             :                 return timestamp_nil;
     464             : 
     465         112 :         daytime tm = ts_time(t);
     466         112 :         date dt = ts_date(t);
     467             : 
     468         112 :         dt = date_add_month(dt, m);
     469         112 :         if (is_date_nil(dt))
     470             :                 return timestamp_nil;
     471         112 :         return mktimestamp(dt, tm);
     472             : }
     473             : 
     474             : date
     475     4950322 : timestamp_date(timestamp t)
     476             : {
     477     4950322 :         if (is_timestamp_nil(t))
     478     2136116 :                 return date_nil;
     479     2814206 :         return ts_date(t);
     480             : }
     481             : 
     482             : daytime
     483     5094488 : timestamp_daytime(timestamp t)
     484             : {
     485     5094488 :         if (is_timestamp_nil(t))
     486             :                 return daytime_nil;
     487     2897369 :         return ts_time(t);
     488             : }
     489             : 
     490             : lng
     491         168 : timestamp_diff(timestamp t1, timestamp t2)
     492             : {
     493         168 :         if (is_timestamp_nil(t1) || is_timestamp_nil(t2))
     494             :                 return lng_nil;
     495         164 :         return ts_time(t1) - ts_time(t2) + DAY_USEC * date_diff(ts_date(t1), ts_date(t2));
     496             : }
     497             : 
     498             : /* GDK level atom functions with some helpers */
     499             : static ssize_t
     500       26855 : fleximatch(const char *s, const char *pat, size_t min)
     501             : {
     502             :         size_t hit;
     503             :         bool spacy = false;
     504             : 
     505       26855 :         if (min == 0) {
     506       24700 :                 min = (int) strlen(pat);        /* default minimum required hits */
     507             :         }
     508       27750 :         for (hit = 0; *pat; hit++) {
     509       27727 :                 if (tolower((unsigned char) s[hit]) != (unsigned char) *pat) {
     510       26832 :                         if (GDKisspace(s[hit]) && spacy) {
     511           0 :                                 min++;
     512           0 :                                 continue;               /* extra spaces */
     513             :                         }
     514             :                         break;
     515             :                 }
     516         895 :                 spacy = GDKisspace(*pat);
     517         895 :                 pat++;
     518             :         }
     519       26855 :         return (hit >= min) ? hit : 0;
     520             : }
     521             : 
     522             : static ssize_t
     523         355 : parse_substr(int *ret, const char *s, size_t min, const char *list[], int size)
     524             : {
     525             :         ssize_t j = 0;
     526             :         int i = 0;
     527             : 
     528         355 :         *ret = int_nil;
     529        2274 :         while (++i <= size) {
     530        2155 :                 if ((j = fleximatch(s, list[i], min)) > 0) {
     531         236 :                         *ret = i;
     532         236 :                         break;
     533             :                 }
     534             :         }
     535         355 :         return j;
     536             : }
     537             : 
     538             : static const char *MONTHS[13] = {
     539             :         NULL, "january", "february", "march", "april", "may", "june",
     540             :         "july", "august", "september", "october", "november", "december"
     541             : };
     542             : 
     543             : static ssize_t
     544      406427 : parse_date(const char *buf, date *d, bool external)
     545             : {
     546      406427 :         int day = 0, month = int_nil;
     547             :         int year = 0;
     548             :         bool yearneg, yearlast = false;
     549             :         ssize_t pos = 0;
     550             :         int sep;
     551             : 
     552      406427 :         *d = date_nil;
     553      406427 :         if (strNil(buf))
     554             :                 return 1;
     555      408956 :         if (external && strncmp(buf, "nil", 3) == 0)
     556             :                 return 3;
     557      408956 :         if ((yearneg = (buf[0] == '-')))
     558           9 :                 buf++;
     559      408956 :         if (!yearneg && !GDKisdigit(buf[0])) {
     560             :                 yearlast = true;
     561             :                 sep = ' ';
     562             :         } else {
     563     2040421 :                 for (pos = 0; GDKisdigit(buf[pos]); pos++) {
     564     1631706 :                         year = (buf[pos] - '0') + year * 10;
     565     1631706 :                         if (year > YEAR_MAX)
     566             :                                 break;
     567             :                 }
     568      408739 :                 sep = (unsigned char) buf[pos++];
     569      408739 :                 sep = tolower(sep);
     570      408739 :                 if (sep >= 'a' && sep <= 'z') {
     571             :                         sep = 0;
     572      410509 :                 } else if (sep == ' ') {
     573          42 :                         while (buf[pos] == ' ')
     574           0 :                                 pos++;
     575      410467 :                 } else if (sep != '-' && sep != '/' && sep != '\\') {
     576          59 :                         GDKerror("Syntax error in date.\n");
     577          59 :                         return -1;
     578             :                 }
     579             :         }
     580      408897 :         if (GDKisdigit(buf[pos])) {
     581      408542 :                 month = buf[pos++] - '0';
     582      408542 :                 if (GDKisdigit(buf[pos])) {
     583      410692 :                         month = (buf[pos++] - '0') + month * 10;
     584             :                 }
     585             :         } else {
     586         355 :                 pos += parse_substr(&month, buf + pos, 3, MONTHS, 12);
     587             :         }
     588      408897 :         if (is_int_nil(month) || (sep && buf[pos++] != sep)) {
     589         130 :                 GDKerror("Syntax error in date.\n");
     590         130 :                 return -1;
     591             :         }
     592      408767 :         if (sep == ' ') {
     593         234 :                 while (buf[pos] == ' ')
     594           0 :                         pos++;
     595             :         }
     596      408767 :         if (!GDKisdigit(buf[pos])) {
     597          12 :                 GDKerror("Syntax error in date.\n");
     598          12 :                 return -1;
     599             :         }
     600     1230617 :         while (GDKisdigit(buf[pos])) {
     601      821916 :                 day = (buf[pos++] - '0') + day * 10;
     602      821916 :                 if (day > 31)
     603             :                         break;
     604             :         }
     605      408755 :         if (yearlast && (buf[pos] == ',' || buf[pos] == ' ')) {
     606         198 :                 while (buf[++pos] == ' ')
     607             :                         ;
     608         192 :                 if (buf[pos] == '-') {
     609             :                         yearneg = true;
     610           0 :                         pos++;
     611             :                 }
     612         583 :                 while (GDKisdigit(buf[pos])) {
     613         391 :                         year = (buf[pos++] - '0') + year * 10;
     614         391 :                         if (year > YEAR_MAX)
     615             :                                 break;
     616             :                 }
     617             :         }
     618             :         /* handle semantic error here */
     619      408755 :         *d = date_create(yearneg ? -year : year, month, day);
     620      408755 :         if (is_date_nil(*d)) {
     621          73 :                 GDKerror("Semantic error in date.\n");
     622          73 :                 return -1;
     623             :         }
     624      408682 :         return pos + yearneg;
     625             : }
     626             : 
     627             : ssize_t
     628      382039 : date_fromstr(const char *buf, size_t *len, date **d, bool external)
     629             : {
     630      382039 :         if (*len < sizeof(date) || *d == NULL) {
     631        2788 :                 GDKfree(*d);
     632        2788 :                 *d = (date *) GDKmalloc(*len = sizeof(date));
     633        2788 :                 if( *d == NULL)
     634             :                         return -1;
     635             :         }
     636      382039 :         return parse_date(buf, *d, external);
     637             : }
     638             : 
     639             : static ssize_t
     640        5788 : do_date_tostr(char *buf, size_t len, const date *val, bool external)
     641             : {
     642        5788 :         assert(len >= 15);
     643        5788 :         if (is_date_nil(*val)) {
     644           0 :                 if (external) {
     645           0 :                         strcpy(buf, "nil");
     646           0 :                         return 3;
     647             :                 }
     648           0 :                 strcpy(buf, str_nil);
     649           0 :                 return 1;
     650             :         }
     651        5788 :         return (ssize_t) snprintf(buf, len, "%d-%02d-%02d",
     652        5788 :                                   date_extract_year(*val),
     653        5788 :                                   date_extract_month(*val),
     654             :                                   date_extract_day(*val));
     655             : }
     656             : 
     657             : ssize_t
     658        5350 : date_tostr(str *buf, size_t *len, const date *val, bool external)
     659             : {
     660             :         /* 15 bytes is more than enough */
     661        5350 :         if (*len < 15 || *buf == NULL) {
     662          19 :                 GDKfree(*buf);
     663          19 :                 *buf = GDKmalloc(15);
     664          20 :                 if( *buf == NULL)
     665             :                         return -1;
     666          20 :                 *len = 15;
     667             :         }
     668        5351 :         return do_date_tostr(*buf, *len, val, external);
     669             : }
     670             : 
     671             : static ssize_t
     672       24601 : parse_daytime(const char *buf, daytime *dt, bool external)
     673             : {
     674       24601 :         unsigned int hour, min, sec = 0, usec = 0;
     675             :         int n1, n2;
     676             :         ssize_t pos = 0;
     677             : 
     678       24601 :         *dt = daytime_nil;
     679       24601 :         if (strNil(buf))
     680             :                 return 1;
     681       24601 :         if (external && strncmp(buf, "nil", 3) == 0)
     682             :                 return 3;
     683             :         /* accept plenty (6) of digits, but the range is still limited */
     684       24601 :         switch (sscanf(buf, "%6u:%6u%n:%6u%n", &hour, &min, &n1, &sec, &n2)) {
     685          18 :         default:
     686          18 :                 GDKerror("Syntax error in time.\n");
     687          18 :                 return -1;
     688         234 :         case 2:
     689             :                 /* read hour and min, but not sec */
     690         234 :                 if (hour >= 24 || min >= 60) {
     691           0 :                         GDKerror("Syntax error in time.\n");
     692           0 :                         return -1;
     693             :                 }
     694         234 :                 pos += n1;
     695         234 :                 break;
     696       24349 :         case 3:
     697             :                 /* read hour, min, and sec */
     698       24349 :                 if (hour >= 24 || min >= 60 || sec > 60) {
     699           0 :                         GDKerror("Syntax error in time.\n");
     700           0 :                         return -1;
     701             :                 }
     702       24349 :                 pos += n2;
     703       24349 :                 if (buf[pos] == '.' && GDKisdigit(buf[pos+1])) {
     704       19450 :                         if (sscanf(buf + pos + 1, "%7u%n", &usec, &n1) < 1) {
     705             :                                 /* cannot happen: buf[pos+1] is a digit */
     706           0 :                                 GDKerror("Syntax error in time.\n");
     707           0 :                                 return -1;
     708             :                         }
     709       19450 :                         pos += n1 + 1;
     710       20505 :                         while (n1 < 6) {
     711        1055 :                                 usec *= 10;
     712        1055 :                                 n1++;
     713             :                         }
     714       19450 :                         if (n1 == 7) {
     715             : #ifdef TRUNCATE_NUMBERS
     716             :                                 usec /= 10;
     717             : #else
     718           1 :                                 usec = (usec + 5) / 10;
     719           1 :                                 if (usec == 1000000) {
     720           0 :                                         usec = 0;
     721           0 :                                         if (++sec == 60) {
     722           0 :                                                 sec = 0;
     723           0 :                                                 if (++min == 60) {
     724           0 :                                                         min = 0;
     725           0 :                                                         if (++hour == 24) {
     726           0 :                                                                 hour = 23;
     727           0 :                                                                 min = 59;
     728           0 :                                                                 sec = 59;
     729           0 :                                                                 usec = 999999;
     730             :                                                         }
     731             :                                                 }
     732             :                                         }
     733             :                                 }
     734             : #endif
     735             :                         }
     736             :                         /* ignore excess digits */
     737       19450 :                         while (GDKisdigit(buf[pos]))
     738           0 :                                 pos++;
     739             :                 }
     740             :                 break;
     741             :         }
     742       24583 :         *dt = daytime_create(hour, min, sec, usec);
     743       24583 :         if (is_daytime_nil(*dt)) {
     744           0 :                 GDKerror("Semantic error in time.\n");
     745           0 :                 return -1;
     746             :         }
     747             :         return pos;
     748             : }
     749             : 
     750             : ssize_t
     751        2660 : daytime_fromstr(const char *buf, size_t *len, daytime **ret, bool external)
     752             : {
     753        2660 :         if (*len < sizeof(daytime) || *ret == NULL) {
     754        2359 :                 GDKfree(*ret);
     755        2359 :                 *ret = (daytime *) GDKmalloc(*len = sizeof(daytime));
     756        2359 :                 if (*ret == NULL)
     757             :                         return -1;
     758             :         }
     759        2660 :         return parse_daytime(buf, *ret, external);
     760             : }
     761             : 
     762             : ssize_t
     763        2642 : daytime_tz_fromstr(const char *buf, size_t *len, daytime **ret, bool external)
     764             : {
     765             :         const char *s = buf;
     766             :         ssize_t pos;
     767             :         daytime val;
     768             :         int offset = 0;
     769             : 
     770        2642 :         pos = daytime_fromstr(s, len, ret, external);
     771        2642 :         if (pos < 0 || is_daytime_nil(**ret))
     772             :                 return pos;
     773             : 
     774        2630 :         s = buf + pos;
     775             :         pos = 0;
     776        2658 :         while (GDKisspace(*s))
     777          28 :                 s++;
     778             :         /* for GMT we need to add the time zone */
     779        2630 :         if (fleximatch(s, "gmt", 0) == 3) {
     780           0 :                 s += 3;
     781             :         }
     782        2630 :         if ((s[0] == '-' || s[0] == '+') &&
     783          34 :             GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     784          18 :             ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     785          18 :                 offset = (((s[1] - '0') * 10 + (s[2] - '0')) * 60 + (s[pos] - '0') * 10 + (s[pos + 1] - '0')) * 60;
     786          18 :                 pos += 2;
     787          18 :                 if (s[0] == '+')
     788          15 :                         offset = -offset;       /* East of Greenwich */
     789          18 :                 s += pos;
     790             :         }
     791             :         /* convert to UTC */
     792        2630 :         val = **ret + offset * LL_CONSTANT(1000000);
     793        2630 :         if (val < 0)
     794           0 :                 val += DAY_USEC;
     795        2630 :         else if (val >= DAY_USEC)
     796           0 :                 val -= DAY_USEC;
     797             :         /* and return */
     798        2630 :         **ret = val;
     799        2630 :         return (ssize_t) (s - buf);
     800             : }
     801             : 
     802             : static ssize_t
     803        4413 : do_daytime_precision_tostr(char *buf, size_t len, const daytime dt,
     804             :                            int precision, bool external)
     805             : {
     806             :         int hour, min, sec, usec;
     807             : 
     808             :         if (precision < 0)
     809             :                 precision = 0;
     810        4413 :         if (len < 10 + (size_t) precision) {
     811             :                 return -1;
     812             :         }
     813        4413 :         if (is_daytime_nil(dt)) {
     814           0 :                 if (external) {
     815           0 :                         strcpy(buf, "nil");
     816           0 :                         return 3;
     817             :                 }
     818           0 :                 strcpy(buf, str_nil);
     819           0 :                 return 1;
     820             :         }
     821        4413 :         usec = (int) (dt % 1000000);
     822        4413 :         sec = (int) (dt / 1000000);
     823        4413 :         hour = sec / 3600;
     824        4413 :         min = (sec % 3600) / 60;
     825        4413 :         sec %= 60;
     826             : 
     827        4413 :         if (precision == 0)
     828        2366 :                 return snprintf(buf, len, "%02d:%02d:%02d", hour, min, sec);
     829        2047 :         else if (precision < 6) {
     830        2760 :                 for (int i = 6; i > precision; i--)
     831        2071 :                         usec /= 10;
     832         689 :                 return snprintf(buf, len, "%02d:%02d:%02d.%0*d", hour, min, sec, precision, usec);
     833             :         } else {
     834        1358 :                 ssize_t l = snprintf(buf, len, "%02d:%02d:%02d.%06d", hour, min, sec, usec);
     835        1358 :                 while (precision > 6) {
     836           0 :                         precision--;
     837           0 :                         buf[l++] = '0';
     838             :                 }
     839        1358 :                 buf[l] = '\0';
     840        1358 :                 return l;
     841             :         }
     842             : }
     843             : 
     844             : ssize_t
     845        3975 : daytime_precision_tostr(str *buf, size_t *len, const daytime dt,
     846             :                         int precision, bool external)
     847             : {
     848             :         if (precision < 0)
     849             :                 precision = 0;
     850        3975 :         if (*len < 10 + (size_t) precision || *buf == NULL) {
     851           1 :                 GDKfree(*buf);
     852           1 :                 *buf = (str) GDKmalloc(*len = 10 + (size_t) precision);
     853           1 :                 if( *buf == NULL)
     854             :                         return -1;
     855             :         }
     856        3975 :         return do_daytime_precision_tostr(*buf, *len, dt, precision, external);
     857             : }
     858             : 
     859             : ssize_t
     860           7 : daytime_tostr(str *buf, size_t *len, const daytime *val, bool external)
     861             : {
     862           7 :         return daytime_precision_tostr(buf, len, *val, 6, external);
     863             : }
     864             : 
     865             : ssize_t
     866       22376 : timestamp_fromstr(const char *buf, size_t *len, timestamp **ret, bool external)
     867             : {
     868             :         const char *s = buf;
     869             :         ssize_t pos;
     870             :         date dt;
     871             :         daytime tm;
     872             : 
     873       22376 :         if (*len < sizeof(timestamp) || *ret == NULL) {
     874        3017 :                 GDKfree(*ret);
     875        3017 :                 *ret = (timestamp *) GDKmalloc(*len = sizeof(timestamp));
     876        3017 :                 if (*ret == NULL)
     877             :                         return -1;
     878             :         }
     879       22376 :         pos = parse_date(buf, &dt, external);
     880       22376 :         if (pos < 0)
     881             :                 return pos;
     882       22195 :         if (is_date_nil(dt)) {
     883           0 :                 **ret = timestamp_nil;
     884           0 :                 return pos;
     885             :         }
     886       22195 :         s += pos;
     887       22195 :         if (*s == '@' || *s == ' ' || *s == '-' || *s == 'T') {
     888       21941 :                 while (*++s == ' ')
     889             :                         ;
     890       21941 :                 pos = parse_daytime(s, &tm, external);
     891       21941 :                 if (pos < 0)
     892             :                         return pos;
     893       21941 :                 s += pos;
     894       21941 :                 if (is_daytime_nil(tm)) {
     895           0 :                         **ret = timestamp_nil;
     896           0 :                         return (ssize_t) (s - buf);
     897             :                 }
     898         254 :         } else if (*s) {
     899         170 :                 tm = daytime_nil;
     900             :         } else {
     901          84 :                 tm = mkdaytime(0, 0, 0, 0);
     902             :         }
     903       22195 :         if (is_date_nil(dt) || is_daytime_nil(tm)) {
     904         170 :                 **ret = timestamp_nil;
     905             :         } else {
     906             :                 lng offset = 0;
     907             : 
     908       22025 :                 **ret = mktimestamp(dt, tm);
     909       22076 :                 while (GDKisspace(*s))
     910          51 :                         s++;
     911             :                 /* in case of gmt we need to add the time zone */
     912       22025 :                 if (fleximatch(s, "gmt", 0) == 3) {
     913          17 :                         s += 3;
     914             :                 }
     915       22025 :                 if ((s[0] == '-' || s[0] == '+') &&
     916          65 :                     GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     917          48 :                     ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     918          48 :                         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);
     919          48 :                         pos += 2;
     920          48 :                         if (s[0] != '-')
     921          32 :                                 offset = -offset;
     922          48 :                         s += pos;
     923             :                 }
     924       22025 :                 **ret = timestamp_add_usec(**ret, offset);
     925             :         }
     926       22195 :         return (ssize_t) (s - buf);
     927             : }
     928             : 
     929             : ssize_t
     930         163 : timestamp_tz_fromstr(const char *buf, size_t *len, timestamp **ret, bool external)
     931             : {
     932             :         const char *s = buf;
     933         163 :         ssize_t pos = timestamp_fromstr(s, len, ret, external);
     934             :         lng offset = 0;
     935             : 
     936         163 :         if (pos < 0 || is_timestamp_nil(**ret))
     937             :                 return pos;
     938             : 
     939          45 :         s = buf + pos;
     940             :         pos = 0;
     941          47 :         while (GDKisspace(*s))
     942           2 :                 s++;
     943             :         /* in case of gmt we need to add the time zone */
     944          45 :         if (fleximatch(s, "gmt", 0) == 3) {
     945           0 :                 s += 3;
     946             :         }
     947          45 :         if ((s[0] == '-' || s[0] == '+') &&
     948           8 :             GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     949           0 :             ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     950           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);
     951           0 :                 pos += 2;
     952           0 :                 if (s[0] != '-')
     953           0 :                         offset = -offset;
     954           0 :                 s += pos;
     955             :         }
     956          45 :         **ret = timestamp_add_usec(**ret, offset);
     957          45 :         return (ssize_t) (s - buf);
     958             : }
     959             : 
     960             : ssize_t
     961         450 : timestamp_precision_tostr(str *buf, size_t *len, timestamp val, int precision, bool external)
     962             : {
     963             :         ssize_t len1, len2;
     964             :         char buf1[128], buf2[128];
     965             :         date dt;
     966             :         daytime tm;
     967             : 
     968         450 :         if (is_timestamp_nil(val)) {
     969          12 :                 if (*len < 4 || *buf == NULL) {
     970          11 :                         GDKfree(*buf);
     971          11 :                         *buf = GDKmalloc(*len = 4);
     972          11 :                         if( *buf == NULL)
     973             :                                 return -1;
     974             :                 }
     975          12 :                 if (external) {
     976          11 :                         strcpy(*buf, "nil");
     977          11 :                         return 3;
     978             :                 }
     979           1 :                 strcpy(*buf, str_nil);
     980           1 :                 return 1;
     981             :         }
     982             : 
     983         438 :         dt = ts_date(val);
     984         438 :         tm = ts_time(val);
     985         438 :         len1 = do_date_tostr(buf1, sizeof(buf1), &dt, false);
     986         438 :         len2 = do_daytime_precision_tostr(buf2, sizeof(buf2), tm,
     987             :                                           precision, false);
     988         438 :         if (len1 < 0 || len2 < 0)
     989             :                 return -1;
     990             : 
     991         438 :         if (*len < 2 + (size_t) len1 + (size_t) len2 || *buf == NULL) {
     992         434 :                 GDKfree(*buf);
     993         434 :                 *buf = GDKmalloc(*len = (size_t) len1 + (size_t) len2 + 2);
     994         434 :                 if( *buf == NULL)
     995             :                         return -1;
     996             :         }
     997         438 :         return (ssize_t) strconcat_len(*buf, *len, buf1, " ", buf2, NULL);
     998             : }
     999             : 
    1000             : ssize_t
    1001         450 : timestamp_tostr(str *buf, size_t *len, const timestamp *val, bool external)
    1002             : {
    1003         450 :         return timestamp_precision_tostr(buf, len, *val, 6, external);
    1004             : }

Generated by: LCOV version 1.14