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>
This commit is contained in:
Brian Inglis 2015-10-27 09:41:22 +01:00 committed by Corinna Vinschen
parent cf51db8baa
commit 6090952296
5 changed files with 114 additions and 25 deletions

View 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

View 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) ] */

View 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.

View 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.

View 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.