commit: 4e46eb9fa6d90ec000211cc191d81dcdf85e9ce4
parent 909ed42b6f1a554c20f1ddf8868141d801e4da00
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date: Thu, 25 Jul 2024 06:46:07 +0200
cmd/date: Add -j option and ability to set system time
Diffstat:
M | cmd/date.1.in | 51 | +++++++++++++++++++++++++++++++++++++++++++-------- |
M | cmd/date.c | 91 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------- |
M | test-cmd/date.sh | 14 | ++++++++++++-- |
3 files changed, 139 insertions(+), 17 deletions(-)
diff --git a/cmd/date.1.in b/cmd/date.1.in
@@ -1,7 +1,7 @@
.\" utils-std: Collection of commonly available Unix tools
.\" Copyright 2017 Haelwenn (lanodan) Monnier <contact+utils@hacktivis.me>
.\" SPDX-License-Identifier: MPL-2.0
-.Dd 2023-06-03
+.Dd 2024-07-25
.Dt DATE 1
.Os
.Sh NAME
@@ -9,11 +9,15 @@
.Nd display date and time
.Sh SYNOPSIS
.Nm
-.Op Fl uR
+.Op Fl jRu
.Op Fl d Ar datetime
.Op Cm + Ns Ar format
.Nm
-.Op Fl uR
+.Op Fl jRu
+.Ar mmddHHMM Ns Oo Oo Ar CC Oc Ns Ar yy Oc
+.Op Cm + Ns Ar format
+.Nm
+.Op Fl jRu
.Fl f Ar now_format
.Ar now
.Op Cm + Ns Ar format
@@ -37,12 +41,40 @@ as the
format string for
.Ar now ,
which will be used instead of the current datetime.
+.It Fl j
+Do no set the system date.
+This allows to use the
+.Fl f
+flag to convert one datetime to another.
.It Fl u
Use UTC (coordinated universal time) instead of the local time.
.It Fl R
Set the default value of
.Ar format
to match RFC5322 (Internet Message Format).
+.It Ar mmddHHMM Ns Oo Oo Ar CC Oc Ns Ar yy Oc
+Sets custom datetime, if
+.Fl j
+isn't set, the system time is also set.
+.Pp
+Each letters corresponds to:
+.Bl -tag -width mm -compact
+.It mm
+months aka %m
+.It dd
+days aka %d
+.It HH
+hours aka %H
+.It MM
+minutes aka %M
+.It CC
+centuries aka %C
+.It yy
+century-less years aka %y
+.El
+.Pp
+For example 072505542024 corresponds to 2024-07-25T05:54, as you can verify with the following command:
+.Dl date -j 072505542024 +%Y-%m-%dT%H:%M
.It Cm + Ns Ar format
Set the displayed datetime in
.Xr strftime 3
@@ -62,12 +94,12 @@ but this depends on your system.
.Sh EXIT STATUS
.Ex -std
.Sh SEE ALSO
-.Xr strftime 3
+.Xr strftime 3 ,
+.Xr clock_settime 3
.Sh STANDARDS
-Except for the lack of setting the system date and time,
.Nm
-is compliant with the
-.St -p1003.1-2008
+should be compliant with the
+IEEE Std 1003.1-2024 (“POSIX.1”)
specification.
.Pp
The
@@ -76,8 +108,11 @@ and
.Fl R
options are present for compatibility with other modern systems such as
NetBSD, BusyBox, and GNU coreutils.
+.br
The
.Fl f
-option is inspired by NetBSD.
+and
+.Fl j
+options are inspired by FreeBSD and NetBSD.
.Sh AUTHORS
.An Haelwenn (lanodan) Monnier Aq Mt contact+utils@hacktivis.me
diff --git a/cmd/date.c b/cmd/date.c
@@ -7,19 +7,25 @@
#include "../lib/iso_parse.h" /* iso_parse */
-#include <errno.h> /* errno */
+#include <assert.h>
+#include <errno.h>
#include <locale.h> /* setlocale() */
+#include <stdbool.h>
#include <stdio.h> /* BUFSIZ, perror(), puts() */
#include <stdlib.h> /* exit(), strtol() */
#include <string.h> /* strerror */
-#include <time.h> /* time, localtime, tm, strftime, strptime */
+#include <time.h> /* time, localtime, tm, strftime, strptime, clock_settime */
#include <unistd.h> /* getopt(), optarg, optind */
static void
usage()
{
- fprintf(stderr, "date [-uR] [-d datetime] [+format]\n");
- fprintf(stderr, "date [-uR] -f now_format now [+format]\n");
+ fprintf(stderr, "\
+Usage:\n\
+ date [-jRu] [-d datetime] [+format]\n\
+ date [-jRu] mmddHHMM[[CC]yy] [+format]\n\
+ date [-jRu] -f now_format now [+format]\n\
+");
}
int
@@ -33,6 +39,8 @@ main(int argc, char *argv[])
int uflag = 0;
int dflag = 0;
int c;
+ bool jflag = false;
+ bool settime = false;
errno = 0;
setlocale(LC_ALL, "");
@@ -49,7 +57,7 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- while((c = getopt(argc, argv, ":d:f:uR")) != -1)
+ while((c = getopt(argc, argv, ":d:f:jRu")) != -1)
{
char *errstr = NULL;
switch(c)
@@ -75,12 +83,16 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
input_format = optarg;
+ settime = true;
+ break;
+ case 'R': /* Email (RFC 5322) format */
+ format = "%a, %d %b %Y %H:%M:%S %z";
break;
case 'u': /* UTC timezone */
uflag++;
break;
- case 'R': /* Email (RFC 5322) format */
- format = "%a, %d %b %Y %H:%M:%S %z";
+ case 'j':
+ jflag = true;
break;
case ':':
fprintf(stderr, "date: Error: Missing operand for option: '-%c'\n", optopt);
@@ -130,8 +142,73 @@ main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
+ assert(errno == 0);
+ now = mktime(tm);
+ errno = 0;
+
+ argv++;
+ argc--;
+ }
+
+ if(input_format == NULL && argc > 0 && *argv && **argv != '+')
+ {
+ char *fmt = "%m%d%H%M";
+ char *s = strptime(*argv, fmt, tm);
+ if(s == NULL)
+ {
+ fprintf(stderr, "date: strptime(\"%s\", \"%s\", …) returned NULL\n", *argv, fmt);
+ exit(EXIT_FAILURE);
+ }
+
+ size_t rem = strlen(s);
+ if(rem > 0)
+ {
+ switch(rem)
+ {
+ case 2:
+ fmt = "%y";
+ break;
+ case 4:
+ fmt = "%Y";
+ break;
+ default:
+ fprintf(stderr, "date: Got %zu trailing characters after \"%s\" for mmddHHMM\n", rem, fmt);
+ exit(EXIT_FAILURE);
+ }
+
+ s = strptime(s, fmt, tm);
+ if(s == NULL)
+ {
+ fprintf(stderr, "date: strptime(\"%s\", \"%s\", …) returned NULL\n", *argv, fmt);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ assert(errno == 0);
+ now = mktime(tm);
+ errno = 0;
+
argv++;
argc--;
+ settime = true;
+ }
+
+ if(settime && !jflag)
+ {
+ struct timespec tp = {
+ .tv_sec = now,
+ .tv_nsec = 0,
+ };
+
+ if(clock_settime(CLOCK_REALTIME, &tp) != 0)
+ {
+ fprintf(stderr,
+ "date: Error clock_settime(CLOCK_REALTIME, {%ld, %ld}): %s\n",
+ tp.tv_sec,
+ tp.tv_nsec,
+ strerror(errno));
+ exit(EXIT_FAILURE);
+ }
}
if(argc > 0 && *argv && **argv == '+')
diff --git a/test-cmd/date.sh b/test-cmd/date.sh
@@ -3,7 +3,7 @@
# SPDX-License-Identifier: MPL-2.0
target="$(dirname "$0")/../cmd/date"
-plans=15
+plans=19
. "$(dirname "$0")/tap.sh"
unset TZ
@@ -39,7 +39,17 @@ t '1969-12-31T23:58:51.00Z' '-u -d 1969-12-31T23:58:51.00Z +%s' '-69
t '1969-12-31T23:58:51,00Z' '-u -d 1969-12-31T23:58:51,00Z +%s' '-69
'
-t 'f_option' '-u -f %Y-%m-%dT%H:%M:%S 2006-08-14T08:34:56 +%s' '1155544496
+t 'f_option' '-u -j -f %Y-%m-%dT%H:%M:%S 2006-08-14T08:34:56 +%s' '1155544496
+'
+
+# Note the lack of setting seconds
+t 'mmddHHMM' '-j 07250554 +%Y-%m-%dT%H:%M' "$(date +%Y-07-25T05:54)
+"
+t 'mmddHHMM24' '-j 0725055424 +%Y-%m-%dT%H:%M' '2024-07-25T05:54
+'
+t 'mmddHHMM69' '-j 0628012069 +%Y-%m-%dT%H:%M' '1969-06-28T01:20
+'
+t 'mmddHHMMCCyy' '-j 072505542024 +%Y-%m-%dT%H:%M' '2024-07-25T05:54
'
#usage="\