Changeset: 3b77f54d2fd6 for MonetDB URL: https://dev.monetdb.org/hg/MonetDB/rev/3b77f54d2fd6 Added Files: sql/test/BugTracker-2024/Tests/7570-timestamp-str.test Modified Files: gdk/gdk_select.c monetdb5/modules/atoms/mtime.c monetdb5/modules/atoms/strptime.c sql/test/BugTracker-2024/Tests/All Branch: Aug2024 Log Message:
Imported newever version of strptime + made some changes to it. Also some changes in how strptime is used in that the timezone offset is filled in before the call and then used after to adjust the timestamp. The call only changes the timezone offset if it was getting parsed. This fixes #7570. diffs (truncated from 1297 to 300 lines): diff --git a/gdk/gdk_select.c b/gdk/gdk_select.c --- a/gdk/gdk_select.c +++ b/gdk/gdk_select.c @@ -647,7 +647,7 @@ NAME##_##TYPE(BATiter *bi, struct candit hval = true; \ } \ if (vl > vh) { \ - *algo = "select: empty range"; \ + *algo = "select: empty range"; \ return 0; \ } \ } \ diff --git a/monetdb5/modules/atoms/mtime.c b/monetdb5/modules/atoms/mtime.c --- a/monetdb5/modules/atoms/mtime.c +++ b/monetdb5/modules/atoms/mtime.c @@ -39,6 +39,7 @@ #ifndef HAVE_STRPTIME extern char *strptime(const char *, const char *, struct tm *); +extern char *strptime2(const char *, const char *, struct tm *, int *); #endif /* interfaces callable from MAL, not used from any C code */ @@ -1169,16 +1170,24 @@ static str str_to_timestamp(timestamp *ret, const char *const *s, const char *const *format, const long gmtoff, const char *type, const char *malfunc) { - struct tm tm = (struct tm) { 0 }; + struct tm tm = (struct tm) { + .tm_isdst = -1, + .tm_mday = 1, +#ifdef HAVE_TM_GMTOFF + .tm_gmtoff = (int) gmtoff, +#endif + }; + int tz = (int) gmtoff; if (strNil(*s) || strNil(*format)) { *ret = timestamp_nil; return MAL_SUCCEED; } - tm.tm_sec = tm.tm_min = tm.tm_hour = 0; - tm.tm_isdst = -1; - tm.tm_mday = 1; +#ifdef HAVE_STRPTIME if (strptime(*s, *format, &tm) == NULL) +#else + if (strptime2(*s, *format, &tm, &tz) == NULL) +#endif throw(MAL, malfunc, "format '%s', doesn't match %s '%s'", *format, type, *s); *ret = timestamp_create(date_create(tm.tm_year + 1900, @@ -1188,26 +1197,10 @@ str_to_timestamp(timestamp *ret, const c tm.tm_min, tm.tm_sec == 60 ? 59 : tm.tm_sec, 0)); - /* if strptime filled in DST information (tm_isdst >= 0), then the - * time is in system local time and we convert to GMT by - * subtracting the time zone offset, else we don't touch the time - * returned because it is assumed to already be in GMT */ - if (tm.tm_isdst >= 0) { - int isdst = 0; - int tz = local_timezone(&isdst); - /* if strptime's information doesn't square with our own - * information about having or not having DST, we compensate - * an hour */ - if (tm.tm_isdst > 0 && isdst == 0) { - tz += 3600; - } else if (tm.tm_isdst == 0 && isdst > 0) { - tz -= 3600; - } - - *ret = timestamp_add_usec(*ret, -tz * LL_CONSTANT(1000000)); - } else { - *ret = timestamp_add_usec(*ret, -gmtoff * LL_CONSTANT(1000000)); - } +#ifdef HAVE_TM_GMTOFF + tz = tm.tm_gmtoff; +#endif + *ret = timestamp_add_usec(*ret, -tz * LL_CONSTANT(1000000)); if (is_timestamp_nil(*ret)) throw(MAL, malfunc, "bad %s '%s'", type, *s); return MAL_SUCCEED; diff --git a/monetdb5/modules/atoms/strptime.c b/monetdb5/modules/atoms/strptime.c --- a/monetdb5/modules/atoms/strptime.c +++ b/monetdb5/modules/atoms/strptime.c @@ -1,12 +1,15 @@ -/* Adapted from https://opensource.apple.com/source/lukemftp/lukemftp-3/lukemftp/libukem/strptime.c */ -/* $Id$ */ -/* $NetBSD: strptime.c,v 1.18 1999/04/29 02:58:30 tv Exp $ */ - +/* Adapted from https://github.com/res2001/strptime/blob/master/strptime.c */ +/* $NetBSD: strptime.c,v 1.62 2017/08/24 01:01:09 ginsbach Exp $ */ +/* http://cvsweb.netbsd.org/bsdweb.cgi/~checkout~/src/lib/libc/time/strptime.c?only_with_tag=HEAD + * NetBSD implementation strptime(). + * Format description: https://netbsd.gw.com/cgi-bin/man-cgi?strptime+3+NetBSD-current +*/ /*- - * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. + * Copyright (c) 1997, 1998, 2005, 2008 The NetBSD Foundation, Inc. * All rights reserved. * * This code was contributed to The NetBSD Foundation by Klaus Klein. + * Heavily optimised by David Laight * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -16,13 +19,6 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the NetBSD - * Foundation, Inc. and its contributors. - * 4. Neither the name of The NetBSD Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED @@ -37,14 +33,31 @@ * POSSIBILITY OF SUCH DAMAGE. */ +/* changes made for MonetDB: + * changed strptime to strptime2, adding extra argument to return gmtoff + * (since Windows doesn't support tm_gmtoff, there was no other way of + * returning that information); + * added include of monetdb_config.h + undef of strncasecmp, added + * define for timezone. + */ #include "monetdb_config.h" -#include "gdk.h" -#include <time.h> +#ifndef HAVE_STRPTIME +#undef strncasecmp +#ifdef _MSC_VER +#define timezone _timezone +#endif + +//#include <sys/cdefs.h> +//__RCSID("$NetBSD: strptime.c,v 1.62 2017/08/24 01:01:09 ginsbach Exp $"); + #include <ctype.h> #include <string.h> +#include <time.h> +#include <stdint.h> -#ifdef WIN32 +static const unsigned char *conv_num(const unsigned char *, int *, unsigned int, unsigned int); +static const unsigned char *find_string(const unsigned char *, int *, const char * const *, const char * const *, int); /* * We do not implement alternate representations. However, we always @@ -54,326 +67,812 @@ #define ALT_O 0x02 #define LEGAL_ALT(x) { if (alt_format & ~(x)) return NULL; } -#ifndef TM_YEAR_BASE -#define TM_YEAR_BASE 1900 +#define TM_YEAR_BASE 1900 + +#define TM_SUNDAY 0 +#define TM_MONDAY 1 +#define TM_TUESDAY 2 +#define TM_WEDNESDAY 3 +#define TM_THURSDAY 4 +#define TM_FRIDAY 5 +#define TM_SATURDAY 6 + +#define S_YEAR (1 << 0) +#define S_MON (1 << 1) +#define S_YDAY (1 << 2) +#define S_MDAY (1 << 3) +#define S_WDAY (1 << 4) +#define S_HOUR (1 << 5) + +#define HAVE_MDAY(s) (s & S_MDAY) +#define HAVE_MON(s) (s & S_MON) +#define HAVE_WDAY(s) (s & S_WDAY) +#define HAVE_YDAY(s) (s & S_YDAY) +#define HAVE_YEAR(s) (s & S_YEAR) +#define HAVE_HOUR(s) (s & S_HOUR) + +#define SECSPERMIN 60 +#define MINSPERHOUR 60 +#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) +#define HOURSPERDAY 24 + +#define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" +#define HERE_D_FMT "%y/%m/%d" +#define HERE_T_FMT_AMPM "%I:%M:%S %p" +#define HERE_T_FMT "%H:%M:%S" + +#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) + +/* +** Since everything in isleap is modulo 400 (or a factor of 400), we know that +** isleap(y) == isleap(y % 400) +** and so +** isleap(a + b) == isleap((a + b) % 400) +** or +** isleap(a + b) == isleap(a % 400 + b % 400) +** This is true even if % means modulo rather than Fortran remainder +** (which is allowed by C89 but not by C99 or later). +** We use this to avoid addition overflow problems. +*/ + +#define isleap_sum(a, b) isleap((a) % 400 + (b) % 400) + +#ifdef _MSC_VER +#define tzname _tzname +#define strncasecmp _strnicmp #endif -static const char *day[7] = - { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", -"Saturday" }; - -static const char *abday[7] = - { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; +#ifdef TM_ZONE +static char* utc = "UTC"; +#endif +/* RFC-822/RFC-2822 */ +static const char* const nast[] = { + "EST", "CST", "MST", "PST", "\0\0\0" +}; +static const char* const nadt[] = { + "EDT", "CDT", "MDT", "PDT", "\0\0\0" +}; +static const char* weekday_name[] = +{ + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" +}; +static const char* ab_weekday_name[] = +{ + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" +}; +static const char* month_name[] = +{ + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" +}; +static const char* ab_month_name[] = +{ + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; +static const char* am_pm[] = {"AM", "PM"}; -static const char *mon[12] = - { "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - }; -static const char *abmon[12] = - { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; +/* + * Table to determine the ordinal date for the start of a month. + * Ref: http://en.wikipedia.org/wiki/ISO_week_date + */ +static const int start_of_month[2][13] = { + /* non-leap year */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* leap year */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } +}; -static const char *am_pm[2] = { "am", "pm" }; +/* + * Calculate the week day of the first day of a year. Valid for + * the Gregorian calendar, which began Sept 14, 1752 in the UK + * and its colonies. Ref: + * http://en.wikipedia.org/wiki/Determination_of_the_day_of_the_week + */ static int -strptime_conv_num(const char **buf, int *dest, int llim, int ulim) +first_wday_of(int yr) { - int result = 0; + return ((2 * (3 - (yr / 100) % 4)) + (yr % 100) + ((yr % 100) / 4) + + (isleap(yr) ? 6 : 0) + 1) % 7; +} + +#define delim(p) ((p) == '\0' || isspace((unsigned char)(p))) - /* The limit also determines the number of valid digits. */ - int rulim = ulim; +static int +fromzone(const unsigned char **bp, struct tm *tm, int mandatory) +{ +// timezone_t tz; + char buf[512], *p; + const unsigned char *rp; _______________________________________________ checkin-list mailing list -- checkin-list@monetdb.org To unsubscribe send an email to checkin-list-le...@monetdb.org