]> sourceware.org Git - newlib-cygwin.git/commitdiff
strftime: Add support for %s (seconds since epoch)
authorBrian Inglis <Brian.Inglis@SystematicSw.ab.ca>
Tue, 27 Oct 2015 08:41:22 +0000 (09:41 +0100)
committerCorinna Vinschen <corinna@vinschen.de>
Tue, 27 Oct 2015 08:41:40 +0000 (09:41 +0100)
* libc/time/strftime.c (__strftime): add support for %s (seconds from
Unix epoch).  Fix whitespaces.

Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
newlib/ChangeLog
newlib/libc/time/strftime.c
winsup/cygwin/release/2.3.0
winsup/doc/ChangeLog
winsup/doc/new-features.xml

index 94b1f7b81ee434cbac6ea518fc4f34fc488808e3..2c0cc5b8094dc1474bf335fc46cd594c43762665 100644 (file)
@@ -1,3 +1,8 @@
+2015-10-26  Brian Inglis  <Brian.Inglis@SystematicSw.ab.ca>
+
+       * libc/time/strftime.c (__strftime): add support for %s (seconds from
+       Unix epoch).  Fix whitespaces.
+
 2015-10-19  Nick Clifton  <nickc@redhat.com>
 
        * libc/include/sys/_intsup.h: Add support for 16-bit and 20-bit
index 9e677346ebcd184a56d1a38fe0b0f2a8bfbfe2af..ced106a5b6caae8438ef7007f438bd0755a3105d 100644 (file)
@@ -79,7 +79,7 @@ The century, that is, the year divided by 100 then truncated.  For
 4-digit years, the result is zero-padded and exactly two characters;
 but for other years, there may a negative sign or more digits.  In
 this way, `<<%C%y>>' is equivalent to `<<%Y>>'. [tm_year]
+
 o %d
 The day of the month, formatted with two digits (from `<<01>>' to
 `<<31>>'). [tm_mday]
@@ -110,7 +110,7 @@ includes January 4th, and begin on Mondays. Therefore, if January 1st,
 2nd, or 3rd falls on a Sunday, that day and earlier belong to the last
 week of the previous year; and if December 29th, 30th, or 31st falls
 on Monday, that day and later belong to week 1 of the next year.  For
-consistency with %Y, it always has at least four characters. 
+consistency with %Y, it always has at least four characters.
 Example: "%G" for Saturday 2nd January 1999 gives "1998", and for
 Tuesday 30th December 1997 gives "1998". [tm_year, tm_wday, tm_yday]
 
@@ -166,6 +166,10 @@ notations, the result is an empty string. [tm_sec, tm_min, tm_hour]
 o %R
 The 24-hour time, to the minute.  Equivalent to "%H:%M". [tm_min, tm_hour]
 
+o %s
+The time elapsed, in seconds, since the start of the Unix epoch at
+1970-01-01 00:00:00 UTC.
+
 o %S
 The second, formatted with two digits (from `<<00>>' to `<<60>>').  The
 value 60 accounts for the occasional leap second. [tm_sec]
@@ -273,7 +277,7 @@ the "C" locale settings.
 #include <wctype.h>
 #include "local.h"
 #include "../locale/timelocal.h"
+
 /* Defines to make the file dual use for either strftime() or wcsftime().
  * To get wcsftime, define MAKE_WCSFTIME.
  * To get strftime, do not define MAKE_WCSFTIME.
@@ -738,7 +742,7 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
       if (*format == CQ('E'))
        {
          alt = *format++;
-#ifdef _WANT_C99_TIME_FORMATS      
+#ifdef _WANT_C99_TIME_FORMATS
 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
          if (!*era_info && *_CurrentTimeLocale->wera)
            *era_info = get_era_info (tim_p, _CurrentTimeLocale->wera);
@@ -751,7 +755,7 @@ _DEFUN (strftime, (s, maxsize, format, tim_p),
       else if (*format == CQ('O'))
        {
          alt = *format++;
-#ifdef _WANT_C99_TIME_FORMATS      
+#ifdef _WANT_C99_TIME_FORMATS
 #if defined (MAKE_WCSFTIME) && defined (__HAVE_LOCALE_INFO_EXTENDED__)
          if (!*alt_digits && *_CurrentTimeLocale->walt_digits)
            *alt_digits = get_alt_digits (_CurrentTimeLocale->walt_digits);
@@ -934,7 +938,7 @@ recurse:
          { /* %F is equivalent to "%+4Y-%m-%d", flags and width can change
               that.  Recurse to avoid need to replicate %Y formation. */
            CHAR fmtbuf[32], *fmt = fmtbuf;
-           
+
            *fmt++ = CQ('%');
            if (pad) /* '0' or '+' */
              *fmt++ = pad;
@@ -1109,6 +1113,74 @@ recurse:
                          tim_p->tm_hour, tim_p->tm_min);
           CHECK_LENGTH ();
           break;
+       case CQ('s'):
+/*
+ * From:
+ * The Open Group Base Specifications Issue 7
+ * IEEE Std 1003.1, 2013 Edition
+ * Copyright (c) 2001-2013 The IEEE and The Open Group
+ * XBD Base Definitions
+ * 4. General Concepts
+ * 4.15 Seconds Since the Epoch
+ * A value that approximates the number of seconds that have elapsed since the
+ * Epoch. A Coordinated Universal Time name (specified in terms of seconds
+ * (tm_sec), minutes (tm_min), hours (tm_hour), days since January 1 of the year
+ * (tm_yday), and calendar year minus 1900 (tm_year)) is related to a time
+ * represented as seconds since the Epoch, according to the expression below.
+ * If the year is <1970 or the value is negative, the relationship is undefined.
+ * If the year is >=1970 and the value is non-negative, the value is related to a
+ * Coordinated Universal Time name according to the C-language expression, where
+ * tm_sec, tm_min, tm_hour, tm_yday, and tm_year are all integer types:
+ * tm_sec + tm_min*60 + tm_hour*3600 + tm_yday*86400 +
+ *     (tm_year-70)*31536000 + ((tm_year-69)/4)*86400 -
+ *     ((tm_year-1)/100)*86400 + ((tm_year+299)/400)*86400
+ * OR
+ * ((((tm_year-69)/4 - (tm_year-1)/100 + (tm_year+299)/400 +
+ *         (tm_year-70)*365 + tm_yday)*24 + tm_hour)*60 + tm_min)*60 + tm_sec
+ */
+/* modified from %z case by hoisting offset outside if block and initializing */
+         {
+           long offset = 0;    /* offset < 0 => W of GMT, > 0 => E of GMT:
+                                  subtract to get UTC */
+
+           if (tim_p->tm_isdst >= 0)
+             {
+               TZ_LOCK;
+               if (!tzset_called)
+                 {
+                   _tzset_unlocked ();
+                   tzset_called = 1;
+                 }
+
+#if defined (__CYGWIN__)
+               /* Cygwin must check if the application has been built with or
+                  without the extra tm members for backward compatibility, and
+                  then use either that or the old method fetching from tzinfo.
+                  Rather than pulling in the version check infrastructure, we
+                  just call a Cygwin function. */
+               extern long __cygwin_gettzoffset (const struct tm *tmp);
+               offset = __cygwin_gettzoffset (tim_p);
+#elif defined (__TM_GMTOFF)
+               offset = tim_p->__TM_GMTOFF;
+#else
+               __tzinfo_type *tz = __gettzinfo ();
+               /* The sign of this is exactly opposite the envvar TZ.  We
+                  could directly use the global _timezone for tm_isdst==0,
+                  but have to use __tzrule for daylight savings.  */
+               offset = -tz->__tzrule[tim_p->tm_isdst > 0].offset;
+#endif
+               TZ_UNLOCK;
+             }
+           len = snprintf (&s[count], maxsize - count, CQ("%lld"),
+                           (((((long long)tim_p->tm_year - 69)/4
+                               - (tim_p->tm_year - 1)/100
+                               + (tim_p->tm_year + 299)/400
+                               + (tim_p->tm_year - 70)*365 + tim_p->tm_yday)*24
+                             + tim_p->tm_hour)*60 + tim_p->tm_min)*60
+                           + tim_p->tm_sec - offset);
+           CHECK_LENGTH ();
+         }
+          break;
        case CQ('S'):
 #ifdef _WANT_C99_TIME_FORMATS
          if (alt != CQ('O') || !*alt_digits
@@ -1378,13 +1450,13 @@ recurse:
 /* The remainder of this file can serve as a regression test.  Compile
  *  with -D_REGRESSION_TEST.  */
 #if defined(_REGRESSION_TEST)  /* [Test code:  */
+
 /* This test code relies on ANSI C features, in particular on the ability
  * of adjacent strings to be pasted together into one string.  */
+
 /* Test output buffer size (should be larger than all expected results) */
 #define OUTSIZE        256
+
 struct test {
        CHAR  *fmt;     /* Testing format */
        size_t  max;    /* Testing maxsize */
@@ -1396,9 +1468,9 @@ struct list {
        const struct test *vec; /* Test vectors */
        int  cnt;               /* Number of vectors */
        };
+
 const char  TZ[]="TZ=EST5EDT";
+
 /* Define list of test inputs and expected outputs, for the given time zone
  * and time.  */
 const struct tm  tm0 = {
@@ -1442,6 +1514,7 @@ const struct test  Vec0[] = {
        { CQ("%p"), 2+1, EXP(CQ("AM")) },
        { CQ("%r"), 11+1, EXP(CQ("09:53:47 AM")) },
        { CQ("%R"), 5+1, EXP(CQ("09:53")) },
+       { CQ("%s"), 2+1, EXP(CQ("1230648827")) },
        { CQ("%S"), 2+1, EXP(CQ("47")) },
        { CQ("%t"), 1+1, EXP(CQ("\t")) },
        { CQ("%T"), 8+1, EXP(CQ("09:53:47")) },
@@ -1502,6 +1575,7 @@ const struct test  Vec1[] = {
        { CQ("%p"), 2+1, EXP(CQ("PM")) },
        { CQ("%r"), 11+1, EXP(CQ("11:01:13 PM")) },
        { CQ("%R"), 5+1, EXP(CQ("23:01")) },
+       { CQ("%s"), 2+1, EXP(CQ("1215054073")) },
        { CQ("%S"), 2+1, EXP(CQ("13")) },
        { CQ("%t"), 1+1, EXP(CQ("\t")) },
        { CQ("%T"), 8+1, EXP(CQ("23:01:13")) },
@@ -1526,7 +1600,7 @@ const struct test  Vec1[] = {
        #undef VEC
        #undef EXP
        };
+
 #if YEAR_BASE == 1900  /* ( */
 /* Checks for very large years.  YEAR_BASE value relied upon so that the
  * answer strings can be predetermined.
@@ -1624,7 +1698,7 @@ const struct test  Vecyr1[] = {
 #undef CENT
 #undef Year
 #endif /* YEAR_BASE ) */
+
 /* Checks for years just over zero (also test for s=60).
  * Years less than 4 digits are not mentioned for %Y in the standard, so the
  * test for that case is based on the design intent.  */
@@ -1695,7 +1769,7 @@ const struct test  Vecyrzn[] = {
 #undef YEAR
 #undef CENT
 #undef Year
+
 const struct list  ListYr[] = {
        { &tmyrzp, Vecyrzp, sizeof(Vecyrzp)/sizeof(Vecyrzp[0]) },
        { &tmyrzn, Vecyrzn, sizeof(Vecyrzn)/sizeof(Vecyrzn[0]) },
@@ -1704,19 +1778,19 @@ const struct list  ListYr[] = {
        { &tmyr1, Vecyr1, sizeof(Vecyr1)/sizeof(Vecyr1[0]) },
        #endif
        };
+
+
 /* List of tests to be run */
 const struct list  List[] = {
        { &tm0, Vec0, sizeof(Vec0)/sizeof(Vec0[0]) },
        { &tm1, Vec1, sizeof(Vec1)/sizeof(Vec1[0]) },
        };
+
 #if defined(STUB_getenv_r)
 char *
 _getenv_r(struct _reent *p, const char *cp) { return getenv(cp); }
 #endif
+
 int
 main(void)
 {
@@ -1724,7 +1798,7 @@ int  i, l, errr=0, erro=0, tot=0;
 const char  *cp;
 CHAR  out[OUTSIZE];
 size_t  ret;
+
 /* Set timezone so that %z and %Z tests come out right */
 cp = TZ;
 if((i=putenv(cp)))  {
@@ -1736,7 +1810,7 @@ if(strcmp(getenv("TZ"),strchr(TZ,'=')+1))  {
     return(-2);
     }
 tzset();
+
 #if defined(VERBOSE)
 printf("_timezone=%d, _daylight=%d, _tzname[0]=%s, _tzname[1]=%s\n", _timezone, _daylight, _tzname[0], _tzname[1]);
 {
@@ -1748,7 +1822,7 @@ __tzinfo_type *tz = __gettzinfo ();
 printf("tz->__tzrule[0].offset=%d, tz->__tzrule[1].offset=%d\n", tz->__tzrule[0].offset, tz->__tzrule[1].offset);
 }
 #endif
+
 /* Run all of the exact-length tests as-given--results should match */
 for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
     const struct list  *test = &List[l];
@@ -1769,7 +1843,7 @@ for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
            }
        }
     }
+
 /* Run all of the exact-length tests with the length made too short--expect to
  * fail.  */
 for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
@@ -1795,7 +1869,7 @@ for(l=0; l<sizeof(List)/sizeof(List[0]); l++)  {
            }
        }
     }
+
 /* Run all of the special year test cases */
 for(l=0; l<sizeof(ListYr)/sizeof(ListYr[0]); l++)  {
     const struct list  *test = &ListYr[l];
@@ -1816,14 +1890,14 @@ for(l=0; l<sizeof(ListYr)/sizeof(ListYr[0]); l++)  {
            }
        }
     }
+
 #define STRIZE(f)      #f
 #define NAME(f)        STRIZE(f)
 printf(NAME(strftime) "() test ");
 if(errr || erro)  printf("FAILED %d/%d of", errr, erro);
   else    printf("passed");
 printf(" %d test cases.\n", tot);
+
 return(errr || erro);
 }
 #endif /* defined(_REGRESSION_TEST) ] */
index 14ca3d40dfa47c729c9ccb2418a921cdece63175..9a44bab475d63a126c59931e18430052ff854d2d 100644 (file)
@@ -1,6 +1,8 @@
 What's new:
 -----------
 
+- strftime(3) supports %s (seconds since Epoch) now.
+
 - posix_madvise(POSIX_MADV_WILLNEED) now utilizes OS functionality available
   starting with Windows 8/Server 2012.  Still a no-op on older systems.
 
index cd6563b634ba4c9b63f40cd32d67d5fae10b7fd1..f2896288097951cbc5f573bd9e251c770ba2eee7 100644 (file)
@@ -1,3 +1,7 @@
+2015-10-27  Corinna Vinschen  <corinna@vinschen.de>
+
+       * new-features.xml (ov-new2.3): Document strftime %s addition.
+
 2015-10-22  Corinna Vinschen  <corinna@vinschen.de>
 
        * posix.xml (std-iso): New section.
index 4e0f3e2bfb73129d296da03fd631293a43dc53cd..469312fee1455ead0da4629cf73a70d499f635f4 100644 (file)
@@ -8,6 +8,10 @@
 
 <itemizedlist mark="bullet">
 
+<listitem><para>
+strftime(3) supports %s (seconds since Epoch) now.
+</para></listitem>
+
 <listitem><para>
 posix_madvise(POSIX_MADV_WILLNEED) now utilizes OS functionality available
 starting with Windows 8/Server 2012.
This page took 0.062775 seconds and 5 git commands to generate.