ls(1): Return previous long format for C/POSIX locales
authorJohn Marino <draco@marino.st>
Fri, 20 Nov 2015 15:32:52 +0000 (16:32 +0100)
committerJohn Marino <draco@marino.st>
Fri, 20 Nov 2015 15:43:15 +0000 (16:43 +0100)
The output of ls -l for POSIX locales is covered by the POSIX standard.
The previous implementation was not compliance with the handling of
future timestamps.  The standard requires that future timestamps always
show the year where as previously it would only show the year if the
file's modification time was less than 6 months into the future.

This change detects if C/POSIX LC_TIME is specified, and if so, it
implements the long format as specified by the POSIX standard.  The
ISO 8601 format is still used for named locales.

Reported by: swildner

bin/ls/ls.1
bin/ls/print.c

index 0625099..e0d34e2 100644 (file)
@@ -150,8 +150,8 @@ When used with the
 (lowercase letter
 .Dq ell )
 option, display complete time information for the file, including
-month, day, hour, minute, second, and year using the ISO 8601 extended
-format.
+month, day, hour, minute, second, and year (named locales use the
+ISO 8601 extended format).
 .It Fl W
 Display whiteouts when scanning directories.
 .It Fl a
@@ -327,13 +327,17 @@ is displayed for each file:
 file mode,
 number of links, owner name, group name,
 number of bytes in the file,
-last modified time in ISO 8601 basic format reduced to
-hour accuracy, and the pathname.
+last modified time in either per POSIX requirements or per
+ISO 8601 basic format reduced to hour accuracy, and the pathname.
 In addition, for each directory whose contents are displayed, the total
 number of 512-byte blocks used by the files in the directory is displayed
 on a line by itself immediately before the information for the files in the
 directory.
 .Pp
+In the POSIX locale, If the modification time of the file is in the future,
+or more than 6 months in the past, then the year of the last modification
+is displayed in place of the hour and minute fields.
+.Pp
 If the owner or group names are not a known user or group name,
 or the
 .Fl n
index 7519e37..98441ff 100644 (file)
@@ -46,6 +46,7 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <locale.h>
 #ifdef COLORLS
 #include <ctype.h>
 #include <termcap.h>
@@ -349,16 +350,43 @@ printtime(time_t ftime)
        char longstring[80];
        static time_t now;
        const char *format;
+       static char *lc_time;
+       static int posix_time;
+
+#define        SIXMONTHS       ((365 / 2) * 86400)
 
        if (now == 0)
                now = time(NULL);
 
-       if (f_sectime)
-               /* ISO 8601 (extended without T): YYYY-DD-MM hh:mm:ss */
-               format = "%F %T ";
-       else
-               /* ISO 8601 (basic with T): YYYYDDMMThh */
+       if (lc_time == NULL) {
+               lc_time = setlocale(LC_TIME, NULL);
+               posix_time = (strcmp(lc_time, "C") == 0);
+       }
+
+       if (f_sectime) {
+               /*
+                * POSIX: Not covered by standard.  If C/POSIX locale used
+                *        the old convention of mmm dd hh:mm:ss yyyy is kept.
+                * Named locales use the extended ISO 8601 format without T:
+                *        YYYY-DD-MM hh:mm:ss
+                */
+               format = posix_time ? "%b %e %T %Y " : "%F %T ";
+       } else if (posix_time) {
+               /*
+                * POSIX: Future or older than 6 months returns equivalent of
+                *        date "+%b %e  %Y"
+                *        If file was modified within the past 6 months,
+                *        return equivalent of: date "+%b %e %H:%M"
+                */
+               if (ftime + SIXMONTHS > now)
+                       format = "%b %e %R ";
+               else
+                       format = "%b %e  %Y ";
+       } else {
+               /* Named locales use ISO 8601 (basic with T): YYYYDDMMThh */
                format = "%Y%m%dT%H ";
+       }
+
        strftime(longstring, sizeof(longstring), format, localtime(&ftime));
        fputs(longstring, stdout);
 }