mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-04 20:40:57 +02:00
43800: Add nanosecond support to strftime built-in
This commit is contained in:
parent
0b3b52778b
commit
5ad76492af
4 changed files with 86 additions and 20 deletions
|
@ -1,3 +1,8 @@
|
|||
2018-11-13 dana <dana@dana.is>
|
||||
|
||||
* 43800: Doc/Zsh/mod_datetime.yo, Src/Modules/datetime.c,
|
||||
Test/V09datetime.ztst: Add nanosecond support to strftime built-in
|
||||
|
||||
2018-11-12 Oliver Kiddle <okiddle@yahoo.co.uk>
|
||||
|
||||
* 43819: Completion/Unix/Command/_adb: expand adb completion to
|
||||
|
|
|
@ -6,9 +6,13 @@ The tt(zsh/datetime) module makes available one builtin command:
|
|||
startitem()
|
||||
findex(strftime)
|
||||
cindex(date string, printing)
|
||||
xitem(tt(strftime) [ tt(-s) var(scalar) ] var(format) var(epochtime) )
|
||||
xitem(tt(strftime) [ tt(-s) var(scalar) ] var(format) [ var(epochtime) [ var(nanoseconds) ] ] )
|
||||
item(tt(strftime) tt(-r) [ tt(-q) ] [ tt(-s) var(scalar) ] var(format) var(timestring) )(
|
||||
Output the date denoted by var(epochtime) in the var(format) specified.
|
||||
Output the date in the var(format) specified. With no var(epochtime), the
|
||||
current system date/time is used; optionally, var(epochtime) may be used to
|
||||
specify the number of seconds since the epoch, and var(nanoseconds) may
|
||||
additionally be used to specify the number of nanoseconds past the second
|
||||
(otherwise that number is assumed to be 0).
|
||||
See manref(strftime)(3) for details. The zsh extensions described in
|
||||
ifzman(the section EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
|
||||
ifnzman(noderef(Prompt Expansion)) are also available.
|
||||
|
|
|
@ -100,8 +100,8 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
|
|||
{
|
||||
int bufsize, x, len;
|
||||
char *endptr = NULL, *scalar = NULL, *buffer;
|
||||
time_t secs;
|
||||
struct tm *t;
|
||||
struct tm *tm;
|
||||
struct timespec ts;
|
||||
|
||||
if (OPT_ISSET(ops,'s')) {
|
||||
scalar = OPT_ARG(ops, 's');
|
||||
|
@ -110,30 +110,58 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
|
|||
return 1;
|
||||
}
|
||||
}
|
||||
if (OPT_ISSET(ops, 'r'))
|
||||
if (OPT_ISSET(ops, 'r')) {
|
||||
if (!argv[1]) {
|
||||
zwarnnam(nam, "timestring expected");
|
||||
return 1;
|
||||
}
|
||||
return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q'));
|
||||
|
||||
errno = 0;
|
||||
secs = (time_t)strtoul(argv[1], &endptr, 10);
|
||||
if (errno != 0) {
|
||||
zwarnnam(nam, "%s: %e", argv[1], errno);
|
||||
return 1;
|
||||
} else if (*endptr != '\0') {
|
||||
zwarnnam(nam, "%s: invalid decimal number", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
t = localtime(&secs);
|
||||
if (!t) {
|
||||
zwarnnam(nam, "%s: unable to convert to time", argv[1]);
|
||||
return 1;
|
||||
if (!argv[1]) {
|
||||
zgettime(&ts);
|
||||
tm = localtime(&ts.tv_sec);
|
||||
} else {
|
||||
errno = 0;
|
||||
|
||||
ts.tv_sec = (time_t)strtoul(argv[1], &endptr, 10);
|
||||
if (errno != 0) {
|
||||
zwarnnam(nam, "%s: %e", argv[1], errno);
|
||||
return 1;
|
||||
} else if (*argv[1] == '\0' || *endptr != '\0') {
|
||||
zwarnnam(nam, "%s: invalid decimal number", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
tm = localtime(&ts.tv_sec);
|
||||
if (!tm) {
|
||||
zwarnnam(nam, "%s: unable to convert to time", argv[1]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
ts.tv_nsec = 0L;
|
||||
if (argv[2]) {
|
||||
ts.tv_nsec = (long)zstrtol(argv[2], &endptr, 10);
|
||||
if (errno != 0) {
|
||||
zwarnnam(nam, "%s: %e", argv[2], errno);
|
||||
return 1;
|
||||
} else if (*argv[2] == '\0' || *endptr != '\0') {
|
||||
zwarnnam(nam, "%s: invalid decimal number", argv[2]);
|
||||
return 1;
|
||||
} else if (ts.tv_nsec < 0) {
|
||||
zwarnnam(nam, "%s: invalid nanosecond value", argv[2]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bufsize = strlen(argv[0]) * 8;
|
||||
buffer = zalloc(bufsize);
|
||||
|
||||
len = 0;
|
||||
for (x=0; x < 4; x++) {
|
||||
if ((len = ztrftime(buffer, bufsize, argv[0], t, 0L)) >= 0 || x==3)
|
||||
if ((len = ztrftime(buffer, bufsize, argv[0], tm, ts.tv_nsec)) >= 0 ||
|
||||
x==3)
|
||||
break;
|
||||
buffer = zrealloc(buffer, bufsize *= 2);
|
||||
}
|
||||
|
@ -207,7 +235,7 @@ getcurrenttime(UNUSED(Param pm))
|
|||
}
|
||||
|
||||
static struct builtin bintab[] = {
|
||||
BUILTIN("strftime", 0, bin_strftime, 2, 2, 0, "qrs:", NULL),
|
||||
BUILTIN("strftime", 0, bin_strftime, 1, 3, 0, "qrs:", NULL),
|
||||
};
|
||||
|
||||
static const struct gsu_integer epochseconds_gsu =
|
||||
|
|
|
@ -82,3 +82,32 @@
|
|||
# The result can be '%@' (Linux), '@' (BSDs) or an error (Cygwin).
|
||||
[[ $(strftime '%@' 0 2> /dev/null) == (%|)@ || $? != 0 ]]
|
||||
0:bad format specifier
|
||||
|
||||
# This test may fail at 23:59:59.xxx on New Year's Eve :/
|
||||
[[ "$( strftime '%Y' )" == "$( strftime '%Y' "$EPOCHSECONDS" )" ]]
|
||||
0:epochtime optional
|
||||
|
||||
strftime '%Y-%m-%d %H:%M:%S.%3.' 1012615322
|
||||
strftime '%Y-%m-%d %H:%M:%S.%3.' 1012615322 0
|
||||
strftime '%Y-%m-%d %H:%M:%S.%3.' 1012615322 2
|
||||
strftime '%Y-%m-%d %H:%M:%S.%3.' 1012615322 $(( 222 * (10 ** 9) ))
|
||||
0:optional nanoseconds
|
||||
>2002-02-02 02:02:02.000
|
||||
>2002-02-02 02:02:02.000
|
||||
>2002-02-02 02:02:02.000
|
||||
>2002-02-02 02:02:02.222
|
||||
|
||||
strftime '%Y' '' 2> /dev/null
|
||||
1:empty epochtime not allowed
|
||||
|
||||
strftime '%Y' 1012615322 '' 2> /dev/null
|
||||
1:empty nanoseconds not allowed
|
||||
|
||||
strftime '%N' 1012615322 ${(l<64><9>):-} 2> /dev/null
|
||||
1:overflowed nanoseconds not allowed
|
||||
|
||||
strftime '%N' 1012615322 -1 2> /dev/null
|
||||
1:negative nanoseconds not allowed
|
||||
|
||||
strftime -r '%Y' 2> /dev/null
|
||||
1:-r timestring not optional
|
||||
|
|
Loading…
Reference in a new issue