coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [coreutils] [PATCH 2/2] stat: print timestamps to full resolution


From: Eric Blake
Subject: Re: [coreutils] [PATCH 2/2] stat: print timestamps to full resolution
Date: Fri, 01 Oct 2010 09:03:07 -0600
User-agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.9) Gecko/20100921 Fedora/3.1.4-1.fc13 Mnenhy/0.8.3 Thunderbird/3.1.4

On 10/01/2010 02:21 AM, Jim Meyering wrote:

+static char * ATTRIBUTE_WARN_UNUSED_RESULT
+epoch_time (struct timespec t)
+{
+  static char str[INT_STRLEN_BOUND (time_t) + sizeof ".NNNNNNNNN"];
+  if (TYPE_SIGNED (time_t))
+    sprintf (str, "%" PRIdMAX ".%09lu", (intmax_t) t.tv_sec,
+             (unsigned long) t.tv_nsec);
+  else
+    sprintf (str, "%" PRIuMAX ".%09lu", (uintmax_t) t.tv_sec,
+             (unsigned long) t.tv_nsec);
+  return str;

time_t can be a float on weird platforms I think?

If you use nstrftime, no one can complain ;-)

Correct - time_t need not be integral, but do we have any proof of a system using a floating-point time_t? Using nstrftime("%s.%N") would indeed avoid that issue, but at what expense? We'd have to convert t.tv_sec to a struct tm, just to have nstrftime convert that struct back to a time_t.

As it is, nstrftime's approach risks rounding errors if time_t is a floating point (should this be reported as a theoretical bug to the gnulib list?):

            /* Generate string value for T using time_t arithmetic;
               this works even if sizeof (long) < sizeof (time_t).  */

            bufp = buf + sizeof (buf) / sizeof (buf[0]);
            negative_number = t < 0;

            do
              {
                int d = t % 10;
                t /= 10;
                *--bufp = (negative_number ? -d : d) + L_('0');
              }
            while (t != 0);

I'm thinking that sticking with a cast to [u]intmax_t is the right thing to do for now, but am adding a comment to the source code.


Other than that, my only suggestion would be to mention what
these directives mean, so the NEWS entry stands more on its own.
I had to look them up.

   +  stat now outputs the full timestamp resolution for the %X, %Y, and
   +  %Z format directives.

Reworded accordingly, and moved to changed behavior rather than new feature.

diff --git i/NEWS w/NEWS
index 690f693..2ce03e3 100644
--- i/NEWS
+++ w/NEWS
@@ -40,9 +40,6 @@ GNU coreutils NEWS -*- outline -*-
   for a file.  It also accepts the %w and %W format directives for
   outputting the birth time of a file, if one is available.

-  stat now outputs the full timestamp resolution for the %X, %Y, and
-  %Z format directives.
-
 ** Changes in behavior

   df now consistently prints the device name for a bind mounted file,
@@ -78,6 +75,11 @@ GNU coreutils NEWS -*- outline -*-
   merely accepted and ignored, for compatibility.  Starting two years
   ago, with coreutils-7.0, its use evoked a warning.

+  stat now outputs the full sub-second resolution for the atime,
+  mtime, and ctime values since the Epoch, when using the %X, %Y, and
+  %Z directives of the --format option.  This matches the fact that
+  %x, %y, and %z were already doing so for the human-readable variant.
+
   touch's --file option is no longer recognized.  Use --reference=F (-r)
   instead.  --file has not been documented for 15 years, and its use has
   elicited a warning since coreutils-7.1.
diff --git i/src/stat.c w/src/stat.c
index b809330..5d5e620 100644
--- i/src/stat.c
+++ w/src/stat.c
@@ -465,6 +465,15 @@ static char * ATTRIBUTE_WARN_UNUSED_RESULT
 epoch_time (struct timespec t)
 {
   static char str[INT_STRLEN_BOUND (time_t) + sizeof ".NNNNNNNNN"];
+  /* Note that time_t can technically be a floating point value, such
+     that casting to [u]intmax_t could lose a fractional value or
+     suffer from overflow.  However, most porting targets have an
+     integral time_t; also, we know of no file systems that store
+     valid time values outside the bounds of intmax_t even if that
+     value were represented as a floating point.  Besides, the cost of
+     converting to struct tm just to use nstrftime (str, len, "%s.%N",
+     tm, 0, t.tv_nsec) is pointless, since nstrftime would have to
+     convert back to seconds as time_t.  */
   if (TYPE_SIGNED (time_t))
     sprintf (str, "%" PRIdMAX ".%09lu", (intmax_t) t.tv_sec,
              (unsigned long) t.tv_nsec);
diff --git i/tests/misc/stat-birthtime w/tests/misc/stat-birthtime
index d4f372e..2da326a 100755
--- i/tests/misc/stat-birthtime
+++ w/tests/misc/stat-birthtime
@@ -33,8 +33,7 @@ ctime=$(stat --format %Z a) || fail=1

 case $(stat --format %x a) in
   *.000000000*) sleep 2;; # worst case file system is FAT
-  *) # FIXME: sleep .1 would be sufficient if %X showed nanoseconds
- sleep 1;; # should be adequate for any system with subsecond resolution
+ *) sleep .1;; # should be adequate for any system with subsecond resolution
 esac

 touch a || fail=1


--
Eric Blake   address@hidden    +1-801-349-2682
Libvirt virtualization library http://libvirt.org



reply via email to

[Prev in Thread] Current Thread [Next in Thread]