date: add -z output_zone option

Inpired by OpenBSD date(1), this option allows to do timezone conversion
via the date(1) command.

For example, to determine when the BSDCan livestream begins for me:

$ env -i TZ=EST5EDT date -z Europe/Paris -j 0900

MFC After:		1 week
Reviewed by:		kib, bcr (manpage)
Differential Revision:	https://reviews.freebsd.org/D40159
This commit is contained in:
Baptiste Daroussin 2023-05-19 11:08:11 +02:00
parent ec6d620b19
commit 31edf56b15
2 changed files with 29 additions and 5 deletions

View file

@ -32,7 +32,7 @@
.\" @(#)date.1 8.3 (Berkeley) 4/28/95
.\" $FreeBSD$
.\"
.Dd April 13, 2023
.Dd May 19, 2023
.Dt DATE 1
.Os
.Sh NAME
@ -42,6 +42,7 @@
.\" Display time.
.Nm
.Op Fl nRu
.Op Fl z Ar output_zone
.Op Fl I Ns Op Ar FMT
.Op Fl r Ar filename
.Op Fl r Ar seconds
@ -56,6 +57,7 @@
.\" Set time with the default input format.
.Nm
.Op Fl jnRu
.Op Fl z Ar output_zone
.Op Fl I Ns Op Ar FMT
.Oo
.Sm off
@ -77,6 +79,7 @@
.\" Set time with the user-provided input format.
.Nm
.Op Fl jnRu
.Op Fl z Ar output_zone
.Op Fl I Ns Op Ar FMT
.Oo
.Sm off
@ -202,6 +205,14 @@ displays the time in the time zone described by
or the
.Ev TZ
environment variable.
.It Fl z Ar output_zone
Just before printing the time, change to the specified timezone;
see the description of
.Ev TZ
below.
This can be used with
.Fl j
to easily convert time specifications from one zone to another.
.It Xo
.Fl v
.Sm off
@ -514,13 +525,20 @@ will display
.Pp
.Dl "2018-08-04T13:42:19-07:00"
.Pp
Finally the command:
The command:
.Pp
.Dl "env LC_ALL=C date -j -f ""%a %b %d %T %Z %Y"" ""`env LC_ALL=C date`"" ""+%s"""
.Pp
can be used to parse the output from
.Nm
and express it in Epoch time.
.Pp
Finally the command
.Pp
.Dl "TZ=America/Los_Angeles date -z Europe/Paris -j 0900"
.Pp
will print the time in the "Europe/Paris" timezone when it is 9:00 in The
America/Los_Angeles timezone.
.Sh DIAGNOSTICS
It is invalid to combine the
.Fl I

View file

@ -95,7 +95,7 @@ main(int argc, char *argv[])
bool Iflag, jflag, Rflag;
const char *format;
char buf[1024];
char *fmt;
char *fmt, *outzone = NULL;
char *tmp;
struct vary *v;
const struct vary *badv;
@ -108,7 +108,7 @@ main(int argc, char *argv[])
(void) setlocale(LC_TIME, "");
rflag = 0;
Iflag = jflag = Rflag = 0;
while ((ch = getopt(argc, argv, "f:I::jnRr:uv:")) != -1)
while ((ch = getopt(argc, argv, "f:I::jnRr:uv:z:")) != -1)
switch((char)ch) {
case 'f':
fmt = optarg;
@ -152,6 +152,9 @@ main(int argc, char *argv[])
case 'u': /* do everything in UTC */
(void)setenv("TZ", "UTC0", 1);
break;
case 'z':
outzone = optarg;
break;
case 'v':
v = vary_append(v, optarg);
break;
@ -189,6 +192,8 @@ main(int argc, char *argv[])
format = *argv + 1;
}
if (outzone != NULL && setenv("TZ", outzone, 1) != 0)
err(1, "setenv(TZ)");
lt = localtime(&tval);
if (lt == NULL)
errx(1, "invalid time");
@ -211,6 +216,7 @@ main(int argc, char *argv[])
*/
setlocale(LC_TIME, "C");
(void)strftime(buf, sizeof(buf), format, lt);
printdate(buf);
}
@ -385,7 +391,7 @@ usage(void)
(void)fprintf(stderr, "%s\n%s\n%s\n",
"usage: date [-jnRu] [-I[date|hours|minutes|seconds]] [-f input_fmt]",
" "
"[-r filename|seconds] [-v[+|-]val[y|m|w|d|H|M|S]]",
"[ -z output_zone ] [-r filename|seconds] [-v[+|-]val[y|m|w|d|H|M|S]]",
" "
"[[[[[[cc]yy]mm]dd]HH]MM[.SS] | new_date] [+output_fmt]"
);