summaryrefslogtreecommitdiff
path: root/src/pr.c
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2016-03-17 10:35:18 -0700
committerPaul Eggert <eggert@cs.ucla.edu>2016-03-17 10:36:33 -0700
commitdf88fce71651afb2c3456967a142db0ae4bf9906 (patch)
treeaa18160fb6d2ef669fcfc04e914da9d10b649287 /src/pr.c
parentc18b3699e1b8c4ad2739761f2b9c306ff2303322 (diff)
downloadcoreutils-df88fce71651afb2c3456967a142db0ae4bf9906.tar.xz
date ls pr: fix time zone abbrs on SysV platforms
The problematic code computed a struct tm in one time zone, and then printed it or converted it to a string in another. To be portable the same time zone needs to be used for both operations. On GNU platforms this is not an issue, but incorrect output can be generated on System V style platforms like AIX where time zone abbreviations are available only in the 'tzname' global variable. Problem reported by Assaf Gordon in: http://bugs.gnu.org/23035 * NEWS: Document the bug. * src/date.c (show_date): * src/ls.c (long_time_expected_width, print_long_format): * src/pr.c (init_header): * src/stat.c (human_time): Use localtime_rz instead of localtime, so that the time zone information is consistent for both localtime and time-formatting functions like fprintftime and nstrftime. For 'stat' this change is mostly just a code cleanup but it also causes stat to also print nanoseconds when printing time stamps that are out of localtime range, as this is more consistent with what other programs do. For programs other than 'stat' this fixes bugs with time zone formats that use %Z. * src/du.c, src/pr.c (localtz): New static var. (main): Initialize it. * src/du.c (show_date): New time zone argument, so that localtime and fprintftime use the same time zone information. All callers changed. * tests/misc/time-style.sh: New file. * tests/local.mk (all_tests): Add it. * tests/misc/date.pl: Test alphabetic time zone abbreviations.
Diffstat (limited to 'src/pr.c')
-rw-r--r--src/pr.c23
1 files changed, 14 insertions, 9 deletions
diff --git a/src/pr.c b/src/pr.c
index 8885fff4f..d4549a3bb 100644
--- a/src/pr.c
+++ b/src/pr.c
@@ -710,6 +710,9 @@ static char *custom_header;
/* (-D) Date format for the header. */
static char const *date_format;
+/* The local time zone rules, as per the TZ environment variable. */
+static timezone_t localtz;
+
/* Date and file name for the header. */
static char *date_text;
static char const *file_text;
@@ -1049,6 +1052,8 @@ main (int argc, char **argv)
? "%b %e %H:%M %Y"
: "%Y-%m-%d %H:%M");
+ localtz = tzalloc (getenv ("TZ"));
+
/* Now we can set a reasonable initial value: */
if (first_page_number == 0)
first_page_number = 1;
@@ -1611,7 +1616,7 @@ init_header (char const *filename, int desc)
struct stat st;
struct timespec t;
int ns;
- struct tm *tm;
+ struct tm tm;
/* If parallel files or standard input, use current date. */
if (STREQ (filename, "-"))
@@ -1627,18 +1632,18 @@ init_header (char const *filename, int desc)
}
ns = t.tv_nsec;
- tm = localtime (&t.tv_sec);
- if (tm == NULL)
+ if (localtime_rz (localtz, &t.tv_sec, &tm))
{
- buf = xmalloc (INT_BUFSIZE_BOUND (long int)
- + MAX (10, INT_BUFSIZE_BOUND (int)));
- sprintf (buf, "%ld.%09d", (long int) t.tv_sec, ns);
+ size_t bufsize
+ = nstrftime (NULL, SIZE_MAX, date_format, &tm, localtz, ns) + 1;
+ buf = xmalloc (bufsize);
+ nstrftime (buf, bufsize, date_format, &tm, localtz, ns);
}
else
{
- size_t bufsize = nstrftime (NULL, SIZE_MAX, date_format, tm, 0, ns) + 1;
- buf = xmalloc (bufsize);
- nstrftime (buf, bufsize, date_format, tm, 0, ns);
+ char secbuf[INT_BUFSIZE_BOUND (intmax_t)];
+ buf = xmalloc (sizeof secbuf + MAX (10, INT_BUFSIZE_BOUND (int)));
+ sprintf (buf, "%s.%09d", timetostr (t.tv_sec, secbuf), ns);
}
free (date_text);