1
0
Fork 0
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:
dana 2018-11-13 13:01:01 -06:00
parent 0b3b52778b
commit 5ad76492af
4 changed files with 86 additions and 20 deletions

View file

@ -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

View file

@ -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.

View file

@ -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 =

View file

@ -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