mirror of
https://git.savannah.gnu.org/git/gnulib.git
synced 2025-08-08 17:22:05 +03:00
parse-datetime: handle timezones reentrantly
This API change was prompted by a report by Pádraig Brady in: https://bug.debian.org/851934#10 To help fix the bug, make parse_datetime2 more reentrant. * NEWS: Document this incompatible change. * lib/parse-datetime.h, lib/parse-datetime.y (parse_datetime2): Add two arguments, the timezone and the timezone name. All callers changed. If TZ="..." is specified, use it for calculating defaults. * lib/parse-datetime.y: Don't include xalloc.h or use xmalloc, as this code should be usable in a library. (mktime_ok, get_effective_timezone): Accept timezone arg too. All callers changed. (get_tz): Remove. (get_effective_timezone): Check for failures. * modules/parse-datetime: Add time_r, time_rz. Remove xalloc.
This commit is contained in:
18
ChangeLog
18
ChangeLog
@@ -1,3 +1,21 @@
|
|||||||
|
2017-01-20 Paul Eggert <eggert@cs.ucla.edu>
|
||||||
|
|
||||||
|
parse-datetime: handle timezones reentrantly
|
||||||
|
This API change was prompted by a report by Pádraig Brady in:
|
||||||
|
https://bug.debian.org/851934#10
|
||||||
|
To help fix the bug, make parse_datetime2 more reentrant.
|
||||||
|
* NEWS: Document this incompatible change.
|
||||||
|
* lib/parse-datetime.h, lib/parse-datetime.y (parse_datetime2):
|
||||||
|
Add two arguments, the timezone and the timezone name.
|
||||||
|
All callers changed. If TZ="..." is specified, use it for
|
||||||
|
calculating defaults.
|
||||||
|
* lib/parse-datetime.y: Don't include xalloc.h or use xmalloc, as
|
||||||
|
this code should be usable in a library.
|
||||||
|
(mktime_ok, get_effective_timezone):
|
||||||
|
Accept timezone arg too. All callers changed.
|
||||||
|
(get_tz): Remove.
|
||||||
|
(get_effective_timezone): Check for failures.
|
||||||
|
|
||||||
2017-01-20 Eric Blake <eblake@redhat.com>
|
2017-01-20 Eric Blake <eblake@redhat.com>
|
||||||
|
|
||||||
localename: port to cygwin 2.6
|
localename: port to cygwin 2.6
|
||||||
|
4
NEWS
4
NEWS
@@ -42,6 +42,10 @@ User visible incompatible changes
|
|||||||
|
|
||||||
Date Modules Changes
|
Date Modules Changes
|
||||||
|
|
||||||
|
2017-01-20 parse-datetime The parse_datetime2 function now takes two
|
||||||
|
more arguments TZ and TZSTRING, for the
|
||||||
|
time zone and its name.
|
||||||
|
|
||||||
2017-01-16 host-cpu-c-abi On ARM platforms, HOST_CPU_C_ABI is now set to
|
2017-01-16 host-cpu-c-abi On ARM platforms, HOST_CPU_C_ABI is now set to
|
||||||
'arm' or 'armhf' instead of 'armel'.
|
'arm' or 'armhf' instead of 'armel'.
|
||||||
|
|
||||||
|
@@ -26,4 +26,4 @@ bool parse_datetime (struct timespec *, char const *, struct timespec const *);
|
|||||||
|
|
||||||
/* same as above, supporting additional flags */
|
/* same as above, supporting additional flags */
|
||||||
bool parse_datetime2 (struct timespec *, char const *, struct timespec const *,
|
bool parse_datetime2 (struct timespec *, char const *, struct timespec const *,
|
||||||
unsigned int flags);
|
unsigned int flags, timezone_t, char const *);
|
||||||
|
@@ -68,7 +68,6 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "gettext.h"
|
#include "gettext.h"
|
||||||
#include "xalloc.h"
|
|
||||||
|
|
||||||
#define _(str) gettext (str)
|
#define _(str) gettext (str)
|
||||||
|
|
||||||
@@ -1531,19 +1530,21 @@ yyerror (parser_control const *pc _GL_UNUSED,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If *TM0 is the old and *TM1 is the new value of a struct tm after
|
/* In timezone TZ, if *TM0 is the old and *TM1 is the new value of a
|
||||||
passing it to mktime, return true if it's OK that mktime returned T.
|
struct tm after passing it to mktime_z, return true if it's OK that
|
||||||
It's not OK if *TM0 has out-of-range members. */
|
mktime_z returned T. It's not OK if *TM0 has out-of-range
|
||||||
|
members. */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
mktime_ok (struct tm const *tm0, struct tm const *tm1, time_t t)
|
mktime_ok (timezone_t tz, struct tm const *tm0, struct tm const *tm1, time_t t)
|
||||||
{
|
{
|
||||||
|
struct tm ltm;
|
||||||
if (t == (time_t) -1)
|
if (t == (time_t) -1)
|
||||||
{
|
{
|
||||||
/* Guard against falsely reporting an error when parsing a
|
/* Guard against falsely reporting an error when parsing a
|
||||||
timestamp that happens to equal (time_t) -1, on a host that
|
timestamp that happens to equal (time_t) -1, on a host that
|
||||||
supports such a timestamp. */
|
supports such a timestamp. */
|
||||||
tm1 = localtime (&t);
|
tm1 = localtime_rz (tz, &t, <m);
|
||||||
if (!tm1)
|
if (!tm1)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -1564,22 +1565,6 @@ enum { TZBUFSIZE = 100 };
|
|||||||
see days_to_name(), debug_strftime() and debug_mktime_not_ok() */
|
see days_to_name(), debug_strftime() and debug_mktime_not_ok() */
|
||||||
enum { DBGBUFSIZE = 100 };
|
enum { DBGBUFSIZE = 100 };
|
||||||
|
|
||||||
/* Return a copy of TZ, stored in TZBUF if it fits, and heap-allocated
|
|
||||||
otherwise. */
|
|
||||||
static char *
|
|
||||||
get_tz (char tzbuf[TZBUFSIZE])
|
|
||||||
{
|
|
||||||
char *tz = getenv ("TZ");
|
|
||||||
if (tz)
|
|
||||||
{
|
|
||||||
size_t tzsize = strlen (tz) + 1;
|
|
||||||
tz = (tzsize <= TZBUFSIZE
|
|
||||||
? memcpy (tzbuf, tz, tzsize)
|
|
||||||
: xmemdup (tz, tzsize));
|
|
||||||
}
|
|
||||||
return tz;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* debugging: format a 'struct tm' into a buffer, taking the parser's
|
/* debugging: format a 'struct tm' into a buffer, taking the parser's
|
||||||
timezone information into account (if pc!=NULL). */
|
timezone information into account (if pc!=NULL). */
|
||||||
static const char*
|
static const char*
|
||||||
@@ -1708,48 +1693,54 @@ debug_mktime_not_ok (struct tm const *tm0, struct tm const *tm1,
|
|||||||
|
|
||||||
/* Returns the effective local timezone, in minutes. */
|
/* Returns the effective local timezone, in minutes. */
|
||||||
static long int
|
static long int
|
||||||
get_effective_timezone (void)
|
get_effective_timezone (timezone_t tz)
|
||||||
{
|
{
|
||||||
/* TODO: check for failures */
|
time_t z = 0;
|
||||||
const time_t z = 0;
|
struct tm tm;
|
||||||
time_t lz ;
|
if (! localtime_rz (tz, &z, &tm))
|
||||||
struct tm *ltm;
|
return 0;
|
||||||
ltm = localtime (&z);
|
return timegm (&tm) / 60;
|
||||||
lz = timegm (ltm)/60;
|
|
||||||
return (long int)lz;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The original interface: run with debug=false */
|
/* The original interface: run with debug=false and the default timezone. */
|
||||||
bool
|
bool
|
||||||
parse_datetime (struct timespec *result, char const *p,
|
parse_datetime (struct timespec *result, char const *p,
|
||||||
struct timespec const *now)
|
struct timespec const *now)
|
||||||
{
|
{
|
||||||
return parse_datetime2 (result, p, now, 0);
|
char const *tzstring = getenv ("TZ");
|
||||||
|
timezone_t tz = tzalloc (tzstring);
|
||||||
|
if (!tz)
|
||||||
|
return false;
|
||||||
|
bool ok = parse_datetime2 (result, p, now, 0, tz, tzstring);
|
||||||
|
tzfree (tz);
|
||||||
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Parse a date/time string, storing the resulting time value into *RESULT.
|
/* Parse a date/time string, storing the resulting time value into *RESULT.
|
||||||
The string itself is pointed to by P. Return true if successful.
|
The string itself is pointed to by P. Return true if successful.
|
||||||
P can be an incomplete or relative time specification; if so, use
|
P can be an incomplete or relative time specification; if so, use
|
||||||
*NOW as the basis for the returned time. */
|
*NOW as the basis for the returned time. Default to timezone
|
||||||
|
TZDEFAULT, which corresponds to tzalloc (TZSTRING). */
|
||||||
bool
|
bool
|
||||||
parse_datetime2 (struct timespec *result, char const *p,
|
parse_datetime2 (struct timespec *result, char const *p,
|
||||||
struct timespec const *now, unsigned int flags)
|
struct timespec const *now, unsigned int flags,
|
||||||
|
timezone_t tzdefault, char const *tzstring)
|
||||||
{
|
{
|
||||||
time_t Start;
|
time_t Start;
|
||||||
long int Start_ns;
|
long int Start_ns;
|
||||||
struct tm const *tmp;
|
struct tm tmp;
|
||||||
struct tm tm;
|
struct tm tm;
|
||||||
struct tm tm0;
|
struct tm tm0;
|
||||||
parser_control pc;
|
parser_control pc;
|
||||||
struct timespec gettime_buffer;
|
struct timespec gettime_buffer;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
bool tz_was_altered = false;
|
timezone_t tz = tzdefault;
|
||||||
char *tz0 = NULL;
|
|
||||||
char tz0buf[TZBUFSIZE];
|
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
char dbg_ord[DBGBUFSIZE];
|
char dbg_ord[DBGBUFSIZE];
|
||||||
char dbg_tm[DBGBUFSIZE];
|
char dbg_tm[DBGBUFSIZE];
|
||||||
char const *input_sentinel = p + strlen (p);
|
char const *input_sentinel = p + strlen (p);
|
||||||
|
char *tz1alloc = NULL;
|
||||||
|
char tz1buf[TZBUFSIZE];
|
||||||
|
|
||||||
if (! now)
|
if (! now)
|
||||||
{
|
{
|
||||||
@@ -1760,10 +1751,6 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
Start = now->tv_sec;
|
Start = now->tv_sec;
|
||||||
Start_ns = now->tv_nsec;
|
Start_ns = now->tv_nsec;
|
||||||
|
|
||||||
tmp = localtime (&now->tv_sec);
|
|
||||||
if (! tmp)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
while (c = *p, c_isspace (c))
|
while (c = *p, c_isspace (c))
|
||||||
p++;
|
p++;
|
||||||
|
|
||||||
@@ -1782,22 +1769,25 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
}
|
}
|
||||||
else if (*s == '"')
|
else if (*s == '"')
|
||||||
{
|
{
|
||||||
|
timezone_t tz1;
|
||||||
|
char *tz1string = tz1buf;
|
||||||
char *z;
|
char *z;
|
||||||
char *tz1;
|
if (TZBUFSIZE < tzsize)
|
||||||
char tz1buf[TZBUFSIZE];
|
{
|
||||||
bool large_tz = TZBUFSIZE < tzsize;
|
tz1alloc = malloc (tzsize);
|
||||||
bool setenv_ok;
|
if (!tz1alloc)
|
||||||
tz0 = get_tz (tz0buf);
|
goto fail;
|
||||||
z = tz1 = large_tz ? xmalloc (tzsize) : tz1buf;
|
tz1string = tz1alloc;
|
||||||
|
}
|
||||||
|
z = tz1string;
|
||||||
for (s = tzbase; *s != '"'; s++)
|
for (s = tzbase; *s != '"'; s++)
|
||||||
*z++ = *(s += *s == '\\');
|
*z++ = *(s += *s == '\\');
|
||||||
*z = '\0';
|
*z = '\0';
|
||||||
setenv_ok = setenv ("TZ", tz1, 1) == 0;
|
tz1 = tzalloc (tz1string);
|
||||||
if (large_tz)
|
if (!tz1)
|
||||||
free (tz1);
|
|
||||||
if (!setenv_ok)
|
|
||||||
goto fail;
|
goto fail;
|
||||||
tz_was_altered = true;
|
tz = tz1;
|
||||||
|
tzstring = tz1string;
|
||||||
|
|
||||||
p = s + 1;
|
p = s + 1;
|
||||||
while (c = *p, c_isspace (c))
|
while (c = *p, c_isspace (c))
|
||||||
@@ -1807,6 +1797,9 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (! localtime_rz (tz, &now->tv_sec, &tmp))
|
||||||
|
return false;
|
||||||
|
|
||||||
/* As documented, be careful to treat the empty string just like
|
/* As documented, be careful to treat the empty string just like
|
||||||
a date string of "0". Without this, an empty string would be
|
a date string of "0". Without this, an empty string would be
|
||||||
declared invalid when parsed during a DST transition. */
|
declared invalid when parsed during a DST transition. */
|
||||||
@@ -1814,16 +1807,16 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
p = "0";
|
p = "0";
|
||||||
|
|
||||||
pc.input = p;
|
pc.input = p;
|
||||||
pc.year.value = tmp->tm_year;
|
pc.year.value = tmp.tm_year;
|
||||||
pc.year.value += TM_YEAR_BASE;
|
pc.year.value += TM_YEAR_BASE;
|
||||||
pc.year.digits = 0;
|
pc.year.digits = 0;
|
||||||
pc.month = tmp->tm_mon + 1;
|
pc.month = tmp.tm_mon + 1;
|
||||||
pc.day = tmp->tm_mday;
|
pc.day = tmp.tm_mday;
|
||||||
pc.hour = tmp->tm_hour;
|
pc.hour = tmp.tm_hour;
|
||||||
pc.minutes = tmp->tm_min;
|
pc.minutes = tmp.tm_min;
|
||||||
pc.seconds.tv_sec = tmp->tm_sec;
|
pc.seconds.tv_sec = tmp.tm_sec;
|
||||||
pc.seconds.tv_nsec = Start_ns;
|
pc.seconds.tv_nsec = Start_ns;
|
||||||
tm.tm_isdst = tmp->tm_isdst;
|
tm.tm_isdst = tmp.tm_isdst;
|
||||||
|
|
||||||
pc.meridian = MER24;
|
pc.meridian = MER24;
|
||||||
pc.rel = RELATIVE_TIME_0;
|
pc.rel = RELATIVE_TIME_0;
|
||||||
@@ -1848,9 +1841,9 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
pc.debug_default_input_timezone = 0;
|
pc.debug_default_input_timezone = 0;
|
||||||
|
|
||||||
#if HAVE_STRUCT_TM_TM_ZONE
|
#if HAVE_STRUCT_TM_TM_ZONE
|
||||||
pc.local_time_zone_table[0].name = tmp->tm_zone;
|
pc.local_time_zone_table[0].name = tmp.tm_zone;
|
||||||
pc.local_time_zone_table[0].type = tLOCAL_ZONE;
|
pc.local_time_zone_table[0].type = tLOCAL_ZONE;
|
||||||
pc.local_time_zone_table[0].value = tmp->tm_isdst;
|
pc.local_time_zone_table[0].value = tmp.tm_isdst;
|
||||||
pc.local_time_zone_table[1].name = NULL;
|
pc.local_time_zone_table[1].name = NULL;
|
||||||
|
|
||||||
/* Probe the names used in the next three calendar quarters, looking
|
/* Probe the names used in the next three calendar quarters, looking
|
||||||
@@ -1860,14 +1853,14 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
for (quarter = 1; quarter <= 3; quarter++)
|
for (quarter = 1; quarter <= 3; quarter++)
|
||||||
{
|
{
|
||||||
time_t probe = Start + quarter * (90 * 24 * 60 * 60);
|
time_t probe = Start + quarter * (90 * 24 * 60 * 60);
|
||||||
struct tm const *probe_tm = localtime (&probe);
|
struct tm probe_tm;
|
||||||
if (probe_tm && probe_tm->tm_zone
|
if (localtime_rz (tz, &probe, &probe_tm) && probe_tm.tm_zone
|
||||||
&& probe_tm->tm_isdst != pc.local_time_zone_table[0].value)
|
&& probe_tm.tm_isdst != pc.local_time_zone_table[0].value)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
pc.local_time_zone_table[1].name = probe_tm->tm_zone;
|
pc.local_time_zone_table[1].name = probe_tm.tm_zone;
|
||||||
pc.local_time_zone_table[1].type = tLOCAL_ZONE;
|
pc.local_time_zone_table[1].type = tLOCAL_ZONE;
|
||||||
pc.local_time_zone_table[1].value = probe_tm->tm_isdst;
|
pc.local_time_zone_table[1].value = probe_tm.tm_isdst;
|
||||||
pc.local_time_zone_table[2].name = NULL;
|
pc.local_time_zone_table[2].name = NULL;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1905,7 +1898,7 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
pc.local_time_zone_table[1].name = NULL;
|
pc.local_time_zone_table[1].name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
pc.debug_default_input_timezone = get_effective_timezone ();
|
pc.debug_default_input_timezone = get_effective_timezone (tz);
|
||||||
|
|
||||||
if (yyparse (&pc) != 0)
|
if (yyparse (&pc) != 0)
|
||||||
{
|
{
|
||||||
@@ -1925,27 +1918,26 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
/* determine effective timezone source */
|
/* determine effective timezone source */
|
||||||
if (pc.parse_datetime_debug)
|
if (pc.parse_datetime_debug)
|
||||||
{
|
{
|
||||||
long int tz = pc.debug_default_input_timezone;
|
long int time_zone = pc.debug_default_input_timezone;
|
||||||
const char* tz_env;
|
|
||||||
|
|
||||||
if (pc.timespec_seen)
|
if (pc.timespec_seen)
|
||||||
{
|
{
|
||||||
tz = 0 ;
|
time_zone = 0;
|
||||||
strncpy (dbg_tm, _("'@timespec' - always UTC0"), sizeof (dbg_tm)-1);
|
strncpy (dbg_tm, _("'@timespec' - always UTC0"), sizeof (dbg_tm)-1);
|
||||||
}
|
}
|
||||||
else if (pc.zones_seen)
|
else if (pc.zones_seen)
|
||||||
{
|
{
|
||||||
tz = pc.time_zone;
|
time_zone = pc.time_zone;
|
||||||
strncpy (dbg_tm, _("parsed date/time string"), sizeof (dbg_tm)-1);
|
strncpy (dbg_tm, _("parsed date/time string"), sizeof (dbg_tm)-1);
|
||||||
}
|
}
|
||||||
else if ((tz_env = getenv("TZ")))
|
else if (tzstring)
|
||||||
{
|
{
|
||||||
if (tz_was_altered)
|
if (tz != tzdefault)
|
||||||
{
|
{
|
||||||
snprintf (dbg_tm, sizeof(dbg_tm), _("TZ=\"%s\" in date string"),
|
snprintf (dbg_tm, sizeof(dbg_tm), _("TZ=\"%s\" in date string"),
|
||||||
tz_env);
|
tzstring);
|
||||||
}
|
}
|
||||||
else if (STREQ(tz_env,"UTC0"))
|
else if (STREQ (tzstring, "UTC0"))
|
||||||
{
|
{
|
||||||
/* Special case: using 'date -u' simply set TZ=UTC0 */
|
/* Special case: using 'date -u' simply set TZ=UTC0 */
|
||||||
strncpy (dbg_tm, _("TZ=UTC0 environment value or -u"),
|
strncpy (dbg_tm, _("TZ=UTC0 environment value or -u"),
|
||||||
@@ -1954,7 +1946,7 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf (dbg_tm, sizeof(dbg_tm),
|
snprintf (dbg_tm, sizeof(dbg_tm),
|
||||||
_("TZ=\"%s\" environment value"), tz_env);
|
_("TZ=\"%s\" environment value"), tzstring);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1970,14 +1962,15 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
default timezone.*/
|
default timezone.*/
|
||||||
if (pc.local_zones_seen && !pc.zones_seen && pc.local_isdst==1)
|
if (pc.local_zones_seen && !pc.zones_seen && pc.local_isdst==1)
|
||||||
{
|
{
|
||||||
tz += 60;
|
time_zone += 60;
|
||||||
strncat (dbg_tm, ", dst",
|
strncat (dbg_tm, ", dst",
|
||||||
sizeof (dbg_tm) - strlen (dbg_tm) - 1);
|
sizeof (dbg_tm) - strlen (dbg_tm) - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pc.parse_datetime_debug)
|
if (pc.parse_datetime_debug)
|
||||||
dbg_printf (_("input timezone: %+03d:%02d (set from %s)\n"),
|
dbg_printf (_("input timezone: %+03d:%02d (set from %s)\n"),
|
||||||
(int)(tz/60), abs ((int)tz)%60, dbg_tm);
|
(int) (time_zone / 60), abs ((int) (time_zone % 60)),
|
||||||
|
dbg_tm);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2045,9 +2038,9 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
|
|
||||||
tm0 = tm;
|
tm0 = tm;
|
||||||
|
|
||||||
Start = mktime (&tm);
|
Start = mktime_z (tz, &tm);
|
||||||
|
|
||||||
if (! mktime_ok (&tm0, &tm, Start))
|
if (! mktime_ok (tz, &tm0, &tm, Start))
|
||||||
{
|
{
|
||||||
if (! pc.zones_seen)
|
if (! pc.zones_seen)
|
||||||
{
|
{
|
||||||
@@ -2071,27 +2064,27 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone;
|
long int abs_time_zone = time_zone < 0 ? - time_zone : time_zone;
|
||||||
long int abs_time_zone_hour = abs_time_zone / 60;
|
long int abs_time_zone_hour = abs_time_zone / 60;
|
||||||
int abs_time_zone_min = abs_time_zone % 60;
|
int abs_time_zone_min = abs_time_zone % 60;
|
||||||
char tz1buf[sizeof "XXX+0:00" + TYPE_WIDTH (pc.time_zone) / 3];
|
char tz2buf[sizeof "XXX+0:00" + TYPE_WIDTH (pc.time_zone) / 3];
|
||||||
if (!tz_was_altered)
|
timezone_t tz2;
|
||||||
tz0 = get_tz (tz0buf);
|
sprintf (tz2buf, "XXX%s%ld:%02d", &"-"[time_zone < 0],
|
||||||
sprintf (tz1buf, "XXX%s%ld:%02d", &"-"[time_zone < 0],
|
|
||||||
abs_time_zone_hour, abs_time_zone_min);
|
abs_time_zone_hour, abs_time_zone_min);
|
||||||
if (setenv ("TZ", tz1buf, 1) != 0)
|
tz2 = tzalloc (tz2buf);
|
||||||
|
if (!tz2)
|
||||||
{
|
{
|
||||||
/* TODO: was warn () + print errno? */
|
|
||||||
if (pc.parse_datetime_debug)
|
if (pc.parse_datetime_debug)
|
||||||
dbg_printf (_("error: setenv('TZ','%s') failed\n"), tz1buf);
|
dbg_printf (_("error: tzalloc (\"%s\") failed\n"), tz2buf);
|
||||||
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
tz_was_altered = true;
|
|
||||||
tm = tm0;
|
tm = tm0;
|
||||||
Start = mktime (&tm);
|
Start = mktime_z (tz2, &tm);
|
||||||
if (! mktime_ok (&tm0, &tm, Start))
|
ok = mktime_ok (tz2, &tm0, &tm, Start);
|
||||||
|
tzfree (tz2);
|
||||||
|
if (! ok)
|
||||||
{
|
{
|
||||||
debug_mktime_not_ok (&tm0, &tm, &pc, pc.zones_seen);
|
debug_mktime_not_ok (&tm0, &tm, &pc, pc.zones_seen);
|
||||||
|
|
||||||
goto fail;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2103,7 +2096,7 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
- (0 < pc.day_ordinal
|
- (0 < pc.day_ordinal
|
||||||
&& tm.tm_wday != pc.day_number)));
|
&& tm.tm_wday != pc.day_number)));
|
||||||
tm.tm_isdst = -1;
|
tm.tm_isdst = -1;
|
||||||
Start = mktime (&tm);
|
Start = mktime_z (tz, &tm);
|
||||||
if (Start == (time_t) -1)
|
if (Start == (time_t) -1)
|
||||||
{
|
{
|
||||||
if (pc.parse_datetime_debug)
|
if (pc.parse_datetime_debug)
|
||||||
@@ -2174,7 +2167,7 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
tm.tm_min = tm0.tm_min;
|
tm.tm_min = tm0.tm_min;
|
||||||
tm.tm_sec = tm0.tm_sec;
|
tm.tm_sec = tm0.tm_sec;
|
||||||
tm.tm_isdst = tm0.tm_isdst;
|
tm.tm_isdst = tm0.tm_isdst;
|
||||||
Start = mktime (&tm);
|
Start = mktime_z (tz, &tm);
|
||||||
if (Start == (time_t) -1)
|
if (Start == (time_t) -1)
|
||||||
{
|
{
|
||||||
if (pc.parse_datetime_debug)
|
if (pc.parse_datetime_debug)
|
||||||
@@ -2250,8 +2243,8 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
delta -= tm.tm_gmtoff;
|
delta -= tm.tm_gmtoff;
|
||||||
#else
|
#else
|
||||||
time_t t = Start;
|
time_t t = Start;
|
||||||
struct tm const *gmt = gmtime (&t);
|
struct tm gmt;
|
||||||
if (! gmt)
|
if (! gmtime_r (&t, &gmt))
|
||||||
{
|
{
|
||||||
/* TODO: use 'warn(3)' + print errno ? */
|
/* TODO: use 'warn(3)' + print errno ? */
|
||||||
if (pc.parse_datetime_debug)
|
if (pc.parse_datetime_debug)
|
||||||
@@ -2259,7 +2252,7 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
delta -= tm_diff (&tm, gmt);
|
delta -= tm_diff (&tm, &gmt);
|
||||||
#endif
|
#endif
|
||||||
t1 = Start - delta;
|
t1 = Start - delta;
|
||||||
if ((Start < t1) != (delta < 0))
|
if ((Start < t1) != (delta < 0))
|
||||||
@@ -2317,6 +2310,7 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
if (pc.parse_datetime_debug
|
if (pc.parse_datetime_debug
|
||||||
&& (pc.rel.hour | pc.rel.minutes | pc.rel.seconds | pc.rel.ns))
|
&& (pc.rel.hour | pc.rel.minutes | pc.rel.seconds | pc.rel.ns))
|
||||||
{
|
{
|
||||||
|
struct tm lmt;
|
||||||
dbg_printf (_("after time adjustment (%+ld hours, " \
|
dbg_printf (_("after time adjustment (%+ld hours, " \
|
||||||
"%+ld minutes, %+ld seconds, %+ld ns),\n"),
|
"%+ld minutes, %+ld seconds, %+ld ns),\n"),
|
||||||
pc.rel.hour,pc.rel.minutes,pc.rel.seconds,pc.rel.ns);
|
pc.rel.hour,pc.rel.minutes,pc.rel.seconds,pc.rel.ns);
|
||||||
@@ -2334,8 +2328,8 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
|
|
||||||
'tm.tm_isdst' contains the date after date adjustment.
|
'tm.tm_isdst' contains the date after date adjustment.
|
||||||
*/
|
*/
|
||||||
struct tm const *lmt = localtime (&t5);
|
if (tm.tm_isdst != -1 && localtime_rz (tz, &t5, &lmt)
|
||||||
if ((tm.tm_isdst!=-1) && (tm.tm_isdst != lmt->tm_isdst))
|
&& tm.tm_isdst != lmt.tm_isdst)
|
||||||
dbg_printf (_("warning: daylight saving time changed after " \
|
dbg_printf (_("warning: daylight saving time changed after " \
|
||||||
"time adjustment\n"));
|
"time adjustment\n"));
|
||||||
}
|
}
|
||||||
@@ -2350,29 +2344,22 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
fail:
|
fail:
|
||||||
ok = false;
|
ok = false;
|
||||||
done:
|
done:
|
||||||
if (tz_was_altered)
|
|
||||||
ok &= (tz0 ? setenv ("TZ", tz0, 1) : unsetenv ("TZ")) == 0;
|
|
||||||
if (tz0 != tz0buf)
|
|
||||||
free (tz0);
|
|
||||||
|
|
||||||
if (ok && pc.parse_datetime_debug)
|
if (ok && pc.parse_datetime_debug)
|
||||||
{
|
{
|
||||||
/* print local timezone AFTER restoring TZ (if tz_was_altered)*/
|
const long int otz = get_effective_timezone (tz);
|
||||||
const long int otz = get_effective_timezone ();
|
const char *tz_src;
|
||||||
const char* tz_src;
|
|
||||||
const char* tz_env;
|
|
||||||
|
|
||||||
if ((tz_env = getenv("TZ")))
|
if (tzstring)
|
||||||
{
|
{
|
||||||
/* Special case: using 'date -u' simply set TZ=UTC0 */
|
/* Special case: using 'date -u' simply set TZ=UTC0 */
|
||||||
if (STREQ(tz_env,"UTC0"))
|
if (STREQ (tzstring, "UTC0"))
|
||||||
{
|
{
|
||||||
tz_src = _("TZ=UTC0 environment value or -u");
|
tz_src = _("TZ=UTC0 environment value or -u");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
snprintf (dbg_tm, sizeof(dbg_tm),
|
snprintf (dbg_tm, sizeof(dbg_tm),
|
||||||
_("TZ=\"%s\" environment value"), tz_env);
|
_("TZ=\"%s\" environment value"), tzstring);
|
||||||
tz_src = dbg_tm;
|
tz_src = dbg_tm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2390,16 +2377,21 @@ parse_datetime2 (struct timespec *result, char const *p,
|
|||||||
dbg_printf (_("final: %ld.%09ld (epoch-seconds)\n"),
|
dbg_printf (_("final: %ld.%09ld (epoch-seconds)\n"),
|
||||||
result->tv_sec,result->tv_nsec);
|
result->tv_sec,result->tv_nsec);
|
||||||
|
|
||||||
struct tm const *gmt = gmtime (&result->tv_sec);
|
struct tm gmt, lmt;
|
||||||
dbg_printf (_("final: %s (UTC0)\n"),
|
if (gmtime_r (&result->tv_sec, &gmt))
|
||||||
debug_strfdatetime (gmt, NULL, dbg_tm, sizeof (dbg_tm)));
|
dbg_printf (_("final: %s (UTC0)\n"),
|
||||||
struct tm const *lmt = localtime (&result->tv_sec);
|
debug_strfdatetime (&gmt, NULL,
|
||||||
dbg_printf (_("final: %s (output timezone TZ=%+03d:%02d)\n"),
|
dbg_tm, sizeof dbg_tm));
|
||||||
debug_strfdatetime (lmt, NULL, dbg_tm, sizeof (dbg_tm)),
|
if (localtime_rz (tz, &result->tv_sec, &lmt))
|
||||||
(int)(otz/60), abs ((int)otz)%60);
|
dbg_printf (_("final: %s (output timezone TZ=%+03d:%02d)\n"),
|
||||||
|
debug_strfdatetime (&lmt, NULL, dbg_tm, sizeof dbg_tm),
|
||||||
|
(int) (otz / 60), abs ((int) (otz % 60)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tz != tzdefault)
|
||||||
|
tzfree (tz);
|
||||||
|
free (tz1alloc);
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,9 +20,10 @@ setenv
|
|||||||
strftime
|
strftime
|
||||||
unsetenv
|
unsetenv
|
||||||
time
|
time
|
||||||
|
time_r
|
||||||
|
time_rz
|
||||||
timegm
|
timegm
|
||||||
verify
|
verify
|
||||||
xalloc
|
|
||||||
|
|
||||||
configure.ac:
|
configure.ac:
|
||||||
gl_PARSE_DATETIME
|
gl_PARSE_DATETIME
|
||||||
|
Reference in New Issue
Block a user