mirror of
git://git.sv.gnu.org/coreutils.git
synced 2026-04-18 01:40:06 +02:00
date: add '--debug' option
Usage example:
date --debug -d 'now + 3 days'
Print parsing and debugging information to stderr when using date's
-d/--date option.
See: http://lists.gnu.org/archive/html/coreutils/2016-01/msg00076.html
* src/date.c (main): Add '--debug' option, enable debugging
in gnulib's parse-datetime.y module.
* tests/misc/date.pl: Repeat tests with '--debug' enable, ensure
no regression.
* tests/misc/date-debug.sh: Test output of '--debug' option.
* tests/local.mk: Add above test.
* NEWS: Mention new option.
* doc/coreutils.texi: Likewise.
This commit is contained in:
5
NEWS
5
NEWS
@@ -71,6 +71,11 @@ GNU coreutils NEWS -*- outline -*-
|
||||
tail -f uses polling for "prl_fs" and "smb2", inotify for "m1fs",
|
||||
and attempts inotify for "wslfs".
|
||||
|
||||
** New Features
|
||||
|
||||
date now accepts the --debug option, to annotate the parsed date string,
|
||||
display timezone information, and warn about potential misuse.
|
||||
|
||||
|
||||
* Noteworthy changes in release 8.25 (2016-01-20) [stable]
|
||||
|
||||
|
||||
@@ -521,8 +521,8 @@ Include the version number, machine architecture, input files, and
|
||||
any other information needed to reproduce the bug: your input, what you
|
||||
expected, what you got, and why it is wrong.
|
||||
|
||||
If you have a problem with @command{sort}, try running @samp{sort
|
||||
--debug}, as it can can often help find and fix problems without
|
||||
If you have a problem with @command{sort} or @command{date}, try using the
|
||||
@option{--debug} option, as it can can often help find and fix problems without
|
||||
having to wait for an answer to a bug report. If the debug output
|
||||
does not suffice to fix the problem on your own, please compress and
|
||||
attach it to the rest of your bug report.
|
||||
@@ -15392,6 +15392,14 @@ date -d "$(LC_TIME=C date)"
|
||||
@end example
|
||||
@xref{Date input formats}.
|
||||
|
||||
@item --debug
|
||||
@opindex --debug
|
||||
@cindex debugging date strings
|
||||
@cindex date strings, debugging
|
||||
@cindex arbitrary date strings, debugging
|
||||
annotate the parsed date, display the effective time zone, and warn about
|
||||
potential misuse.
|
||||
|
||||
@item -f @var{datefile}
|
||||
@itemx --file=@var{datefile}
|
||||
@opindex -f
|
||||
|
||||
21
src/date.c
21
src/date.c
@@ -78,7 +78,8 @@ static char const rfc_2822_format[] = "%a, %d %b %Y %H:%M:%S %z";
|
||||
non-character as a pseudo short option, starting with CHAR_MAX + 1. */
|
||||
enum
|
||||
{
|
||||
RFC_3339_OPTION = CHAR_MAX + 1
|
||||
RFC_3339_OPTION = CHAR_MAX + 1,
|
||||
DEBUG_DATE_PARSING
|
||||
};
|
||||
|
||||
static char const short_options[] = "d:f:I::r:Rs:u";
|
||||
@@ -86,6 +87,7 @@ static char const short_options[] = "d:f:I::r:Rs:u";
|
||||
static struct option const long_options[] =
|
||||
{
|
||||
{"date", required_argument, NULL, 'd'},
|
||||
{"debug", no_argument, NULL, DEBUG_DATE_PARSING},
|
||||
{"file", required_argument, NULL, 'f'},
|
||||
{"iso-8601", optional_argument, NULL, 'I'},
|
||||
{"reference", required_argument, NULL, 'r'},
|
||||
@@ -101,6 +103,9 @@ static struct option const long_options[] =
|
||||
{NULL, 0, NULL, 0}
|
||||
};
|
||||
|
||||
/* flags for parse_datetime2 */
|
||||
static unsigned int parse_datetime_flags;
|
||||
|
||||
#if LOCALTIME_CACHE
|
||||
# define TZSET tzset ()
|
||||
#else
|
||||
@@ -133,6 +138,12 @@ Display the current time in the given FORMAT, or set the system date.\n\
|
||||
|
||||
fputs (_("\
|
||||
-d, --date=STRING display time described by STRING, not 'now'\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--debug annotate the parsed date,\n\
|
||||
and warn about questionable usage to stderr\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
-f, --file=DATEFILE like --date; once for each line of DATEFILE\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
@@ -306,7 +317,7 @@ batch_convert (const char *input_filename, const char *format, timezone_t tz)
|
||||
break;
|
||||
}
|
||||
|
||||
if (! parse_datetime (&when, line, NULL))
|
||||
if (! parse_datetime2 (&when, line, NULL, parse_datetime_flags))
|
||||
{
|
||||
if (line[line_length - 1] == '\n')
|
||||
line[line_length - 1] = '\0';
|
||||
@@ -360,6 +371,9 @@ main (int argc, char **argv)
|
||||
case 'd':
|
||||
datestr = optarg;
|
||||
break;
|
||||
case DEBUG_DATE_PARSING:
|
||||
parse_datetime_flags |= PARSE_DATETIME_DEBUG;
|
||||
break;
|
||||
case 'f':
|
||||
batch_file = optarg;
|
||||
break;
|
||||
@@ -527,7 +541,8 @@ main (int argc, char **argv)
|
||||
{
|
||||
if (set_datestr)
|
||||
datestr = set_datestr;
|
||||
valid_date = parse_datetime (&when, datestr, NULL);
|
||||
valid_date = parse_datetime2 (&when, datestr, NULL,
|
||||
parse_datetime_flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -279,6 +279,7 @@ all_tests = \
|
||||
tests/misc/csplit-heap.sh \
|
||||
tests/misc/csplit-io-err.sh \
|
||||
tests/misc/csplit-suppress-matched.pl \
|
||||
tests/misc/date-debug.sh \
|
||||
tests/misc/date-sec.sh \
|
||||
tests/misc/dircolors.pl \
|
||||
tests/misc/dirname.pl \
|
||||
|
||||
103
tests/misc/date-debug.sh
Executable file
103
tests/misc/date-debug.sh
Executable file
@@ -0,0 +1,103 @@
|
||||
#!/bin/sh
|
||||
# Test 'date --debug' option.
|
||||
|
||||
# Copyright (C) 2016 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
|
||||
print_ver_ date
|
||||
|
||||
export LC_ALL=C
|
||||
|
||||
## Ensure timezones are supported.
|
||||
## (NOTE: America/Belize timezone does not change on DST)
|
||||
test "$(TZ=America/Belize date +%z)" = '-0600' \
|
||||
|| skip_ 'Timezones database not found'
|
||||
|
||||
|
||||
##
|
||||
## Test 1: complex date string
|
||||
##
|
||||
in1='TZ="Asia/Tokyo" Sun, 90-12-11 + 3 days - 90 minutes'
|
||||
|
||||
cat<<EOF>exp1
|
||||
date: parsed day part: Sun (day ordinal=0 number=0)
|
||||
date: parsed date part: (Y-M-D) 0090-12-11
|
||||
date: parsed relative part: +3 day(s)
|
||||
date: parsed relative part: +3 day(s) -90 minutes
|
||||
date: input timezone: +09:00 (set from TZ="Asia/Tokyo" in date string)
|
||||
date: warning: adjusting year value 90 to 1990
|
||||
date: warning: using midnight as starting time: 00:00:00
|
||||
date: warning: day (Sun) ignored when explicit dates are given
|
||||
date: starting date/time: '(Y-M-D) 1990-12-11 00:00:00 TZ=+09:00'
|
||||
date: warning: when adding relative days, it is recommended to specify 12:00pm
|
||||
date: after date adjustment (+0 years, +0 months, +3 days),
|
||||
date: new date/time = '(Y-M-D) 1990-12-14 00:00:00 TZ=+09:00'
|
||||
date: '(Y-M-D) 1990-12-14 00:00:00 TZ=+09:00' = 661100400 epoch-seconds
|
||||
date: after time adjustment (+0 hours, -90 minutes, +0 seconds, +0 ns),
|
||||
date: new time = 661095000 epoch-seconds
|
||||
date: output timezone: -06:00 (set from TZ="America/Belize" environment value)
|
||||
date: final: 661095000.000000000 (epoch-seconds)
|
||||
date: final: (Y-M-D) 1990-12-13 13:30:00 (UTC0)
|
||||
date: final: (Y-M-D) 1990-12-13 07:30:00 (output timezone TZ=-06:00)
|
||||
Thu Dec 13 07:30:00 CST 1990
|
||||
EOF
|
||||
|
||||
TZ=America/Belize date --debug -d "$in1" >out1 2>&1 || fail=1
|
||||
|
||||
compare exp1 out1 || fail=1
|
||||
|
||||
##
|
||||
## Test 2: Invalid date from Coreutils' FAQ
|
||||
## (with explicit timezone added)
|
||||
in2='TZ="America/Edmonton" 2006-04-02 02:30:00'
|
||||
cat<<EOF>exp2
|
||||
date: parsed date part: (Y-M-D) 2006-04-02
|
||||
date: parsed time part: 02:30:00
|
||||
date: input timezone: -07:00 (set from TZ="America/Edmonton" in date string)
|
||||
date: using specified time as starting value: '02:30:00'
|
||||
date: error: invalid date/time value:
|
||||
date: user provided time: '(Y-M-D) 2006-04-02 02:30:00 TZ=-07:00'
|
||||
date: normalized time: '(Y-M-D) 2006-04-02 03:30:00 TZ=-07:00'
|
||||
date: --
|
||||
date: possible reasons:
|
||||
date: non-existing due to daylight-saving time;
|
||||
date: numeric values overflow;
|
||||
date: missing timezone
|
||||
date: invalid date 'TZ="America/Edmonton" 2006-04-02 02:30:00'
|
||||
EOF
|
||||
|
||||
# date should return 1 (error) for invalid date
|
||||
returns_ 1 date --debug -d "$in2" >out2 2>&1 || fail=1
|
||||
compare exp2 out2 || fail=1
|
||||
|
||||
##
|
||||
## Test 3: timespec (input always UTC, output is TZ-dependent)
|
||||
##
|
||||
in3='@1'
|
||||
cat<<EOF>exp3
|
||||
date: parsed number of seconds part: number of seconds: 1
|
||||
date: input timezone: +00:00 (set from '@timespec' - always UTC0)
|
||||
date: output timezone: -05:00 (set from TZ="America/Lima" environment value)
|
||||
date: final: 1.000000000 (epoch-seconds)
|
||||
date: final: (Y-M-D) 1970-01-01 00:00:01 (UTC0)
|
||||
date: final: (Y-M-D) 1969-12-31 19:00:01 (output timezone TZ=-05:00)
|
||||
Wed Dec 31 19:00:01 PET 1969
|
||||
EOF
|
||||
|
||||
TZ=America/Lima date --debug -d "$in3" >out3 2>&1 || fail=1
|
||||
compare exp3 out3 || fail=1
|
||||
|
||||
Exit $fail
|
||||
@@ -314,6 +314,35 @@ foreach my $t (@Tests)
|
||||
}
|
||||
}
|
||||
|
||||
# Repeat all tests with --debug option, ensure it does not cause any regression
|
||||
my @debug_tests;
|
||||
foreach my $t (@Tests)
|
||||
{
|
||||
# Skip tests with EXIT!=0 or ERR_SUBST part
|
||||
# (as '--debug' requires its own ERR_SUBST).
|
||||
my $exit_val;
|
||||
my $have_err_subst;
|
||||
foreach my $e (@$t)
|
||||
{
|
||||
next unless ref $e && ref $e eq 'HASH';
|
||||
$exit_val = $e->{EXIT} if defined $e->{EXIT};
|
||||
$have_err_subst = 1 if defined $e->{ERR_SUBST};
|
||||
}
|
||||
next if $exit_val || $have_err_subst;
|
||||
|
||||
# Duplicate the test, add '--debug' argument
|
||||
my @newt = @$t;
|
||||
$newt[0] = 'dbg_' . $newt[0];
|
||||
$newt[1] = '--debug ' . $newt[1];
|
||||
|
||||
# Discard all debug printouts before comparing output
|
||||
push @newt, {ERR_SUBST => q!s/^date: .*\n//m!};
|
||||
|
||||
push @debug_tests, \@newt;
|
||||
}
|
||||
push @Tests, @debug_tests;
|
||||
|
||||
|
||||
my $save_temps = $ENV{DEBUG};
|
||||
my $verbose = $ENV{VERBOSE};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user