LCOV - code coverage report
Current view: top level - gdk - gdk_time.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 489 557 87.8 %
Date: 2024-04-25 20:03:45 Functions: 49 50 98.0 %

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

Generated by: LCOV version 1.14