Include timespec.h.
authorJim Meyering <jim@meyering.net>
Fri, 1 Mar 2002 23:57:21 +0000 (23:57 +0000)
committerJim Meyering <jim@meyering.net>
Fri, 1 Mar 2002 23:57:21 +0000 (23:57 +0000)
(strftime, time, stime): Remove declarations; no longer needed.
(usage): Document %N.
(main): Use gettime rather than time to get the time of day,
so that we can get fractional times.
Similarly for settime and stime, so that we can set fractional times
(though this currently is not available to the user since we don't
parse fractional times; add FIXMES for that).
Check for gettime failures; e.g. this can occur if it
is past 2038 and we are a 32-bit app running on a 64-bit OS.
Get fractional part of file time stamps.
Do not falsely report failures just because time_t happens to be -1
(e.g. a file time stamp 1 second before the epoch).
(show_date): 2nd arg is now struct timespec, not time_t.
All uses changed.  Use nstrftime rather than strftime, so that
we can format fractional seconds.

src/date.c

index cc26595..2942169 100644 (file)
 #include "getline.h"
 #include "posixtm.h"
 #include "posixver.h"
+#include "timespec.h"
 
 /* The official name of this program (e.g., no `g' prefix).  */
 #define PROGRAM_NAME "date"
 
 #define AUTHORS "David MacKenzie"
 
-#ifndef STDC_HEADERS
-size_t strftime ();
-time_t time ();
-#endif
-
 int putenv ();
-int stime ();
 
-static void show_date PARAMS ((const char *format, time_t when));
+size_t nstrftime PARAMS ((char *, size_t, char const *,
+                         struct tm const *, int, int));
+
+static void show_date PARAMS ((const char *format, struct timespec when));
 
 enum Time_spec
 {
@@ -181,6 +179,7 @@ specifies Coordinated Universal Time.  Interpreted sequences are:\n\
 "), stdout);
       fputs (_("\
   %n   a newline\n\
+  %N   nanoseconds (000000000..999999999)\n\
   %p   locale's upper case AM or PM indicator\n\
   %P   locale's lower case am or pm indicator\n\
   %r   time, 12-hour (hh:mm:ss [AP]M)\n\
@@ -233,7 +232,7 @@ batch_convert (const char *input_filename, const char *format)
   char *line;
   int line_length;
   size_t buflen;
-  time_t when;
+  struct timespec when;
 
   if (strcmp (input_filename, "-") == 0)
     {
@@ -261,9 +260,10 @@ batch_convert (const char *input_filename, const char *format)
          break;
        }
 
-      when = get_date (line, NULL);
+      when.tv_sec = get_date (line, NULL);
+      when.tv_nsec = 0; /* FIXME: get_date should set this.  */
 
-      if (when == -1)
+      if (when.tv_sec == -1)
        {
          if (line[line_length - 1] == '\n')
            line[line_length - 1] = '\0';
@@ -291,7 +291,7 @@ main (int argc, char **argv)
   int optc;
   const char *datestr = NULL;
   const char *set_datestr = NULL;
-  time_t when;
+  struct timespec when;
   int set_date = 0;
   char *format;
   char *batch_file = NULL;
@@ -411,6 +411,7 @@ argument must be a format string beginning with `+'."),
     }
   else
     {
+      bool invalid_date = false;
       status = 0;
 
       if (!option_specified_date && !set_date)
@@ -421,15 +422,19 @@ argument must be a format string beginning with `+'."),
                 given in the POSIX-format.  */
              set_date = 1;
              datestr = argv[optind];
-             when = posixtime (datestr,
-                               PDS_TRAILING_YEAR | PDS_CENTURY | PDS_SECONDS);
+             when.tv_sec = posixtime (datestr,
+                                      (PDS_TRAILING_YEAR
+                                       | PDS_CENTURY | PDS_SECONDS));
+             when.tv_nsec = 0; /* FIXME: posixtime should set this.  */
+             invalid_date = (when.tv_sec == (time_t) -1);
              format = NULL;
            }
          else
            {
              /* Prepare to print the current date/time.  */
              datestr = _("undefined");
-             time (&when);
+             if (gettime (&when) != 0)
+               error (EXIT_FAILURE, errno, _("cannot get time of day"));
              format = (n_args == 1 ? argv[optind] + 1 : NULL);
            }
        }
@@ -440,24 +445,27 @@ argument must be a format string beginning with `+'."),
            {
              if (stat (reference, &refstats))
                error (1, errno, "%s", reference);
-             when = refstats.st_mtime;
+             when.tv_sec = refstats.st_mtime;
+             when.tv_nsec = TIMESPEC_NS (refstats.st_mtim);
            }
          else
            {
-             when = get_date (datestr, NULL);
+             when.tv_sec = get_date (datestr, NULL);
+             when.tv_nsec = 0; /* FIXME: get_date should set this.  */
+             invalid_date = (when.tv_sec == (time_t) -1);
            }
 
          format = (n_args == 1 ? argv[optind] + 1 : NULL);
        }
 
-      if (when == -1)
+      if (invalid_date)
        error (1, 0, _("invalid date `%s'"), datestr);
 
       if (set_date)
        {
          /* Set the system clock to the specified date, then regardless of
             the success of that operation, format and print that date.  */
-         if (stime (&when) == -1)
+         if (settime (&when) != 0)
            {
              error (0, errno, _("cannot set date"));
              status = 1;
@@ -475,7 +483,7 @@ argument must be a format string beginning with `+'."),
    standard output format (ctime style but with a timezone inserted). */
 
 static void
-show_date (const char *format, time_t when)
+show_date (const char *format, struct timespec when)
 {
   struct tm *tm;
   char *out = NULL;
@@ -489,17 +497,10 @@ show_date (const char *format, time_t when)
     "%Y-%m-%dT%H:%M:%S%z"
   };
 
-  tm = localtime (&when);
+  tm = localtime (&when.tv_sec);
 
   if (format == NULL)
     {
-      /* Print the date in the default format.  Vanilla ANSI C strftime
-         doesn't support %e, but POSIX requires it.  If you don't use
-         a GNU strftime, make sure yours supports %e.
-        If you are not using GNU strftime, you want to change %z
-        in the RFC format to %Z; this gives, however, an invalid
-        RFC time format outside the continental United States and GMT. */
-
       if (rfc_format)
        format = "%a, %d %b %Y %H:%M:%S %z";
       else if (iso_8601_format)
@@ -530,7 +531,7 @@ show_date (const char *format, time_t when)
       out = (char *) xrealloc (out, out_length);
 
       /* Mark the first byte of the buffer so we can detect the case
-        of strftime producing an empty string.  Otherwise, this loop
+        of nstrftime producing an empty string.  Otherwise, this loop
         would not terminate when date was invoked like this
         `LANG=de date +%p' on a system with good language support.  */
       out[0] = '\1';
@@ -538,7 +539,8 @@ show_date (const char *format, time_t when)
       if (rfc_format)
        setlocale (LC_ALL, "C");
 
-      done = (strftime (out, out_length, format, tm) || out[0] == '\0');
+      done = (nstrftime (out, out_length, format, tm, 0, when.tv_nsec)
+             || out[0] == '\0');
 
       if (rfc_format)
        setlocale (LC_ALL, "");