LCOV - code coverage report
Current view: top level - gdk - gdk_time.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 517 582 88.8 %
Date: 2024-04-26 00:35:57 Functions: 53 55 96.4 %

          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     4497723 : date_create(int year, int month, int day)
      63             : {
      64             :         /* note that isdate returns false if any argument is nil */
      65     4755190 :         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     7080465 : date_year(date dt)
      91             : {
      92     7080465 :         if (is_date_nil(dt))
      93             :                 return int_nil;
      94     6709428 :         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     6775667 : date_month(date dt)
     107             : {
     108     6775667 :         if (is_date_nil(dt))
     109      356948 :                 return bte_nil;
     110     6418719 :         return date_extract_month(dt);
     111             : }
     112             : 
     113             : bte
     114     7103020 : date_day(date dt)
     115             : {
     116     7103020 :         if (is_date_nil(dt))
     117      375411 :                 return bte_nil;
     118     6727609 :         return date_extract_day(dt);
     119             : }
     120             : 
     121             : date
     122        2871 : date_add_day(date dt, int days)
     123             : {
     124        2871 :         if (is_date_nil(dt) || is_int_nil(days))
     125             :                 return date_nil;
     126             : 
     127        2871 :         if (abs(days) >= 1 << (DTDAY_WIDTH + DTMONTH_WIDTH))
     128             :                 return date_nil;                /* overflow for sure */
     129             : 
     130        2871 :         int y = date_extract_year(dt);
     131        2871 :         int m = date_extract_month(dt);
     132        2871 :         int d = date_extract_day(dt);
     133             : 
     134        2871 :         d += days;
     135        2965 :         while (d <= 0) {
     136          94 :                 if (--m == 0) {
     137          20 :                         m = 12;
     138          20 :                         if (--y < YEAR_MIN)
     139             :                                 return date_nil;
     140             :                 }
     141          95 :                 d += monthdays(y, m);
     142             :         }
     143        7265 :         while (d > monthdays(y, m)) {
     144        4028 :                 d -= monthdays(y, m);
     145        4028 :                 if (++m > 12) {
     146         386 :                         m = 1;
     147         386 :                         if (++y > YEAR_MAX)
     148             :                                 return date_nil;
     149             :                 }
     150             :         }
     151        2871 :         return mkdate(y, m, d);
     152             : }
     153             : 
     154             : date
     155         304 : date_add_month(date dt, int months)
     156             : {
     157         304 :         if (is_date_nil(dt) || is_int_nil(months))
     158             :                 return date_nil;
     159             : 
     160         304 :         if (abs(months) >= 1 << DTMONTH_WIDTH)
     161             :                 return date_nil;                /* overflow for sure */
     162             : 
     163         303 :         int y = date_extract_year(dt);
     164         303 :         int m = date_extract_month(dt);
     165         303 :         int d = date_extract_day(dt);
     166         303 :         m += months;
     167         303 :         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         277 :         } 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         327 :         if (d > monthdays(y, m)) {
     179          12 :                 d = monthdays(y, m);
     180             :         }
     181         303 :         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         883 : date_countdays(date dt)
     188             : {
     189         883 :         static_assert(CNT_OFF % 400 == 0, /* for leapyear function to work */
     190             :                       "CNT_OFF must be multiple of 400");
     191         883 :         assert(!is_date_nil(dt));
     192         883 :         int y = date_extract_year(dt);
     193         883 :         int m = date_extract_month(dt);
     194         883 :         int y1 = y + CNT_OFF - 1;
     195         883 :         return date_extract_day(dt)
     196         883 :                 + (y+CNT_OFF)*365 + y1/4 - y1/100 + y1/400
     197         883 :                 + cumdays[m-1] + (m > 2 && isleapyear(y));
     198             : }
     199             : 
     200             : /* return the difference in days between the two dates */
     201             : int
     202         280 : date_diff(date d1, date d2)
     203             : {
     204         280 :         if (is_date_nil(d1) || is_date_nil(d2))
     205             :                 return int_nil;
     206         275 :         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          89 : date_dayofweek(date dt)
     215             : {
     216          89 :         if (is_date_nil(dt))
     217           3 :                 return bte_nil;
     218             :         /* calculate number of days since the start of the year -CNT_OFF */
     219          86 :         int d = date_countdays(dt);
     220             :         /* then simply take the remainder from 7 and convert to correct
     221             :          * weekday */
     222          86 :         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          80 : date_dayofyear(date dt)
     272             : {
     273          80 :         if (is_date_nil(dt))
     274           3 :                 return sht_nil;
     275          77 :         int m = date_extract_month(dt);
     276          77 :         return date_extract_day(dt) + cumdays[m-1]
     277          91 :                 + (m > 2 && isleapyear(date_extract_year(dt)));
     278             : }
     279             : 
     280             : daytime
     281     3748195 : daytime_create(int hour, int min, int sec, int usec)
     282             : {
     283     3748195 :         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          34 : daytime_diff(daytime d1, daytime d2)
     289             : {
     290          34 :         if (is_daytime_nil(d1) || is_daytime_nil(d2))
     291             :                 return lng_nil;
     292          28 :         return (d1 - d2) / 1000;
     293             : }
     294             : 
     295             : bte
     296     7130285 : daytime_hour(daytime tm)
     297             : {
     298     7130285 :         if (is_daytime_nil(tm))
     299      376938 :                 return bte_nil;
     300     6753347 :         return daytime_extract_hour(tm);
     301             : }
     302             : 
     303             : bte
     304     6895261 : daytime_min(daytime tm)
     305             : {
     306     6895261 :         if (is_daytime_nil(tm))
     307      363612 :                 return bte_nil;
     308     6531649 :         return daytime_extract_minute(tm);
     309             : }
     310             : 
     311             : int
     312     3601267 : daytime_sec(daytime tm)
     313             : {
     314     3601267 :         if (is_daytime_nil(tm))
     315          17 :                 return int_nil;
     316     3601250 :         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     3485721 : daytime_sec_usec(daytime tm)
     329             : {
     330     3485721 :         if (is_daytime_nil(tm))
     331      374619 :                 return int_nil;
     332     3111102 :         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         260 : daytime_add_usec_modulo(daytime t, lng usec)
     350             : {
     351         260 :         if (is_daytime_nil(t) || is_lng_nil(usec))
     352             :                 return daytime_nil;
     353             :         /* if usec < 0, usec%DAY_USEC < 0 */
     354         249 :         t += usec % DAY_USEC;
     355         249 :         if (t < 0)
     356           3 :                 t += DAY_USEC;
     357         246 :         else if (t >= DAY_USEC)
     358          40 :                 t -= DAY_USEC;
     359             :         return t;
     360             : }
     361             : 
     362             : /* convert a value returned by the system time() function to a timestamp */
     363             : timestamp
     364        2898 : timestamp_fromtime(time_t timeval)
     365             : {
     366        2898 :         struct tm tm = (struct tm) {0};
     367        2898 :         date d;
     368        2898 :         daytime t;
     369             : 
     370        2898 :         if (timeval == (time_t) -1 || gmtime_r(&timeval, &tm) == NULL)
     371           0 :                 return timestamp_nil;
     372        2898 :         if (tm.tm_sec >= 60)
     373           0 :                 tm.tm_sec = 59;                 /* ignore leap seconds */
     374        2898 :         d = date_create(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
     375        2898 :         t = daytime_create(tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
     376        2898 :         if (is_date_nil(d) || is_daytime_nil(t))
     377           0 :                 return timestamp_nil;
     378        2898 :         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     2001851 : timestamp_create(date dt, daytime tm)
     402             : {
     403     2001851 :         if (is_date_nil(dt) || is_daytime_nil(tm))
     404      199410 :                 return timestamp_nil;
     405     1802441 :         return mktimestamp(dt, tm);
     406             : }
     407             : 
     408             : /* return the current time in UTC */
     409             : timestamp
     410         474 : 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         474 :         struct timespec ts;
     423         474 :         clock_gettime(CLOCK_REALTIME, &ts);
     424         474 :         return timestamp_add_usec(timestamp_fromtime(ts.tv_sec),
     425         474 :                                   (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       20775 : timestamp_add_usec(timestamp t, lng usec)
     437             : {
     438       20775 :         if (is_timestamp_nil(t) || is_lng_nil(usec))
     439             :                 return timestamp_nil;
     440             : 
     441       20767 :         daytime tm = ts_time(t);
     442       20767 :         date dt = ts_date(t);
     443             : 
     444       20767 :         tm += usec;
     445       20767 :         if (tm < 0) {
     446         181 :                 int add = (int) ((DAY_USEC - 1 - tm) / DAY_USEC);
     447         181 :                 tm += add * DAY_USEC;
     448         181 :                 dt = date_add_day(dt, -add);
     449       20586 :         } else if (tm >= DAY_USEC) {
     450         269 :                 dt = date_add_day(dt, (int) (tm / DAY_USEC));
     451         269 :                 tm %= DAY_USEC;
     452             :         }
     453       20767 :         if (is_date_nil(dt))
     454             :                 return timestamp_nil;
     455       20767 :         return mktimestamp(dt, tm);
     456             : }
     457             : 
     458             : timestamp
     459         120 : timestamp_add_month(timestamp t, int m)
     460             : {
     461         120 :         if (is_timestamp_nil(t) || is_int_nil(m))
     462             :                 return timestamp_nil;
     463             : 
     464         120 :         daytime tm = ts_time(t);
     465         120 :         date dt = ts_date(t);
     466             : 
     467         120 :         dt = date_add_month(dt, m);
     468         120 :         if (is_date_nil(dt))
     469             :                 return timestamp_nil;
     470         120 :         return mktimestamp(dt, tm);
     471             : }
     472             : 
     473             : date
     474     6918331 : timestamp_date(timestamp t)
     475             : {
     476     6918331 :         if (is_timestamp_nil(t))
     477      559628 :                 return date_nil;
     478     6358703 :         return ts_date(t);
     479             : }
     480             : 
     481             : daytime
     482     6978104 : timestamp_daytime(timestamp t)
     483             : {
     484     6978104 :         if (is_timestamp_nil(t))
     485             :                 return daytime_nil;
     486     6417336 :         return ts_time(t);
     487             : }
     488             : 
     489             : lng
     490         204 : timestamp_diff(timestamp t1, timestamp t2)
     491             : {
     492         204 :         if (is_timestamp_nil(t1) || is_timestamp_nil(t2))
     493             :                 return lng_nil;
     494         200 :         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       23982 : fleximatch(const char *s, const char *pat, size_t min)
     500             : {
     501       23982 :         size_t hit;
     502       23982 :         bool spacy = false;
     503             : 
     504       23982 :         if (min == 0) {
     505       21984 :                 min = (int) strlen(pat);        /* default minimum required hits */
     506             :         }
     507       24777 :         for (hit = 0; *pat; hit++) {
     508       24758 :                 if (tolower((unsigned char) s[hit]) != (unsigned char) *pat) {
     509       23963 :                         if (GDKisspace(s[hit]) && spacy) {
     510           0 :                                 min++;
     511           0 :                                 continue;               /* extra spaces */
     512             :                         }
     513             :                         break;
     514             :                 }
     515         795 :                 spacy = GDKisspace(*pat);
     516         795 :                 pat++;
     517             :         }
     518       23982 :         return (hit >= min) ? hit : 0;
     519             : }
     520             : 
     521             : static ssize_t
     522         319 : parse_substr(int *ret, const char *s, size_t min, const char *list[], int size)
     523             : {
     524         319 :         ssize_t j = 0;
     525         319 :         int i = 0;
     526             : 
     527         319 :         *ret = int_nil;
     528        2106 :         while (++i <= size) {
     529        1998 :                 if ((j = fleximatch(s, list[i], min)) > 0) {
     530         211 :                         *ret = i;
     531         211 :                         break;
     532             :                 }
     533             :         }
     534         319 :         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      581643 : parse_date(const char *buf, date *d, bool external)
     544             : {
     545      581643 :         int day = 0, month = int_nil;
     546      581643 :         int year = 0;
     547      581643 :         bool yearneg, yearlast = false;
     548      581643 :         ssize_t pos = 0;
     549      581643 :         int sep;
     550             : 
     551      581643 :         *d = date_nil;
     552      581643 :         if (strNil(buf))
     553             :                 return 1;
     554      581640 :         if (external && strncmp(buf, "nil", 3) == 0)
     555             :                 return 3;
     556      581640 :         if ((yearneg = (buf[0] == '-')))
     557           9 :                 pos++;
     558      581640 :         if (!yearneg && !GDKisdigit(buf[pos])) {
     559             :                 yearlast = true;
     560             :                 sep = ' ';
     561             :         } else {
     562     2899194 :                 for (; GDKisdigit(buf[pos]); pos++) {
     563     2317730 :                         year = (buf[pos] - '0') + year * 10;
     564     2317730 :                         if (year > YEAR_MAX)
     565             :                                 break;
     566             :                 }
     567      581484 :                 sep = (unsigned char) buf[pos++];
     568      581484 :                 sep = tolower(sep);
     569      581484 :                 if (sep >= 'a' && sep <= 'z') {
     570             :                         sep = 0;
     571      581499 :                 } else if (sep == ' ') {
     572          14 :                         while (buf[pos] == ' ')
     573           0 :                                 pos++;
     574      581485 :                 } else if (sep != '-' && sep != '/' && sep != '\\') {
     575          47 :                         GDKerror("Syntax error in date.\n");
     576          47 :                         return -1;
     577             :                 }
     578             :         }
     579      581593 :         if (GDKisdigit(buf[pos])) {
     580      581274 :                 month = buf[pos++] - '0';
     581      581274 :                 if (GDKisdigit(buf[pos])) {
     582      584784 :                         month = (buf[pos++] - '0') + month * 10;
     583             :                 }
     584             :         } else {
     585         319 :                 pos += parse_substr(&month, buf + pos, 3, MONTHS, 12);
     586             :         }
     587      581593 :         if (is_int_nil(month) || (sep && buf[pos++] != sep)) {
     588         115 :                 GDKerror("Syntax error in date.\n");
     589         115 :                 return -1;
     590             :         }
     591      585252 :         if (sep == ' ') {
     592         201 :                 while (buf[pos] == ' ')
     593           0 :                         pos++;
     594             :         }
     595      581478 :         if (!GDKisdigit(buf[pos])) {
     596           4 :                 GDKerror("Syntax error in date.\n");
     597           4 :                 return -1;
     598             :         }
     599     1752099 :         while (GDKisdigit(buf[pos])) {
     600     1170650 :                 day = (buf[pos++] - '0') + day * 10;
     601     1170650 :                 if (day > 31)
     602             :                         break;
     603             :         }
     604      581474 :         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      581474 :         if (!yearneg && buf[pos] == ' ') {
     618             :                 ssize_t opos = pos;
     619       19165 :                 while (buf[++pos] == ' ')
     620             :                         ;
     621       19165 :                 if (strncasecmp(buf + pos, "BCE", 3) == 0) {
     622             :                         /* Before Common Era */
     623           0 :                         yearneg = true;
     624           0 :                         pos += 3;
     625       19165 :                 } else if (strncasecmp(buf + pos, "BC", 2) == 0) {
     626             :                         /* Before Christ */
     627          13 :                         yearneg = true;
     628          13 :                         pos += 2;
     629       19152 :                 } else if (strncasecmp(buf + pos, "CE", 2) == 0) {
     630             :                         /* Common Era */
     631           0 :                         pos += 2;
     632       19152 :                 } 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      581474 :         *d = date_create(yearneg ? -year : year, month, day);
     641      581474 :         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      563958 : date_fromstr(const char *buf, size_t *len, date **d, bool external)
     650             : {
     651      563958 :         if (*len < sizeof(date) || *d == NULL) {
     652        2441 :                 GDKfree(*d);
     653        2441 :                 *d = (date *) GDKmalloc(*len = sizeof(date));
     654        2441 :                 if( *d == NULL)
     655             :                         return -1;
     656             :         }
     657      563958 :         ssize_t n = 0;
     658      563958 :         while (buf[n] && GDKisspace(buf[n]))
     659           0 :                 n++;
     660      563958 :         ssize_t l = parse_date(buf + n, *d, external);
     661      564997 :         if (l < 0)
     662             :                 return l;
     663      564957 :         n += l;
     664      564959 :         while (buf[n] && GDKisspace(buf[n]))
     665           2 :                 n++;
     666             :         return n;
     667             : }
     668             : 
     669             : static ssize_t
     670        5720 : do_date_tostr(char *buf, size_t len, const date *val, bool external)
     671             : {
     672        5720 :         assert(len >= 15);
     673        5720 :         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        5719 :         return (ssize_t) snprintf(buf, len, "%d-%02d-%02d",
     682        5719 :                                   date_extract_year(*val),
     683        5719 :                                   date_extract_month(*val),
     684             :                                   date_extract_day(*val));
     685             : }
     686             : 
     687             : ssize_t
     688        5043 : date_tostr(str *buf, size_t *len, const date *val, bool external)
     689             : {
     690             :         /* 15 bytes is more than enough */
     691        5043 :         if (*len < 15 || *buf == NULL) {
     692          21 :                 GDKfree(*buf);
     693          21 :                 *buf = GDKmalloc(15);
     694          23 :                 if( *buf == NULL)
     695             :                         return -1;
     696          23 :                 *len = 15;
     697             :         }
     698        5045 :         return do_date_tostr(*buf, *len, val, external);
     699             : }
     700             : 
     701             : static ssize_t
     702       21907 : parse_daytime(const char *buf, daytime *dt, bool external)
     703             : {
     704       21907 :         unsigned int hour, min, sec = 0, usec = 0;
     705       21907 :         int n1, n2;
     706       21907 :         ssize_t pos = 0;
     707             : 
     708       21907 :         *dt = daytime_nil;
     709       21907 :         if (strNil(buf))
     710             :                 return 1;
     711       21907 :         if (external && strncmp(buf, "nil", 3) == 0)
     712             :                 return 3;
     713             :         /* accept plenty (6) of digits, but the range is still limited */
     714       21907 :         switch (sscanf(buf, "%6u:%6u%n:%6u%n", &hour, &min, &n1, &sec, &n2)) {
     715          16 :         default:
     716          16 :                 GDKerror("Syntax error in time.\n");
     717          16 :                 return -1;
     718         251 :         case 2:
     719             :                 /* read hour and min, but not sec */
     720         251 :                 if (hour >= 24 || min >= 60) {
     721           0 :                         GDKerror("Syntax error in time.\n");
     722           0 :                         return -1;
     723             :                 }
     724         251 :                 pos += n1;
     725         251 :                 break;
     726       21640 :         case 3:
     727             :                 /* read hour, min, and sec */
     728       21640 :                 if (hour >= 24 || min >= 60 || sec > 60) {
     729           0 :                         GDKerror("Syntax error in time.\n");
     730           0 :                         return -1;
     731             :                 }
     732       21640 :                 pos += n2;
     733       21640 :                 if (buf[pos] == '.' && GDKisdigit(buf[pos+1])) {
     734       18454 :                         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       18454 :                         pos += n1 + 1;
     740       19512 :                         while (n1 < 6) {
     741        1058 :                                 usec *= 10;
     742        1058 :                                 n1++;
     743             :                         }
     744       18454 :                         if (n1 == 7) {
     745             : #ifdef TRUNCATE_NUMBERS
     746             :                                 usec /= 10;
     747             : #else
     748           0 :                                 usec = (usec + 5) / 10;
     749           0 :                                 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       18454 :                         while (GDKisdigit(buf[pos]))
     768           0 :                                 pos++;
     769             :                 }
     770             :                 break;
     771             :         }
     772       21891 :         *dt = daytime_create(hour, min, sec, usec);
     773       21891 :         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        2750 : daytime_fromstr(const char *buf, size_t *len, daytime **ret, bool external)
     782             : {
     783        2750 :         if (*len < sizeof(daytime) || *ret == NULL) {
     784           5 :                 GDKfree(*ret);
     785           5 :                 *ret = (daytime *) GDKmalloc(*len = sizeof(daytime));
     786           5 :                 if (*ret == NULL)
     787             :                         return -1;
     788             :         }
     789        2750 :         ssize_t n = 0;
     790        2754 :         while (buf[n] && GDKisspace(buf[n]))
     791           4 :                 n++;
     792        2750 :         ssize_t l = parse_daytime(buf + n, *ret, external);
     793        2750 :         if (l < 0)
     794             :                 return l;
     795        2734 :         n += l;
     796        2770 :         while (buf[n] && GDKisspace(buf[n]))
     797          36 :                 n++;
     798             :         return n;
     799             : }
     800             : 
     801             : static ssize_t
     802        2747 : daytime_tz_fromstr_internal(const char *buf, size_t *len, daytime **ret, long tz_sec, bool tzlocal, bool external)
     803             : {
     804        2747 :         const char *s = buf;
     805        2747 :         ssize_t pos;
     806        2747 :         daytime val;
     807        2747 :         int offset = 0;
     808        2747 :         bool has_tz = false;
     809             : 
     810        2747 :         pos = daytime_fromstr(s, len, ret, external);
     811        2747 :         if (pos < 0 || is_daytime_nil(**ret))
     812             :                 return pos;
     813             : 
     814        2731 :         s = buf + pos;
     815        2731 :         pos = 0;
     816        2731 :         while (GDKisspace(*s))
     817           0 :                 s++;
     818             :         /* for GMT we need to add the time zone */
     819        2731 :         if (fleximatch(s, "gmt", 0) == 3) {
     820           0 :                 s += 3;
     821             :         }
     822        2731 :         if ((s[0] == '-' || s[0] == '+') &&
     823          49 :             GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     824          33 :             ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     825          33 :                 offset = (((s[1] - '0') * 10 + (s[2] - '0')) * 60 + (s[pos] - '0') * 10 + (s[pos + 1] - '0')) * 60;
     826          33 :                 pos += 2;
     827          33 :                 if (s[0] == '+')
     828          29 :                         offset = -offset;       /* East of Greenwich */
     829          33 :                 s += pos;
     830          33 :                 has_tz = true;
     831             :         }
     832        2731 :         val = **ret;
     833        2731 :         (void)tz_sec;
     834        2731 :         if (!tzlocal && has_tz) /* convert into utc */
     835          33 :                 val += offset * LL_CONSTANT(1000000);
     836        2731 :         if (!tzlocal && !has_tz) /* convert into utc */
     837         360 :                 val -= tz_sec * LL_CONSTANT(1000000);
     838        2731 :         if (val < 0)
     839          10 :                 val += DAY_USEC;
     840        2721 :         else if (val >= DAY_USEC)
     841           0 :                 val -= DAY_USEC;
     842             :         /* and return */
     843        2731 :         **ret = val;
     844        2731 :         while (*s && GDKisspace(*s))
     845           0 :                 s++;
     846        2731 :         return (ssize_t) (s - buf);
     847             : }
     848             : 
     849             : ssize_t
     850         319 : daytime_tz_fromstr(const char *buf, size_t *len, daytime **ret, bool external)
     851             : {
     852         319 :         return daytime_tz_fromstr_internal(buf, len, ret, 0, false, external);
     853             : }
     854             : 
     855             : ssize_t
     856        2428 : sql_daytime_fromstr(const char *buf, daytime *ret, long tz_sec, bool tclocal)
     857             : {
     858        2428 :         size_t len = sizeof(daytime);
     859        2428 :         return daytime_tz_fromstr_internal(buf, &len, &ret, tz_sec, tclocal, false);
     860             : }
     861             : 
     862             : static ssize_t
     863        4820 : do_daytime_precision_tostr(char *buf, size_t len, const daytime dt,
     864             :                            int precision, bool external)
     865             : {
     866        4820 :         int hour, min, sec, usec;
     867             : 
     868        4820 :         if (precision < 0)
     869             :                 precision = 0;
     870        4820 :         if (len < 10 + (size_t) precision) {
     871             :                 return -1;
     872             :         }
     873        4820 :         if (is_daytime_nil(dt)) {
     874           0 :                 if (external) {
     875           0 :                         strcpy(buf, "nil");
     876           0 :                         return 3;
     877             :                 }
     878           0 :                 strcpy(buf, str_nil);
     879           0 :                 return 1;
     880             :         }
     881        4820 :         usec = (int) (dt % 1000000);
     882        4820 :         sec = (int) (dt / 1000000);
     883        4820 :         hour = sec / 3600;
     884        4820 :         min = (sec % 3600) / 60;
     885        4820 :         sec %= 60;
     886             : 
     887        4820 :         if (precision == 0)
     888        2512 :                 return snprintf(buf, len, "%02d:%02d:%02d", hour, min, sec);
     889        2308 :         else if (precision < 6) {
     890        2800 :                 for (int i = 6; i > precision; i--)
     891        2095 :                         usec /= 10;
     892             : #if defined(__GNUC__) && __GNUC__ < 9 && __GNUC__ > 4
     893             : /* the %0*d format gives an incorrect warning in gcc on at least gcc 8.3.1
     894             :  * old gcc (at least 4.8.5) does not have the option */
     895             : GCC_Pragma("GCC diagnostic ignored \"-Wformat-truncation\"")
     896             : #endif
     897         705 :                 return snprintf(buf, len, "%02d:%02d:%02d.%0*d", hour, min, sec, precision, usec);
     898             :         } else {
     899        1603 :                 ssize_t l = snprintf(buf, len, "%02d:%02d:%02d.%06d", hour, min, sec, usec);
     900        1603 :                 while (precision > 6) {
     901           0 :                         precision--;
     902           0 :                         buf[l++] = '0';
     903             :                 }
     904        1603 :                 buf[l] = '\0';
     905        1603 :                 return l;
     906             :         }
     907             : }
     908             : 
     909             : ssize_t
     910        4145 : daytime_precision_tostr(str *buf, size_t *len, const daytime dt,
     911             :                         int precision, bool external)
     912             : {
     913        4145 :         if (precision < 0)
     914             :                 precision = 0;
     915        4145 :         if (*len < 10 + (size_t) precision || *buf == NULL) {
     916           5 :                 GDKfree(*buf);
     917           5 :                 *buf = (str) GDKmalloc(*len = 10 + (size_t) precision);
     918           5 :                 if( *buf == NULL)
     919             :                         return -1;
     920             :         }
     921        4145 :         return do_daytime_precision_tostr(*buf, *len, dt, precision, external);
     922             : }
     923             : 
     924             : ssize_t
     925          11 : daytime_tostr(str *buf, size_t *len, const daytime *val, bool external)
     926             : {
     927          11 :         return daytime_precision_tostr(buf, len, *val, 6, external);
     928             : }
     929             : 
     930             : static ssize_t
     931       19596 : timestamp_fromstr_internal(const char *buf, size_t *len, timestamp **ret, bool external, bool parse_offset)
     932             : {
     933       19596 :         const char *s = buf;
     934       19596 :         ssize_t pos;
     935       19596 :         date dt;
     936       19596 :         daytime tm;
     937             : 
     938       19596 :         if (*len < sizeof(timestamp) || *ret == NULL) {
     939           0 :                 GDKfree(*ret);
     940           0 :                 *ret = (timestamp *) GDKmalloc(*len = sizeof(timestamp));
     941           0 :                 if (*ret == NULL)
     942             :                         return -1;
     943             :         }
     944       19596 :         while (*s && GDKisspace(*s))
     945           0 :                 s++;
     946       19596 :         pos = parse_date(s, &dt, external);
     947       19596 :         if (pos < 0)
     948             :                 return pos;
     949       19423 :         if (is_date_nil(dt)) {
     950           0 :                 **ret = timestamp_nil;
     951           0 :                 return pos;
     952             :         }
     953       19423 :         s += pos;
     954       19423 :         if (*s == '@' || *s == ' ' || *s == '-' || *s == 'T') {
     955       19157 :                 while (*++s == ' ')
     956             :                         ;
     957       19157 :                 pos = parse_daytime(s, &tm, external);
     958       19157 :                 if (pos < 0)
     959             :                         return pos;
     960       19157 :                 s += pos;
     961       19157 :                 if (is_daytime_nil(tm)) {
     962           0 :                         **ret = timestamp_nil;
     963           0 :                         return (ssize_t) (s - buf);
     964             :                 }
     965         266 :         } else if (*s) {
     966         170 :                 tm = daytime_nil;
     967             :         } else {
     968          96 :                 tm = mkdaytime(0, 0, 0, 0);
     969             :         }
     970       19423 :         if (is_date_nil(dt) || is_daytime_nil(tm)) {
     971         170 :                 **ret = timestamp_nil;
     972             :         } else {
     973       19253 :                 lng offset = 0;
     974             : 
     975       19253 :                 **ret = mktimestamp(dt, tm);
     976       19253 :                 if (parse_offset) {
     977       18551 :                         while (GDKisspace(*s))
     978          10 :                                 s++;
     979             :                         /* in case of gmt we need to add the time zone */
     980       18541 :                         if (fleximatch(s, "gmt", 0) == 3) {
     981           3 :                                 s += 3;
     982             :                         }
     983       18541 :                         if ((s[0] == '-' || s[0] == '+') &&
     984          20 :                                 GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
     985          17 :                                 ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
     986          17 :                                 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);
     987          17 :                                 pos += 2;
     988          17 :                                 if (s[0] != '-')
     989          13 :                                         offset = -offset;
     990          17 :                                 s += pos;
     991             :                         }
     992       18541 :                         **ret = timestamp_add_usec(**ret, offset);
     993             :                 }
     994             :         }
     995       19461 :         while (*s && GDKisspace(*s))
     996          38 :                 s++;
     997       19423 :         return (ssize_t) (s - buf);
     998             : }
     999             : 
    1000             : ssize_t
    1001       18601 : timestamp_fromstr(const char *buf, size_t *len, timestamp **ret, bool external)
    1002             : {
    1003       18601 :         return timestamp_fromstr_internal(buf, len, ret, external, true);
    1004             : }
    1005             : 
    1006             : static ssize_t
    1007         995 : timestamp_tz_fromstr_internal(const char *buf, size_t *len, timestamp **ret, long tz_sec, bool tzlocal, bool external)
    1008             : {
    1009         995 :         const char *s = buf;
    1010         995 :         ssize_t pos = timestamp_fromstr_internal(s, len, ret, external, false);
    1011         995 :         lng offset = 0;
    1012         995 :         bool has_tz = false;
    1013             : 
    1014         995 :         if (pos < 0 || is_timestamp_nil(**ret))
    1015             :                 return pos;
    1016             : 
    1017         712 :         s = buf + pos;
    1018         712 :         pos = 0;
    1019         712 :         while (GDKisspace(*s))
    1020           0 :                 s++;
    1021             :         /* in case of gmt we need to add the time zone */
    1022         712 :         if (fleximatch(s, "gmt", 0) == 3) {
    1023          14 :                 s += 3;
    1024             :         }
    1025         712 :         if ((s[0] == '-' || s[0] == '+') &&
    1026          53 :             GDKisdigit(s[1]) && GDKisdigit(s[2]) && GDKisdigit(s[pos = 4]) &&
    1027          41 :             ((s[3] == ':' && GDKisdigit(s[5])) || GDKisdigit(s[pos = 3]))) {
    1028          41 :                 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);
    1029          41 :                 pos += 2;
    1030          41 :                 if (s[0] != '-')
    1031          26 :                         offset = -offset;
    1032          41 :                 s += pos;
    1033          41 :                 has_tz = true;
    1034             :         }
    1035         712 :         if (!tzlocal && has_tz) /* convert into utc */
    1036          33 :                 **ret = timestamp_add_usec(**ret, offset);
    1037         712 :         if (!tzlocal && !has_tz)
    1038          86 :                 **ret = timestamp_add_usec(**ret, -tz_sec * LL_CONSTANT(1000000));
    1039         716 :         while (*s && GDKisspace(*s))
    1040           4 :                 s++;
    1041         712 :         return (ssize_t) (s - buf);
    1042             : }
    1043             : 
    1044             : ssize_t
    1045           0 : timestamp_tz_fromstr(const char *buf, size_t *len, timestamp **ret, bool external)
    1046             : {
    1047           0 :         return timestamp_tz_fromstr_internal(buf, len, ret, 0, false, external);
    1048             : }
    1049             : 
    1050             : /* timestamp from str (return timestamp in local time */
    1051             : ssize_t
    1052         995 : sql_timestamp_fromstr(const char *buf, timestamp *ret, long tz_sec, bool tzlocal)
    1053             : {
    1054         995 :         size_t len = sizeof(timestamp);
    1055         995 :         return timestamp_tz_fromstr_internal(buf, &len, &ret, tz_sec, tzlocal, false);
    1056             : }
    1057             : 
    1058             : ssize_t
    1059         678 : timestamp_precision_tostr(str *buf, size_t *len, timestamp val, int precision, bool external)
    1060             : {
    1061         678 :         ssize_t len1, len2;
    1062         678 :         char buf1[128], buf2[128];
    1063         678 :         date dt;
    1064         678 :         daytime tm;
    1065             : 
    1066         678 :         if (is_timestamp_nil(val)) {
    1067           3 :                 if (*len < 4 || *buf == NULL) {
    1068           3 :                         GDKfree(*buf);
    1069           3 :                         *buf = GDKmalloc(*len = 4);
    1070           3 :                         if( *buf == NULL)
    1071             :                                 return -1;
    1072             :                 }
    1073           3 :                 if (external) {
    1074           3 :                         strcpy(*buf, "nil");
    1075           3 :                         return 3;
    1076             :                 }
    1077           0 :                 strcpy(*buf, str_nil);
    1078           0 :                 return 1;
    1079             :         }
    1080             : 
    1081         675 :         dt = ts_date(val);
    1082         675 :         tm = ts_time(val);
    1083         675 :         len1 = do_date_tostr(buf1, sizeof(buf1), &dt, false);
    1084         675 :         len2 = do_daytime_precision_tostr(buf2, sizeof(buf2), tm,
    1085             :                                           precision, false);
    1086         675 :         if (len1 < 0 || len2 < 0)
    1087             :                 return -1;
    1088             : 
    1089         675 :         if (*len < 2 + (size_t) len1 + (size_t) len2 || *buf == NULL) {
    1090         672 :                 GDKfree(*buf);
    1091         672 :                 *buf = GDKmalloc(*len = (size_t) len1 + (size_t) len2 + 2);
    1092         672 :                 if( *buf == NULL)
    1093             :                         return -1;
    1094             :         }
    1095         675 :         return (ssize_t) strconcat_len(*buf, *len, buf1, " ", buf2, NULL);
    1096             : }
    1097             : 
    1098             : ssize_t
    1099         678 : timestamp_tostr(str *buf, size_t *len, const timestamp *val, bool external)
    1100             : {
    1101         678 :         return timestamp_precision_tostr(buf, len, *val, 6, external);
    1102             : }

Generated by: LCOV version 1.14