Mail Archives: djgpp-workers/2004/10/24/20:44:04
X-Authentication-Warning: | delorie.com: mail set sender to djgpp-workers-bounces using -f
|
Date: | Sun, 24 Oct 2004 18:43:49 -0600
|
From: | Brian Inglis <Brian DOT Inglis AT SystematicSw DOT ab DOT ca>
|
Subject: | Re: C99 strftime and Related Changes
|
To: | djgpp-workers <djgpp-workers AT delorie DOT com>
|
Message-id: | <puion0tjsn0bl0sjtipt4koi5qn3l2ckcd@4ax.com>
|
Organization: | Systematic Software
|
MIME-version: | 1.0
|
X-Mailer: | Forte Agent 1.93/32.576 English (American)
|
X-MIME-Autoconverted: | from quoted-printable to 8bit by delorie.com id i9P0i3wD013256
|
Reply-To: | djgpp-workers AT delorie DOT com
|
On Thu, 18 Mar 2004 03:07:04 -0700, Brian Inglis
<Brian DOT Inglis AT SystematicSw DOT ab DOT ca> wrote:
>13 files, 1748 lines, 57294 bytes
Here they are inline, then.
CONTENTS C99 Time Related Changes
liblocal.02/src/ansi/locale/setlocal.pat to
liblocal.02/src/ansi/locale/setlocal.c
liblocal.02/src/ansi/time/strftime.pat to
liblocal.02/src/ansi/time/strftime.c
djgpp/src/libc/ansi/time/strftime.pat to
djgpp/src/libc/ansi/time/strftime.c
djgpp/src/libc/ansi/time/strftxh.pat to
djgpp/src/libc/ansi/time/strftime.txh
djgpp/tests/libc/ansi/time/makefile.pat to
djgpp/tests/libc/ansi/time/makefile
djgpp/tests/libc/ansi/time/strftime.pat to
djgpp/tests/libc/ansi/time/strftime.c
djgpp/tests/libc/ansi/time/xstrftm.pat to
djgpp/tests/libc/ansi/time/xstrftm.c
djgpp/tests/libc/ansi/time/strftiml.pat to
djgpp/tests/libc/ansi/time/strftiml.c NEW
djgpp/tests/libc/ansi/time/strftimt.pat to
djgpp/tests/libc/ansi/time/strftimt. NEW
CHANGES C99 Time Related Changes
liblocal.02/src/ansi/locale/setlocal.c
fix problem resetting standard locale and returning updated locale
name
liblocal.02/src/ansi/time/strftime.c
src/libc/ansi/time/strftime.c
#define required constants;
add YEAR() conversion macro and ISLEAPYEAR() test macro;
add weekday enum definitions;
add iso_year() and iso_week() functions;
accept and ignore C99 E and O modifiers;
add C99 %F, %G, %g, %V formats;
add %s (GNU) format;
fix %z ISO 8601/RFC 822 time zone results
src/libc/ansi/time/strftime.txh
add new formats; add all modifiers; make descriptions consistent
tests/libc/ansi/time/makefile
add strftiml.c and strftimt.c tests
tests/libc/ansi/time/strftime.c
change inline macro calls to table driven tests;
add new tests and results for all formats, including unsupported
letters
tests/libc/ansi/time/xstrftm.c
add standard and current locale changes; output each locale name
tests/libc/ansi/time/strftiml.c
list all formats, including unsupported letters
tests/libc/ansi/time/strftimt.c
exception tester covering all formats;
table driven supporting locales and time zones;
many corner cases for non/ISO week and weekdays
--- setlocal.c 2002-07-17 02:16:36.000000000 -0600
+++ setlocal.c 2004-02-24 01:57:18.000000000 -0700
@@ -465,15 +465,17 @@ setlocale(int category, const char *loca
if (locale[0] == '\0')
{
const char *env;
- if ((env = getenv ("LANG")) != NULL)
+ if ((env = getenv (cat[i].env)) != NULL)
{
locale = env;
}
- if ((env = getenv (cat[i].env)) != NULL)
+ else
+ if ((env = getenv ("LC_ALL")) != NULL)
{
locale = env;
}
- if ((env = getenv ("LC_ALL")) != NULL)
+ else
+ if ((env = getenv ("LANG")) != NULL)
{
locale = env;
}
@@ -481,7 +483,10 @@ setlocale(int category, const char *loca
if ((stricmp(locale, "C") == 0) || (stricmp(locale, "POSIX")
== 0))
{
if (cat[i].reset() == 0)
+ {
honored = 0;
+ continue;
+ }
}
else
{
@@ -559,10 +564,10 @@ setlocale(int category, const char *loca
honored = 0;
continue;
}
-
- strncpy(lc_current[i], locale, LC_MAXNAMESIZE);
- lc_current[i][LC_MAXNAMESIZE - 1] = '\0';
}
+
+ strncpy(lc_current[i], locale, LC_MAXNAMESIZE);
+ lc_current[i][LC_MAXNAMESIZE - 1] = '\0';
}
}
if (segment != -1)
@@ -607,8 +612,8 @@ setlocale(int category, const char *loca
#include <stdio.h>
unsigned char __dj_collate_table[256];
-char __dj_date_format[10] = "%m/%d/%y";
-char __dj_time_format[16] = "%H:%M:%S";
+extern char __dj_date_format[10];
+extern char __dj_time_format[16];
int
main(int ac, char *av[])
--- strftime.c 2002-06-08 04:18:06.000000000 -0600
+++ strftime.c 2004-02-29 00:04:48.000000000 -0700
@@ -1,13 +1,57 @@
+/* Copyright (C) 2003 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 2001 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1999 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
/* Copyright (C) 1994 DJ Delorie, see COPYING.DJ for details */
-
#include <string.h>
#include <time.h>
#include <ctype.h>
+#include <stdlib.h>
+#if 0 /* DEBUG */
+#include <stdio.h>
+#endif /* 0 */
+
+
+
+#define TM_YEAR_BASE 1900 /* tm year epoch base
*/
+#define LEAP_CENTURIES 4 /* centuries between leap
centuries */
+#define CENTURY_YEARS 100 /* years per century
*/
+#define LEAP_CENTURY_YEARS (LEAP_CENTURIES * CENTURY_YEARS) /*
years */
+#define LEAP_YEARS 4 /* years between leap years
*/
+#define YEAR_DAYS 365 /* days in common year
*/
+#define HOUR_MINS 60 /* minutes per hour
*/
+#define MIN_SECS 60 /* seconds per minute
*/
+
+
+#define FMT_DATE_ISO "%Y-%m-%d" /* ISO date format
*/
+
+
+/* convert tm year to Gregorian year */
+#define YEAR(tm_y) ((tm_y) + TM_YEAR_BASE)
+/* test if Gregorian year is a leap year */
+#define IS_LEAP_YEAR(y) (!((y) % LEAP_YEARS) && (((y) %
CENTURY_YEARS) \
+ || !((y) %
LEAP_CENTURY_YEARS)))
+
-#define TM_YEAR_BASE 1900
+
+/* tm wday values */
+typedef enum weekday
+{
+ SUNDAY,
+ MONDAY,
+ TUESDAY,
+ WEDNESDAY,
+ THURSDAY,
+ FRIDAY,
+ SATURDAY,
+ WEEK_DAYS
+
+} weekday; /* enum */
+
+
+
+
+/* locale dependent strings */
static const char *afmt[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
@@ -24,11 +68,92 @@ static const char *Bfmt[] = {
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December",
};
+
+
+/* locale dependent formats */
+
char __dj_date_format[10] = "%m/%d/%y";
char __dj_time_format[16] = "%H:%M:%S";
-static size_t gsize;
-static char *pt;
+
+/* internal global variables */
+
+static size_t gsize; /* user buffer space left */
+static char *pt; /* next char to use in buffer */
+
+
+
+/* calculate ISO year from Gregorian year and days of year and week
*/
+static int
+iso_year( int year, int doy, int dow)
+{
+ int ISOyear = year; /* ISO year may not be same as
Gregorian */
+ int near_thu = doy + THURSDAY - (dow ? dow : WEEK_DAYS);
+ /* day in year of closest Thu to date
*/
+
+
+#if 0 /* DEBUG */
+ printf( "year %d doy %d dow %d thu %d near thu %d max %d
\n",
+ year, doy, dow, THURSDAY, near_thu, YEAR_DAYS + IS_LEAP_YEAR(
year ));
+#endif /* 0 */
+
+/* if nearest Thu before start of year, then it's in last year */
+ if (near_thu < 0)
+ {
+ --ISOyear;
+ }
+ else
+/* if nearest Thu after end of year, then it's in next year */
+ if (near_thu >= YEAR_DAYS + IS_LEAP_YEAR( year ))
+ {
+ ++ISOyear;
+ }
+
+ return ISOyear;
+
+} /* iso_year() */
+
+
+
+/* calculate ISO week from Gregorian year and days of year and week
*/
+static int
+iso_week( int year, int doy, int dow)
+{
+ int near_thu = doy + THURSDAY - (dow ? dow : WEEK_DAYS);
+ /* day in year of closest Thu to date
*/
+
+
+#if 0 /* DEBUG */
+ printf( "year %d doy %d dow %d thu %d near thu %d"
+ " max prev %d this
%d \n",
+ year, doy, dow, THURSDAY, near_thu,
+ YEAR_DAYS + IS_LEAP_YEAR( year - 1 ),
+ YEAR_DAYS + IS_LEAP_YEAR(
year ));
+#endif /* 0 */
+
+/* if nearest Thu before start of year, then it's in last year */
+ if (near_thu < 0)
+ {
+/* adjust day to make it part of last year */
+ near_thu += YEAR_DAYS + IS_LEAP_YEAR( year - 1 );
+ }
+ else
+/* if nearest Thu after end of year, then it's in next year */
+ if (near_thu >= YEAR_DAYS + IS_LEAP_YEAR( year ))
+ {
+/* adjust day to make it part of next year */
+ near_thu -= YEAR_DAYS + IS_LEAP_YEAR( year );
+ }
+
+#if 0 /* DEBUG */
+ printf( "near thu %d week %d \n", near_thu, near_thu / WEEK_DAYS
+ 1);
+#endif /* 0 */
+
+ return near_thu / WEEK_DAYS + 1; /* 0-365 -> 0-52 -> 1-53
*/
+
+} /* iso_week() */
+
+
static int
_add(const char *str, int upcase)
@@ -47,7 +172,7 @@ _add(const char *str, int upcase)
static int
_conv(int n, int digits, char pad)
{
- static char buf[10];
+ static char buf[12];
char *p = buf + sizeof(buf) - 2;
do {
@@ -70,6 +195,10 @@ _fmt(const char *format, const struct tm
if (*format == '%')
{
int pad = '0', space=' ';
+ int era = 0; /* locale era modifier
*/
+ int ordinal = 0; /* locale ordinal modifier
*/
+
+
if (format[1] == '_')
pad = space = ' ', format++;
if (format[1] == '-')
@@ -78,6 +207,10 @@ _fmt(const char *format, const struct tm
pad = space = '0', format++;
if (format[1] == '^')
upcase = 1, format++;
+ if (format[1] == 'E') /* if locale era modifier
*/
+ era = 1, format++;
+ if (format[1] == 'O') /* if locale ordinal modifier
*/
+ ordinal = 1, format++;
switch(*++format)
{
@@ -129,6 +262,16 @@ _fmt(const char *format, const struct tm
if (!_conv(t->tm_mday, 2, pad))
return 0;
continue;
+
+/*
+ * %F is equivalent to ``%Y-%m-%d'' (the ISO 8601 date format).
+ * [tm_year, tm_mon, tm_mday]
+ */
+ case 'F':
+ if (!_fmt( FMT_DATE_ISO, t, upcase))
+ return 0;
+ continue;
+
case 'H':
if (!_conv(t->tm_hour, 2, pad))
return 0;
@@ -179,6 +322,29 @@ _fmt(const char *format, const struct tm
if (!_conv(t->tm_sec, 2, pad))
return 0;
continue;
+
+/*
+ * + %s is replaced by the number of seconds since the epoch
+ * 1970-01-01 00:00:00 as a decimal number. [all]
+ */
+ case 's':
+ {
+/* copy user tm in case modified */
+ struct tm tm = *t;
+/* convert to seconds since epoch */
+ time_t secs = mktime( &tm );
+
+#if 0 /* DEBUG */
+ printf( "\n %u s \n", secs);
+#endif /* 0 */
+
+ if (secs == (time_t)-1) /* if invalid time, quit
*/
+ return 0;
+ if (!_conv( secs, 10, '\0')) /* if conversion failed, quit
*/
+ return 0;
+ continue;
+ }
+
case 'T':
if (!_fmt("%H:%M:%S", t, upcase))
return 0;
@@ -196,6 +362,37 @@ _fmt(const char *format, const struct tm
2, pad))
return 0;
continue;
+
+/*
+ * %V is replaced by the ISO 8601 week number (see above)
+ * as a decimal number (01-53). [tm_year, tm_wday, tm_yday]
+ */
+ case 'V':
+ if (!_conv( iso_week( YEAR( t->tm_year ), t->tm_yday,
t->tm_wday),
+ 2, pad))
+ return 0;
+ continue;
+
+/*
+ * %g is replaced by the last 2 digits of the week-based year (see
above)
+ * as a decimal number (00-99). [tm_year, tm_wday, tm_yday]
+ */
+ case 'g':
+ if (!_conv( iso_year( YEAR( t->tm_year ), t->tm_yday,
t->tm_wday)
+ % CENTURY_YEARS, 2, pad))
+ return 0;
+ continue;
+
+/*
+ * %G is replaced by the week-based year (see above) as a
+ * decimal number (e.g., 1997). [tm_year, tm_wday, tm_yday]
+ */
+ case 'G':
+ if (!_conv( iso_year( YEAR( t->tm_year ), t->tm_yday,
t->tm_wday),
+ 4, pad))
+ return 0;
+ continue;
+
case 'W':
if (!_conv((t->tm_yday + 7 -
(t->tm_wday ? (t->tm_wday - 1) : 6))
@@ -215,24 +412,31 @@ _fmt(const char *format, const struct tm
return 0;
continue;
case 'y':
- case 'g':
if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, 2, pad))
return 0;
continue;
case 'Y':
- case 'G':
if (!_conv(t->tm_year + TM_YEAR_BASE, 4, pad))
return 0;
continue;
case 'z':
- if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
- return 0;
- if (!_conv(t->__tm_gmtoff<0 ? -t->__tm_gmtoff :
t->__tm_gmtoff, 4, pad))
- return 0;
+/* if time zone available, do conversion */
+ if (t->tm_isdst >= 0 && t->__tm_zone && *t->__tm_zone)
+ {
+ int offset = abs( t->__tm_gmtoff ) / MIN_SECS;
+
+ if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
+ return 0;
+ if (!_conv( offset / HOUR_MINS * 100 + offset % HOUR_MINS,
+ 4, pad))
+ return 0;
+ }
continue;
case 'Z':
- if (!t->tm_zone || !_add(t->tm_zone, upcase))
- return 0;
+/* if time zone available, do conversion */
+ if (t->tm_isdst >= 0 && t->__tm_zone && *t->__tm_zone)
+ if (!_add(t->__tm_zone, upcase))
+ return 0;
continue;
case '%':
/*
Index: strftime.c
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/time/strftime.c,v
retrieving revision 1.6
diff -p -u -t -r1.6 strftime.c
--- strftime.c 8 Nov 2003 12:19:40 -0000 1.6
+++ strftime.c 17 Mar 2004 06:36:05 -0000
@@ -6,8 +6,52 @@
#include <string.h>
#include <time.h>
#include <ctype.h>
+#include <stdlib.h>
+#if 0 /* DEBUG */
+#include <stdio.h>
+#endif /* 0 */
-#define TM_YEAR_BASE 1900
+
+
+#define TM_YEAR_BASE 1900 /* tm year epoch base
*/
+#define LEAP_CENTURIES 4 /* centuries between leap
centuries */
+#define CENTURY_YEARS 100 /* years per century
*/
+#define LEAP_CENTURY_YEARS (LEAP_CENTURIES * CENTURY_YEARS) /*
years */
+#define LEAP_YEARS 4 /* years between leap years
*/
+#define YEAR_DAYS 365 /* days in common year
*/
+#define HOUR_MINS 60 /* minutes per hour
*/
+#define MIN_SECS 60 /* seconds per minute
*/
+
+
+#define FMT_DATE_ISO "%Y-%m-%d" /* ISO date format
*/
+
+
+/* convert tm year to Gregorian year */
+#define YEAR(tm_y) ((tm_y) + TM_YEAR_BASE)
+/* test if Gregorian year is a leap year */
+#define IS_LEAP_YEAR(y) (!((y) % LEAP_YEARS) && (((y) %
CENTURY_YEARS) \
+ || !((y) %
LEAP_CENTURY_YEARS)))
+
+
+
+/* tm wday values */
+typedef enum weekday
+{
+ SUNDAY,
+ MONDAY,
+ TUESDAY,
+ WEDNESDAY,
+ THURSDAY,
+ FRIDAY,
+ SATURDAY,
+ WEEK_DAYS
+
+} weekday; /* enum */
+
+
+
+
+/* locale dependent strings */
static const char *afmt[] = {
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
@@ -24,11 +68,92 @@ static const char *Bfmt[] = {
"January", "February", "March", "April", "May", "June", "July",
"August", "September", "October", "November", "December",
};
+
+
+/* locale dependent formats */
+
char __dj_date_format[10] = "%m/%d/%y";
char __dj_time_format[16] = "%H:%M:%S";
-static size_t gsize;
-static char *pt;
+
+/* internal global variables */
+
+static size_t gsize; /* user buffer space left */
+static char *pt; /* next char to use in buffer */
+
+
+
+/* calculate ISO year from Gregorian year and days of year and week
*/
+static int
+iso_year( int year, int doy, int dow)
+{
+ int ISOyear = year; /* ISO year may not be same as
Gregorian */
+ int near_thu = doy + THURSDAY - (dow ? dow : WEEK_DAYS);
+ /* day in year of closest Thu to date
*/
+
+
+#if 0 /* DEBUG */
+ printf( "year %d doy %d dow %d thu %d near thu %d max %d
\n",
+ year, doy, dow, THURSDAY, near_thu, YEAR_DAYS + IS_LEAP_YEAR(
year ));
+#endif /* 0 */
+
+/* if nearest Thu before start of year, then it's in last year */
+ if (near_thu < 0)
+ {
+ --ISOyear;
+ }
+ else
+/* if nearest Thu after end of year, then it's in next year */
+ if (near_thu >= YEAR_DAYS + IS_LEAP_YEAR( year ))
+ {
+ ++ISOyear;
+ }
+
+ return ISOyear;
+
+} /* iso_year() */
+
+
+
+/* calculate ISO week from Gregorian year and days of year and week
*/
+static int
+iso_week( int year, int doy, int dow)
+{
+ int near_thu = doy + THURSDAY - (dow ? dow : WEEK_DAYS);
+ /* day in year of closest Thu to date
*/
+
+
+#if 0 /* DEBUG */
+ printf( "year %d doy %d dow %d thu %d near thu %d"
+ " max prev %d this
%d \n",
+ year, doy, dow, THURSDAY, near_thu,
+ YEAR_DAYS + IS_LEAP_YEAR( year - 1 ),
+ YEAR_DAYS + IS_LEAP_YEAR(
year ));
+#endif /* 0 */
+
+/* if nearest Thu before start of year, then it's in last year */
+ if (near_thu < 0)
+ {
+/* adjust day to make it part of last year */
+ near_thu += YEAR_DAYS + IS_LEAP_YEAR( year - 1 );
+ }
+ else
+/* if nearest Thu after end of year, then it's in next year */
+ if (near_thu >= YEAR_DAYS + IS_LEAP_YEAR( year ))
+ {
+/* adjust day to make it part of next year */
+ near_thu -= YEAR_DAYS + IS_LEAP_YEAR( year );
+ }
+
+#if 0 /* DEBUG */
+ printf( "near thu %d week %d \n", near_thu, near_thu / WEEK_DAYS
+ 1);
+#endif /* 0 */
+
+ return near_thu / WEEK_DAYS + 1; /* 0-365 -> 0-52 -> 1-53
*/
+
+} /* iso_week() */
+
+
static int
_add(const char *str, int upcase)
@@ -47,7 +172,7 @@ _add(const char *str, int upcase)
static int
_conv(int n, int digits, char pad)
{
- static char buf[10];
+ static char buf[12];
char *p = buf + sizeof(buf) - 2;
do {
@@ -70,6 +195,10 @@ _fmt(const char *format, const struct tm
if (*format == '%')
{
int pad = '0', space=' ';
+ int era = 0; /* locale era modifier
*/
+ int ordinal = 0; /* locale ordinal modifier
*/
+
+
if (format[1] == '_')
pad = space = ' ', format++;
if (format[1] == '-')
@@ -78,6 +207,10 @@ _fmt(const char *format, const struct tm
pad = space = '0', format++;
if (format[1] == '^')
upcase = 1, format++;
+ if (format[1] == 'E') /* if locale era modifier
*/
+ era = 1, format++;
+ if (format[1] == 'O') /* if locale ordinal modifier
*/
+ ordinal = 1, format++;
switch(*++format)
{
@@ -129,6 +262,16 @@ _fmt(const char *format, const struct tm
if (!_conv(t->tm_mday, 2, pad))
return 0;
continue;
+
+/*
+ * %F is equivalent to ``%Y-%m-%d'' (the ISO 8601 date format).
+ * [tm_year, tm_mon, tm_mday]
+ */
+ case 'F':
+ if (!_fmt( FMT_DATE_ISO, t, upcase))
+ return 0;
+ continue;
+
case 'H':
if (!_conv(t->tm_hour, 2, pad))
return 0;
@@ -179,6 +322,29 @@ _fmt(const char *format, const struct tm
if (!_conv(t->tm_sec, 2, pad))
return 0;
continue;
+
+/*
+ * + %s is replaced by the number of seconds since the epoch
+ * 1970-01-01 00:00:00 as a decimal number. [all]
+ */
+ case 's':
+ {
+/* copy user tm in case modified */
+ struct tm tm = *t;
+/* convert to seconds since epoch */
+ time_t secs = mktime( &tm );
+
+#if 0 /* DEBUG */
+ printf( "\n %u s \n", secs);
+#endif /* 0 */
+
+ if (secs == (time_t)-1) /* if invalid time, quit
*/
+ return 0;
+ if (!_conv( secs, 10, '\0')) /* if conversion failed, quit
*/
+ return 0;
+ continue;
+ }
+
case 'T':
if (!_fmt("%H:%M:%S", t, upcase))
return 0;
@@ -196,6 +362,37 @@ _fmt(const char *format, const struct tm
2, pad))
return 0;
continue;
+
+/*
+ * %V is replaced by the ISO 8601 week number (see above)
+ * as a decimal number (01-53). [tm_year, tm_wday, tm_yday]
+ */
+ case 'V':
+ if (!_conv( iso_week( YEAR( t->tm_year ), t->tm_yday,
t->tm_wday),
+ 2, pad))
+ return 0;
+ continue;
+
+/*
+ * %g is replaced by the last 2 digits of the week-based year (see
above)
+ * as a decimal number (00-99). [tm_year, tm_wday, tm_yday]
+ */
+ case 'g':
+ if (!_conv( iso_year( YEAR( t->tm_year ), t->tm_yday,
t->tm_wday)
+ % CENTURY_YEARS, 2, pad))
+ return 0;
+ continue;
+
+/*
+ * %G is replaced by the week-based year (see above) as a
+ * decimal number (e.g., 1997). [tm_year, tm_wday, tm_yday]
+ */
+ case 'G':
+ if (!_conv( iso_year( YEAR( t->tm_year ), t->tm_yday,
t->tm_wday),
+ 4, pad))
+ return 0;
+ continue;
+
case 'W':
if (!_conv((t->tm_yday + 7 -
(t->tm_wday ? (t->tm_wday - 1) : 6))
@@ -215,24 +412,31 @@ _fmt(const char *format, const struct tm
return 0;
continue;
case 'y':
- case 'g':
if (!_conv((t->tm_year + TM_YEAR_BASE) % 100, 2, pad))
return 0;
continue;
case 'Y':
- case 'G':
if (!_conv(t->tm_year + TM_YEAR_BASE, 4, pad))
return 0;
continue;
case 'z':
- if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
- return 0;
- if (!_conv(t->__tm_gmtoff<0 ? -t->__tm_gmtoff :
t->__tm_gmtoff, 4, pad))
- return 0;
+/* if time zone available, do conversion */
+ if (t->tm_isdst >= 0 && t->__tm_zone && *t->__tm_zone)
+ {
+ int offset = abs( t->__tm_gmtoff ) / MIN_SECS;
+
+ if (!_add(t->__tm_gmtoff<0 ? "-" : "+", 0))
+ return 0;
+ if (!_conv( offset / HOUR_MINS * 100 + offset % HOUR_MINS,
+ 4, pad))
+ return 0;
+ }
continue;
case 'Z':
- if (!t->tm_zone || !_add(t->tm_zone, upcase))
- return 0;
+/* if time zone available, do conversion */
+ if (t->tm_isdst >= 0 && t->__tm_zone && *t->__tm_zone)
+ if (!_add(t->__tm_zone, upcase))
+ return 0;
continue;
case '%':
/*
Index: strftime.txh
===================================================================
RCS file: /cvs/djgpp/djgpp/src/libc/ansi/time/strftime.txh,v
retrieving revision 1.6
diff -u -t -F^@[[:alpha:]] -r1.6 strftime.txh
--- strftime.txh 8 Nov 2003 12:19:40 -0000 1.6
+++ strftime.txh 17 Mar 2004 06:39:48 -0000
@@ -5,145 +5,187 @@
@example
#include <time.h>
-size_t strftime(char *buf, size_t n, const char *format,
- const struct tm *time_info);
+size_t strftime(char * restrict string,
+ size_t maxsize,
+ const char * restrict format,
+ const struct tm * restrict time_info);
+
@end example
@subheading Description
-This function formats the time data in @var{time_info} according to
the
-given @var{format} and stores it in @var{buf}, not exceeding @var{n}
-bytes.
-
-The format string is like @code{printf} in that any character other
than
-@code{%} is added to the output string, and for each character
following
-a @code{%} a pattern is added to the string as follows, with the
-examples as if the time was Friday, October 1, 1993, at 03:30:34 PM
EDT:
+This function formats the calendar time data in @var{time_info}
+according to the given format string @var{format}
+and stores it in the output string @var{string},
+not exceeding @var{maxsize} bytes.
+
+The format string is like @code{sprintf} in that any character other
+than the flag character @code{%} is added to the output string, and
+depending on the conversion specifier character after the @code{%},
+characters are added to the output string, with the following
examples
+shown as if the time was Friday, October 1, 1993, at 03:30:34 PM EDT:
@table @code
@item %A
-The full weekday name (@code{Friday})
+The full weekday name represented according to the
+current locale: (@code{Friday}) in the C locale
@item %a
-The abbreviated weekday name (@code{Fri})
+The abbreviated weekday name represented according to
+the current locale: (@code{Fri}) in the C locale
@item %B
-The full month name (@code{October})
+The full month name represented according to the
+current locale: (@code{October}) in the C locale
@item %b
@itemx %h
-The abbreviated month name (@code{Oct})
+The abbreviated month name represented according to
+the current locale: (@code{Oct}) in the C locale
@item %C
-Short for @code{%a %b %e %H:%M:%S %Y} (@code{Fri Oct 1 15:30:34
1993})
+The century of the year, zero padded to two digits (@code{19})
@item %c
-Short for @code{%m/%d/%y %H:%M:%S} (@code{10/01/93 15:30:34})
+The date and time represented according to the current locale: short
for
+@code{%a %b %e %T %Y} (@code{Fri Oct 1 15:30:34 1993}) in the C
locale
+
+@item %D
+
+The date in POSIX format; short for @code{%m/%d/%y} (@code{10/01/93})
+
+@item %d
+
+The day of the month (01-31), zero padded to two digits (@code{01})
@item %e
-The day of the month, blank padded to two characters (@code{ 2})
+The day of the month (1-31), blank padded to two characters (@code{
1})
-@item %D
+@item %F
-Short for @code{%m/%d/%y} (@code{10/01/93})
+The date in ISO format; short for @code{%Y-%m-%d} (@code{1993-10-01})
-@item %d
+@item %G
-The day of the month, zero padded to two characters (@code{02})
+The ISO week based year, zero padded to four digits (@code{1993})
+
+@item %g
+
+The ISO week based year of the century (00-99),
+zero padded to two digits (@code{93})
@item %H
-The hour (0-24), zero padded to two characters (@code{15})
+The hour in the 24 hour clock (00-24), zero padded to two digits
(@code{15})
@item %I
-The hour (1-12), zero padded to two characters (@code{03})
+The hour in the 12 hour clock (01-12), zero padded to two digits
(@code{03})
@item %j
-The Julian day, zero padded to three characters (@code{275})
+The Julian day of the year (001-366), zero padded to three digits
(@code{274})
@item %k
-The hour (0-24), space padded to two characters (@code{15})
+The hour in the 24 hour clock (0-24),
+space padded to two characters (@code{15})
@item %l
-The hour (1-12), space padded to two characters(@code{ 3})
+The hour in the 12 hour clock (1-12),
+space padded to two characters (@code{ 3})
@item %M
-The minutes, zero padded to two characters (@code{30})
+The minutes in the hour (00-59), zero padded to two digits
(@code{30})
@item %m
-The month (1-12), zero padded to two characters (@code{10})
+The month in the year (01-12), zero padded to two digits (@code{10})
@item %n
-A newline (@code{\n})
+The newline control character (@code{\n})
@item %p
-AM or PM (@code{PM})
+The AM/PM indicator in the 12 hour clock represented according
+to the current locale: (@code{PM}) in the C locale
@item %R
-Short for @code{%H:%M} (@code{15:30})
+The time in the 24 hour clock, excluding seconds;
+short for @code{%H:%M} (@code{15:30})
@item %r
-Short for @code{%I:%M:%S %p} (@code{03:30:35 PM})
+The time in the 12 hour clock represented according to the current
locale:
+short for @code{%I:%M:%S %p} (@code{03:30:35 PM}) in the C locale
@item %S
-The seconds, zero padded to two characters (@code{35})
+The seconds in the minute (00-60), zero padded to two digits
(@code{35});
+the maximum value is 60 to allow leap seconds to be represented
+
+@item %s
+
+The number of seconds since 1970-01-01 00:00:00 UTC
(@code{749503834})
@item %T
-Short for @code{%H:%M:%S} (@code{15:30:35})
+The time in the 24 hour clock, including seconds;
+short for @code{%H:%M:%S} (@code{15:30:35})
@item %t
-A tab (@code{\t})
+The horizontal tab control character (@code{\t})
@item %U
-The week of the year, with the first week defined by the first Sunday
of
-the year, zero padded to two characters (@code{39})
+The Sunday based week of the year (00-53), with the first week
defined
+by the first Sunday of the year, zero padded to two digits
(@code{39})
@item %u
-The day of the week (1-7) (@code{6})
+The ISO Monday based day of the week (Mon 1-Sun 7) (@code{5})
+
+@item %V
+
+The ISO Monday based week of the year (01-53), with the first and
last
+weeks defined by the first and last Thursdays of the year, zero
padded
+to two digits (@code{39})
@item %W
-The week of the year, with the first week defined by the first Monday
of
-the year, zero padded to two characters (@code{39})
+The Monday based week of the year (00-53), with the first week
defined
+by the first Monday of the year, zero padded to two digits
(@code{39})
@item %w
-The day of the week (0-6) (@code{5})
+The Sunday based day of the week (Sun 0-Sat 6) (@code{5})
@item %x
-Date represented according to the current locale.
+The date represented according to the current locale:
+short for @code{%D} (@code{10/01/93}) in the C locale
@item %X
-Time represented according to the current locale.
+The time in the 24 hour clock represented according to the current
+locale: short for @code{%T} (@code{15:30:34}) in the C locale
@item %y
-The year (00-99) of the century (@code{93})
+The year of the century (00-99), zero padded to two digits
(@code{93})
@item %Y
@@ -151,11 +193,54 @@
@item %Z
-The timezone abbreviation (@code{EDT})
+The timezone abbreviation represented according
+to the current locale (@code{EDT})
+
+@item %z
+
+The ISO timezone offset in [+-]HHMM format (@code{-0400})
@item %%
-A percent symbol (@code{%})
+The percent symbol character (@code{%})
+
+@end table
+
+@subheading Conversion Modifiers
+
+The following conversion modifier characters affect the conversion
into
+the output string and must appear after the flag character (@code{%})
+and before the conversion specifier character.
+
+@table @code
+
+@item -
+
+Left justify the output with no padding characters,
+for example @code{%-d} gives @code{1}
+
+@item 0
+
+Right justify the output with zero digit padding,
+for example @code{%0d} gives @code{01}
+
+@item _
+
+Right justify the output with space character padding,
+for example @code{%_d} gives @code{ 1}
+
+@item ^
+
+Convert lowercase letters in the output to uppercase,
+for example @code{%^a} gives @code{FRI}
+
+@item E
+
+Locale alternate era output format; ignored in the C locale
+
+@item O
+
+Locale alternate digits output format; ignored in the C locale
@end table
@@ -165,7 +250,7 @@
@subheading Portability
-@portability ansi, posix
+@portability ANSI, POSIX
@subheading Example
Index: strftime.c
===================================================================
RCS file: /cvs/djgpp/djgpp/zoneinfo/src/strftime.c,v
retrieving revision 1.2
diff -p -u -t -r1.2 strftime.c
--- strftime.c 28 May 1998 16:56:10 -0000 1.2
+++ strftime.c 17 Mar 2004 06:43:26 -0000
@@ -1,6 +1,6 @@
#ifndef lint
#ifndef NOID
-static char elsieid[] = "@(#)strftime.c 7.57";
+static char elsieid[] = "@(#)strftime.c 7.62";
/*
** Based on the UCB version with the ID appearing below.
** This is ANSIish only when "multibyte character == plain
character".
@@ -80,24 +80,21 @@ static const struct lc_time_T C_time_loc
/*
** x_fmt
- ** Since the C language standard calls for
- ** "date, using locale's date format," anything goes.
+ ** C99 requires this format.
** Using just numbers (as here) makes Quakers happier;
** it's also compatible with SVR4.
- **
- ** XXX--might it be better to use the year-2000 friendly
- ** %Y-%m-%d
- ** here?
*/
"%m/%d/%y",
/*
** c_fmt
+ ** C99 requires this format.
+ ** Previously this code used "%D %X", but we now conform to
C99.
** Note that
- ** "%a %b %d %H:%M:%S %Y"
+ ** "%a %b %d %H:%M:%S %Y"
** is used by Solaris 2.3.
*/
- "%D %X", /* %m/%d/%y %H:%M:%S */
+ "%a %b %e %T %Y",
/* am */
"AM",
@@ -236,20 +233,21 @@ label:
case 'E':
case 'O':
/*
- ** POSIX locale extensions, a la
- ** Arnold Robbins' strftime version
3.0.
+ ** C99 locale modifiers.
** The sequences
- ** %Ec %EC %Ex %Ey %EY
+ ** %Ec %EC %Ex %EX %Ey %EY
** %Od %oe %OH %OI %Om %OM
** %OS %Ou %OU %OV %Ow %OW %Oy
** are supposed to provide alternate
** representations.
- ** (ado, 1993-05-24)
*/
goto label;
case 'e':
pt = _conv(t->tm_mday, "%2d", pt,
ptlim);
continue;
+ case 'F':
+ pt = _fmt("%Y-%m-%d", t, pt, ptlim,
warnp);
+ continue;
case 'H':
pt = _conv(t->tm_hour, "%02d", pt,
ptlim);
continue;
@@ -492,10 +490,66 @@ label:
pt = _add(t->TM_ZONE, pt,
ptlim);
else
#endif /* defined TM_ZONE */
- if (t->tm_isdst == 0 || t->tm_isdst
== 1) {
- pt =
_add(tzname[t->tm_isdst],
+ if (t->tm_isdst >= 0)
+ pt = _add(tzname[t->tm_isdst
!= 0],
pt, ptlim);
- } else pt = _add("?", pt, ptlim);
+ /*
+ ** C99 says that %Z must be replaced
by the
+ ** empty string if the time zone is
not
+ ** determinable.
+ */
+ continue;
+ case 'z':
+ {
+ int diff;
+ char const * sign;
+
+ if (t->tm_isdst < 0)
+ continue;
+#ifdef TM_GMTOFF
+ diff = t->TM_GMTOFF;
+#else /* !defined TM_GMTOFF */
+ /*
+ ** C99 says that the UTC offset must
+ ** be computed by looking only at
+ ** tm_isdst. This requirement is
+ ** incorrect, since it means the code
+ ** must rely on magic (in this case
+ ** altzone and timezone), and the
+ ** magic might not have the correct
+ ** offset. Doing things correctly is
+ ** tricky and requires disobeying
C99;
+ ** see GNU C strftime for details.
+ ** For now, punt and conform to the
+ ** standard, even though it's
incorrect.
+ **
+ ** C99 says that %z must be replaced
by the
+ ** empty string if the time zone is
not
+ ** determinable, so output nothing if
the
+ ** appropriate variables are not
available.
+ */
+ if (t->tm_isdst == 0)
+#ifdef USG_COMPAT
+ diff = -timezone;
+#else /* defined USG_COMPAT */
+ continue;
+#endif /* !defined USG_COMPAT */
+ else
+#ifdef ALTZONE
+ diff = -altzone;
+#else /* !defined ALTZONE */
+ continue;
+#endif /* !defined ALTZONE */
+#endif /* !defined TM_GMTOFF */
+ if (diff < 0) {
+ sign = "-";
+ diff = -diff;
+ } else sign = "+";
+ pt = _add(sign, pt, ptlim);
+ diff /= 60;
+ pt = _conv((diff/60)*100 + diff%60,
+ "%04d", pt, ptlim);
+ }
continue;
case '+':
pt = _fmt(Locale->date_fmt, t, pt,
ptlim,
@@ -503,10 +557,10 @@ label:
continue;
case '%':
/*
- * X311J/88-090 (4.12.3.5): if conversion
char is
- * undefined, behavior is undefined. Print
out the
- * character itself as printf(3) also does.
- */
+ ** X311J/88-090 (4.12.3.5): if conversion
char is
+ ** undefined, behavior is undefined. Print
out the
+ ** character itself as printf(3) also does.
+ */
default:
break;
}
Index: makefile
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/ansi/time/makefile,v
retrieving revision 1.3
diff -u -t -r1.3 makefile
--- makefile 8 Nov 2003 12:19:41 -0000 1.3
+++ makefile 17 Mar 2004 06:57:18 -0000
@@ -4,6 +4,8 @@
SRC += strftime.c
SRC += tzinfo.c
SRC += xstrftm.c
+SRC += strftimt.c
+SRC += strftiml.c
include $(TOP)/../makefile.inc
Index: strftime.c
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/ansi/time/strftime.c,v
retrieving revision 1.3
diff -p -u -t -r1.3 strftime.c
--- strftime.c 26 May 2002 16:12:46 -0000 1.3
+++ strftime.c 17 Mar 2004 06:48:41 -0000
@@ -11,6 +11,86 @@
#include <time.h>
#include <libc/unconst.h>
+
+#undef CMP
+#define CMP(Fmt, Expected) n_fail += compare ((Fmt), tm, (Expected))
+
+
+typedef struct cmp
+{
+ char *fmt;
+ char *expected;
+
+} cmp;
+
+
+struct cmp comparisons[] =
+{
+ { "%-m", "1" }, /* GNU */
+ { "%A", "Friday" },
+ { "%^A", "FRIDAY" }, /* GNU */
+ { "%B", "January" },
+ { "%^B", "JANUARY" },
+ { "%C", "19" }, /* POSIX.2 */
+ { "%D", "01/09/70" }, /* POSIX.2 */
+ { "%E", "E" }, /* C99 */
+ { "%F", "1970-01-09"}, /* C99 */
+ { "%G", "1970" }, /* GNU */
+ { "%H", "13" },
+ { "%I", "01" },
+ { "%J", "J" },
+ { "%K", "K" },
+ { "%L", "L" },
+ { "%M", "06" },
+ { "%N", "N" },
+ { "%O", "O" }, /* C99 */
+ { "%P", "P" },
+ { "%Q", "Q" },
+ { "%R", "13:06" }, /* POSIX.2 */
+ { "%S", "07" },
+ { "%T", "13:06:07" }, /* POSIX.2 */
+ { "%U", "01" },
+ { "%V", "02" },
+ { "%W", "01" },
+ { "%X", "13:06:07" },
+ { "%Y", "1970" },
+ { "%Z", "GMT" },
+ { "%_m", " 1" }, /* GNU */
+ { "%a", "Fri" },
+ { "%^a", "FRI" },
+ { "%b", "Jan" },
+ { "%^b", "JAN" },
+ { "%c", "Fri Jan 9 13:06:07 1970" },
+ { "%^c", "FRI JAN 9 13:06:07 1970" },
+ { "%d", "09" },
+ { "%e", " 9" }, /* POSIX.2 */
+ { "%f", "f" }, /* ISO */
+ { "%g", "70" }, /* GNU */
+ { "%h", "Jan" }, /* POSIX.2 */
+ { "%^h", "JAN" },
+ { "%i", "i" },
+ { "%j", "009" },
+ { "%k", "13" }, /* GNU */
+ { "%l", " 1" }, /* GNU */
+ { "%m", "01" },
+ { "%n", "\n" }, /* POSIX.2 */
+ { "%o", "o" },
+ { "%p", "PM" },
+ { "%q", "q" },
+ { "%r", "01:06:07 PM"}, /* POSIX.2 */
+ { "%s", "738367" }, /* GNU */
+ { "%t", "\t" }, /* POSIX.2 */
+ { "%u", "5" }, /* POSIX.2 */
+ { "%v", "v" },
+ { "%w", "5" },
+ { "%x", "01/09/70" },
+ { "%y", "70" },
+ { "%z", "+0000" }, /* GNU */
+ { "%%", "%" },
+
+}; /* comparisons[] */
+
+
static int
compare (const char *fmt, const struct tm *tm, const char *expected)
{
@@ -19,7 +99,8 @@ compare (const char *fmt, const struct t
if (strcmp (buf, expected))
{
#if 1
- printf ("fmt: \"%s\", expected \"%s\", got \"%s\"\n",
+ printf ("\n fmt: \"%-3s\" expected: \"%s\" \n"
+ " got: \"%s\" \n",
fmt, expected, buf);
#endif
return 1;
@@ -27,68 +108,24 @@ compare (const char *fmt, const struct t
return 0;
}
+
int
main (void)
{
- int n_fail = 0;
- struct tm *tm;
- time_t t = 738367; /* Fri Jan 9 13:06:07 1970 */
- tm = gmtime (&t);
+ struct cmp * c;
+ int n_fail = 0;
+ time_t t = 738367; /* Fri Jan 9 13:06:07 1970 */
+ struct tm * tm = gmtime (&t);
+
/* This is necessary to make strftime give consistent zone strings
and
e.g., seconds since the epoch (%s). */
putenv (unconst("TZ=GMT0", char *));
-#undef CMP
-#define CMP(Fmt, Expected) n_fail += compare ((Fmt), tm, (Expected))
-
- CMP ("%-m", "1"); /* GNU */
- CMP ("%A", "Friday");
- CMP ("%^A", "FRIDAY"); /* The ^ is a GNU extension. */
- CMP ("%B", "January");
- CMP ("%^B", "JANUARY");
- CMP ("%C", "19"); /* POSIX.2 */
- CMP ("%D", "01/09/70"); /* POSIX.2 */
- CMP ("%G", "1970"); /* GNU */
- CMP ("%H", "13");
- CMP ("%I", "01");
- CMP ("%M", "06");
- CMP ("%M", "06");
- CMP ("%R", "13:06"); /* POSIX.2 */
- CMP ("%S", "07");
- CMP ("%T", "13:06:07"); /* POSIX.2 */
- CMP ("%U", "01");
- CMP ("%V", "02");
- CMP ("%W", "01");
- CMP ("%X", "13:06:07");
- CMP ("%Y", "1970");
- CMP ("%Z", "GMT");
- CMP ("%_m", " 1"); /* GNU */
- CMP ("%a", "Fri");
- CMP ("%^a", "FRI");
- CMP ("%b", "Jan");
- CMP ("%^b", "JAN");
- CMP ("%c", "Fri Jan 9 13:06:07 1970");
- CMP ("%^c", "FRI JAN 9 13:06:07 1970");
- CMP ("%d", "09");
- CMP ("%e", " 9"); /* POSIX.2 */
- CMP ("%g", "70"); /* GNU */
- CMP ("%h", "Jan"); /* POSIX.2 */
- CMP ("%^h", "JAN");
- CMP ("%j", "009");
- CMP ("%k", "13"); /* GNU */
- CMP ("%l", " 1"); /* GNU */
- CMP ("%m", "01");
- CMP ("%n", "\n"); /* POSIX.2 */
- CMP ("%p", "PM");
- CMP ("%r", "01:06:07 PM"); /* POSIX.2 */
- CMP ("%s", "738367"); /* GNU */
- CMP ("%t", "\t"); /* POSIX.2 */
- CMP ("%u", "5"); /* POSIX.2 */
- CMP ("%w", "5");
- CMP ("%x", "01/09/70");
- CMP ("%y", "70");
- CMP ("%z", "+0000"); /* GNU */
+ for (c = comparisons; c < comparisons + sizeof comparisons / sizeof
*comparisons; ++ c)
+ {
+ CMP( c->fmt, c->expected);
+ }
exit (n_fail ? 1 : 0);
}
Index: xstrftm.c
===================================================================
RCS file: /cvs/djgpp/djgpp/tests/libc/ansi/time/xstrftm.c,v
retrieving revision 1.1
diff -p -u -t -r1.1 xstrftm.c
--- xstrftm.c 8 Nov 2003 12:19:41 -0000 1.1
+++ xstrftm.c 17 Mar 2004 06:49:25 -0000
@@ -1,19 +1,38 @@
+#include <locale.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
-extern char __dj_date_format[10];
-extern char __dj_time_format[16];
+extern char __dj_date_format[];
+extern char __dj_time_format[];
int main(int ac, char *av[])
{
char buf[99];
time_t t = time(NULL);
+ char *locale;
+/* default C locale */
+ locale = setlocale( LC_TIME, NULL );
+ strftime(buf, sizeof(buf), "%x %X", gmtime(&t));
+ printf("%s locale %s\n", locale, buf);
+
+/* current locale */
+ locale = setlocale( LC_TIME, "" );
+ strftime(buf, sizeof(buf), "%x %X", gmtime(&t));
+ printf("%s locale %s\n", locale, buf);
+
+/* custom locale */
+ locale = "custom";
strcpy(__dj_date_format, "%d|%m|%Y");
strcpy(__dj_time_format, "[%H|%M|%S]");
+ strftime(buf, sizeof(buf), "%x %X", gmtime(&t));
+ printf("%s locale %s\n", locale, buf);
+/* default C locale */
+ locale = setlocale( LC_TIME, "C" );
strftime(buf, sizeof(buf), "%x %X", gmtime(&t));
- printf("%s\n", buf);
+ printf("%s locale %s\n", locale, buf);
+
return 0;
}
--- strftiml.c 2004-01-01 00:00:00.000000000 -0700
+++ strftiml.c 2004-02-18 22:32:40.000000000 -0700
@@ -0,0 +1,38 @@
+/* strftiml.c - basic time conversion calls */
+
+
+#include <stdio.h>
+#include <time.h>
+
+
+
+int main( void )
+{
+ char *p;
+ struct tm *tm_now = NULL;
+ time_t t_now = 0;
+ int n;
+ char fmts[] =
"aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ%";
+ char fmt[] = "%%\t'%%'\n";
+ char msg[1024];
+
+
+ t_now = time( NULL ); /* get current time */
+ tm_now = localtime( &t_now ); /* get local time */
+ t_now = mktime( tm_now ); /* convert back to time */
+
+ p = ctime( &t_now ); /* convert time_t to string
*/
+ printf( "ctime '%s'\n", p);
+ p = asctime( tm_now ); /* convert struct tm to
string */
+ printf( "asctime '%s'\n", p);
+ for (p = fmts; p < fmts + sizeof( fmts ); ++p)
+ {
+ n = sprintf( fmt, "%c\t'%%%c'\n", *p, *p);
+ n = strftime( msg, sizeof( msg ), fmt, tm_now);
+ n = printf( "%s", msg);
+ }
+
+ return 0;
+
+} /* main() */
+
--- strftimt.c 2004-01-01 00:00:00.000000000 -0700
+++ strftimt.c 2004-02-24 02:30:52.000000000 -0700
@@ -0,0 +1,192 @@
+/* @(#)strftimt.c 1.1 24 Feb 2004 BWI */
+
+
+
+#include <errno.h>
+#include <locale.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+
+
+static const struct
+{
+ const char * locale;
+ const char * tz;
+ const char * format;
+ const char * text;
+ struct tm tm;
+} tests[] =
+/* locale tz format text
*/
+/* sec min hr day mon year wdy
ydy dst */
+/* -1 -1970 0-6
0-* -=+ */
+{
+/* 1 */ { "C", "Universal", "%u %Y-%m-%d %H:%M:%S", "7 1999-01-31
21:01:10",
+ { 10, 1, 21, 31, 0, 99, 0,
30,-1 }},
+/* 2 */ { "C", "Universal", "%u %C%y.%b.%e %I.%M %p","7
1999.Feb.28 09.01 PM",
+ { 10, 1, 21, 28, 1, 99, 0,
58,-1 }},
+/* 3 */ { "C", "Universal", "%w %y/%h %j %k-%M-%S", "2 00/Feb 060
16-30-46",
+ { 46, 30, 16, 29, 1, 100, 2,
59,-1 }},
+/* 4 */ { "C", "Universal", "%a %y %B %e %l:%M %p", "Sat 00
January 1 12:34 PM",
+ { 12, 34, 12, 1, 0, 100, 6,
0,-1 }},
+/* 5 */ { "C", "Universal", "%A %y-%m-%d %T","Friday 00-03-03
17:41:01",
+ { 1, 41, 17, 3, 2, 100, 5,
62,-1 }},
+/* 6 */ { "C", "Universal", "%W %F %R", "36 1999-09-09
21:01",
+ { 10, 1, 21, 9, 8, 99, 4,
251,-1 }},
+/* 7 */ { "C", "Universal", "%U %D %X", "18 05/02/99
12:34:12",
+ { 12, 34, 12, 2, 4, 99, 1,
121,-1 }},
+/* 8 */ { "C", "Universal", "%x %t %r", "05/21/01 \t 09:01:10
PM",
+ { 10, 1, 21, 21, 4, 101, 1,
140,-1 }},
+/* 9 */ { "C", "Universal", "%c %n", "Mon May 21 16:30:46
2001 \n",
+ { 46, 30, 16, 21, 4, 101, 1,
140,-1 }},
+/* 10 */ { "C", "Universal", "%F %T %Z", "2000-01-05 17:41:01
UTC",
+ { 1, 41, 17, 5, 0, 100, 3,
4,-1 }},
+/* 11 */ { "C", "Universal", "%F %T %z", "2000-01-05 17:41:01
+0000",
+ { 1, 41, 17, 5, 0, 100, 3,
4,-1 }},
+/* 12 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"1975-12-29 1976-W01-1 1975-w52-1 1975-u52-1",
+ { 0, 0, 0, 29, 11, 75, 0,
362,-1 }},
+/* 13 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"1977-01-02 1976-W53-7 1977-w00-7 1977-u01-0",
+ { 0, 0, 0, 2, 0, 77, 0,
1,-1 }},
+/* 14 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"1999-01-02 1998-W53-6 1999-w00-6 1999-u00-6",
+ { 0, 0, 0, 2, 0, 99, 5,
1,-1 }},
+/* 15 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"1999-12-27 1999-W52-1 1999-w52-1 1999-u52-1",
+ { 0, 0, 0, 27, 11, 99, 0,
360,-1 }},
+/* 16 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2000-01-02 1999-W52-7 2000-w00-7 2000-u01-0",
+ { 0, 0, 0, 2, 0, 100, 0,
1,-1 }},
+/* 17 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2003-12-28 2003-W52-7 2003-w51-7 2003-u52-0",
+ { 0, 0, 0, 28, 11, 103, 0,
361,-1 }},
+/* 18 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2003-12-29 2004-W01-1 2003-w52-1 2003-u52-1",
+ { 0, 0, 0, 29, 11, 103, 0,
362,-1 }},
+/* 19 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2003-12-31 2004-W01-3 2003-w52-3 2003-u52-3",
+ { 0, 0, 0, 31, 11, 103, 2,
364,-1 }},
+/* 20 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2004-01-01 2004-W01-4 2004-w00-4 2004-u00-4",
+ { 0, 0, 0, 1, 0, 104, 3,
0,-1 }},
+/* 21 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2004-01-04 2004-W01-7 2004-w00-7 2004-u01-0",
+ { 0, 0, 0, 4, 0, 104, 0,
3,-1 }},
+/* 22 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2004-01-05 2004-W02-1 2004-w01-1 2004-u01-1",
+ { 0, 0, 0, 5, 0, 104, 0,
4,-1 }},
+/* 23 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2004-12-26 2004-W52-7 2004-w51-7 2004-u52-0",
+ { 0, 0, 0, 26, 11, 104, 0,
360,-1 }},
+/* 24 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2004-12-27 2004-W53-1 2004-w52-1 2004-u52-1",
+ { 0, 0, 0, 27, 11, 104, 0,
361,-1 }},
+/* 25 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2004-12-31 2004-W53-5 2004-w52-5 2004-u52-5",
+ { 0, 0, 0, 31, 11, 104, 4,
365,-1 }},
+/* 26 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2005-01-01 2004-W53-6 2005-w00-6 2005-u00-6",
+ { 0, 0, 0, 1, 0, 105, 5,
0,-1 }},
+/* 27 */ { "C", "Universal", "%F %G-W%V-%u %Y-w%W-%u %Y-u%U-%w",
"2005-01-03 2005-W01-1 2005-w01-1 2005-u01-1",
+ { 0, 0, 0, 3, 0, 105, 0,
2,-1 }},
+/* 28 */ { "C", "Universal", "%F %g-W%V-%u %y-w%W-%u %y-u%U-%w",
"2012-01-01 11-W52-7 12-w00-7 12-u01-0",
+ { 0, 0, 0, 1, 0, 112, 0,
0,-1 }},
+/* 29 */ { "C", "Universal", "%F %g-W%V-%u %y-w%W-%u %y-u%U-%w",
"2012-02-29 12-W09-3 12-w09-3 12-u09-3",
+ { 0, 0, 0, 29, 01, 112, 2,
59,-1 }},
+/* 30 */ { "C", "Universal", "%F %g-W%V-%u %y-w%W-%u %y-u%U-%w",
"2012-12-31 13-W01-1 12-w53-1 12-u53-1",
+ { 0, 0, 0, 31, 11, 112, 0,
365,-1 }},
+/* 31 */ { "C", "EST5EDT", "%c %Z %s W%V w%W u%U", "Fri Oct 1
15:30:34 1993 EDT 749503834 W39 w39 u39",
+ { 34, 30, 15, 1, 9, 93, 5,
273,-1 }},
+/* 32 */ { "C", "Europe/Berlin","%d.%m.%Y %T %Z","01.08.2000 05:06:07
CEST",
+ { 7, 6, 5, 1, 7, 100, 0,
0,-1 }},
+/* 33 */ { "C", "Europe/Berlin","%d.%m.%Y %T %z","01.08.2000 05:06:07
+0200",
+ { 7, 6, 5, 1, 7, 100, 0,
0,-1 }},
+#if 0 /* not yet supported */
+/* 34 */ { "ja_JP.EUC-JP","Universal", "%Y %U %a", "2001 20
\xb7\xee",
+ { 0, 0, 0, 21, 4, 101, 1,
140,-1 }},
+/* 35 */ { "ja_JP.EUC-JP","Universal", "%Y %W %a", "2001 21
\xb7\xee",
+ { 0, 0, 0, 21, 4, 101, 1,
140,-1 }},
+/* 36 */ { "ja_JP.EUC-JP","Asia/Tokyo", "%Y %W %a", "2001 21
\xb7\xee",
+ { 0, 0, 0, 21, 4, 101, 1,
140,-1 }},
+
+#endif /* 0 */
+};
+
+
+
+int
+main (int argc, char *argv[])
+{
+ time_t tt;
+ size_t t;
+ size_t len = 0;
+ int rc = 0;
+ int errs = 0;
+ struct tm tm = { 0 };
+ char text[BUFSIZ] = "";
+
+ for (t = 0; t < sizeof tests / sizeof *tests; ++t)
+ {
+ errno = 0;
+
+ if (setlocale( LC_TIME, tests[t].locale) == NULL)
+ {
+ if (errno) perror( "setlocale()" );
+ printf( "test %3d error %6s set locale '%s' category
'%s'(%d) \n",
+ t + 1, "NULL", tests[t].locale,
"LC_TIME", LC_TIME);
+ ++errs;
+ continue;
+ }
+
+ if ((rc = setenv( "TZ", tests[t].tz, 1)))
+ {
+ if (errno) perror( "setenv()" );
+ printf( "test %3d error %6d set environment '%s' '%s'
\n",
+ t + 1, rc, "TZ",
tests[t].tz);
+ ++errs;
+ continue;
+ }
+
+ tzset();
+
+ tm = tests[t].tm;
+
+ if ((tt = mktime( &tm )) == -1)
+ {
+ if (errno) perror( "mktime()" );
+ printf( "test %3d error %6d make time "
+ "%04d-%02d-%02d %02d:%02d:%02d j%03d w%01d dst %d
\n",
+ t + 1, tt,
+ tests[t].tm.tm_year + 1900,
+ tests[t].tm.tm_mon + 1,
+ tests[t].tm.tm_mday,
+ tests[t].tm.tm_hour,
+ tests[t].tm.tm_min,
+ tests[t].tm.tm_sec,
+ tests[t].tm.tm_yday +
1,
+
tests[t].tm.tm_wday,
+
tests[t].tm.tm_isdst);
+ ++errs;
+ continue;
+ }
+
+ if (!(len = strftime( text, sizeof text, tests[t].format,
&tm)))
+ {
+ if (errno) perror( "strftime()" );
+ printf( "test %3d error %6d time format '%s' \n",
+ t + 1, len, tests[t].format);
+ ++errs;
+ continue;
+ }
+
+ if (strlen( tests[t].text ) != strlen( text )
+ || strcmp( tests[t].text, text))
+ {
+ printf( "\n test %3d error %6s expected '%s' \n"
+ " actual '%s' \n",
+ t + 1, "FAILED", tests[t].text,
text);
+ ++errs;
+ continue;
+ }
+ }
+
+ if (errs)
+ {
+ printf( "tests %2d errors %5d passed %d \n",
+ sizeof tests / sizeof *tests,
+ errs,
+ sizeof tests / sizeof *tests
- errs);
+ }
+
+ return errs;
+
+} /* main() */
+
--
Thanks. Take care, Brian Inglis
Business: +1(403)547-8816 Brian DOT Inglis AT SystematicSW DOT ab DOT ca
Residence: +1(403)239-6520 BWInglis AT Shaw DOT ca
Cellular: +1(403)708-7006 Brian_Inglis AT CompuServe DOT com
Facsimile: +1(403)547-8816 Brian_Inglis AT CSi DOT com
- Raw text -