logo

utils-std

Collection of commonly available Unix tools
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:

Mcmd/date.1.in51+++++++++++++++++++++++++++++++++++++++++++--------
Mcmd/date.c91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
Mtest-cmd/date.sh14++++++++++++--
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="\