mirror of
git://git.code.sf.net/p/zsh/code
synced 2025-10-07 09:21:18 +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>
|
2018-11-12 Oliver Kiddle <okiddle@yahoo.co.uk>
|
||||||
|
|
||||||
* 43819: Completion/Unix/Command/_adb: expand adb completion to
|
* 43819: Completion/Unix/Command/_adb: expand adb completion to
|
||||||
|
|
|
@ -6,9 +6,13 @@ The tt(zsh/datetime) module makes available one builtin command:
|
||||||
startitem()
|
startitem()
|
||||||
findex(strftime)
|
findex(strftime)
|
||||||
cindex(date string, printing)
|
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) )(
|
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
|
See manref(strftime)(3) for details. The zsh extensions described in
|
||||||
ifzman(the section EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
|
ifzman(the section EXPANSION OF PROMPT SEQUENCES in zmanref(zshmisc))\
|
||||||
ifnzman(noderef(Prompt Expansion)) are also available.
|
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;
|
int bufsize, x, len;
|
||||||
char *endptr = NULL, *scalar = NULL, *buffer;
|
char *endptr = NULL, *scalar = NULL, *buffer;
|
||||||
time_t secs;
|
struct tm *tm;
|
||||||
struct tm *t;
|
struct timespec ts;
|
||||||
|
|
||||||
if (OPT_ISSET(ops,'s')) {
|
if (OPT_ISSET(ops,'s')) {
|
||||||
scalar = OPT_ARG(ops, 's');
|
scalar = OPT_ARG(ops, 's');
|
||||||
|
@ -110,30 +110,58 @@ output_strftime(char *nam, char **argv, Options ops, UNUSED(int func))
|
||||||
return 1;
|
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'));
|
return reverse_strftime(nam, argv, scalar, OPT_ISSET(ops, 'q'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!argv[1]) {
|
||||||
|
zgettime(&ts);
|
||||||
|
tm = localtime(&ts.tv_sec);
|
||||||
|
} else {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
secs = (time_t)strtoul(argv[1], &endptr, 10);
|
|
||||||
|
ts.tv_sec = (time_t)strtoul(argv[1], &endptr, 10);
|
||||||
if (errno != 0) {
|
if (errno != 0) {
|
||||||
zwarnnam(nam, "%s: %e", argv[1], errno);
|
zwarnnam(nam, "%s: %e", argv[1], errno);
|
||||||
return 1;
|
return 1;
|
||||||
} else if (*endptr != '\0') {
|
} else if (*argv[1] == '\0' || *endptr != '\0') {
|
||||||
zwarnnam(nam, "%s: invalid decimal number", argv[1]);
|
zwarnnam(nam, "%s: invalid decimal number", argv[1]);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
t = localtime(&secs);
|
tm = localtime(&ts.tv_sec);
|
||||||
if (!t) {
|
if (!tm) {
|
||||||
zwarnnam(nam, "%s: unable to convert to time", argv[1]);
|
zwarnnam(nam, "%s: unable to convert to time", argv[1]);
|
||||||
return 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;
|
bufsize = strlen(argv[0]) * 8;
|
||||||
buffer = zalloc(bufsize);
|
buffer = zalloc(bufsize);
|
||||||
|
|
||||||
len = 0;
|
len = 0;
|
||||||
for (x=0; x < 4; x++) {
|
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;
|
break;
|
||||||
buffer = zrealloc(buffer, bufsize *= 2);
|
buffer = zrealloc(buffer, bufsize *= 2);
|
||||||
}
|
}
|
||||||
|
@ -207,7 +235,7 @@ getcurrenttime(UNUSED(Param pm))
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct builtin bintab[] = {
|
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 =
|
static const struct gsu_integer epochseconds_gsu =
|
||||||
|
|
|
@ -82,3 +82,32 @@
|
||||||
# The result can be '%@' (Linux), '@' (BSDs) or an error (Cygwin).
|
# The result can be '%@' (Linux), '@' (BSDs) or an error (Cygwin).
|
||||||
[[ $(strftime '%@' 0 2> /dev/null) == (%|)@ || $? != 0 ]]
|
[[ $(strftime '%@' 0 2> /dev/null) == (%|)@ || $? != 0 ]]
|
||||||
0:bad format specifier
|
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