[newlib-cygwin/cygwin-acl] strftime: Add support for %s (seconds since epoch)

Corinna Vinschen corinna@sourceware.org
Tue Oct 27 10:11:00 GMT 2015


https://sourceware.org/git/gitweb.cgi?p=newlib-cygwin.git;h=e1bbdf12846611a28bc721897312e16c3a718d33

commit e1bbdf12846611a28bc721897312e16c3a718d33
Author: Brian Inglis <Brian.Inglis@SystematicSw.ab.ca>
Date:   Tue Oct 27 09:41:22 2015 +0100

    strftime: Add support for %s (seconds since epoch)
    
    	* libc/time/strftime.c (__strftime): add support for %s (seconds from
    	Unix epoch).  Fix whitespaces.
    
    Signed-off-by: Corinna Vinschen <corinna@vinschen.de>

Diff:
---
 newlib/ChangeLog            |   5 ++
 newlib/libc/time/strftime.c | 124 +++++++++++++++++++++++++++++++++++---------
 winsup/cygwin/release/2.3.0 |   2 +
 winsup/doc/ChangeLog        |   4 ++
 winsup/doc/new-features.xml |   4 ++
 5 files changed, 114 insertions(+), 25 deletions(-)

diff --git a/newlib/ChangeLog b/newlib/ChangeLog
index 6c9c6e2..a0892eb 100644
--- a/newlib/ChangeLog
+++ b/newlib/ChangeLog
@@ -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-14  Sebastian Huber  <sebastian.huber@embedded-brains.de>
 
 	* libc/stdlib/Makefile.am (GENERAL_SOURCES): Add alloc_aligned.c.c.
diff --git a/newlib/libc/time/strftime.c b/newlib/libc/time/strftime.c
index 9e67734..ced106a 100644
--- a/newlib/libc/time/strftime.c
+++ b/newlib/libc/time/strftime.c
@@ -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) ] */
diff --git a/winsup/cygwin/release/2.3.0 b/winsup/cygwin/release/2.3.0
index 48adb5f..b517abd 100644
--- a/winsup/cygwin/release/2.3.0
+++ b/winsup/cygwin/release/2.3.0
@@ -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.
 
diff --git a/winsup/doc/ChangeLog b/winsup/doc/ChangeLog
index cd6563b..f289628 100644
--- a/winsup/doc/ChangeLog
+++ b/winsup/doc/ChangeLog
@@ -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.
diff --git a/winsup/doc/new-features.xml b/winsup/doc/new-features.xml
index c95f339..d65145b 100644
--- a/winsup/doc/new-features.xml
+++ b/winsup/doc/new-features.xml
@@ -9,6 +9,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.
 </para><para>



More information about the Cygwin-cvs mailing list