Skip to content

Commit

Permalink
Bring back Y2K code as DEPRECATE_TWO_DIGIT_YEARS
Browse files Browse the repository at this point in the history
Perhaps this stuff will be useful around 2100.
Requested by Brian Inglis in:
http://mm.icann.org/pipermail/tz/2017-June/025138.html
* Makefile, NEWS: Mention this.
* strftime.c (YEAR_2000_NAME, IN_NONE, IN_SOME, IN_THIS, IN_ALL):
Bring back these symbols and their uses, except warn if
DEPRECATE_TWO_DIGIT_YEARS, and use enum rather than int.
(strftime): Warn about Y2K problems.
(_fmt): Bring back last (warning) arg; all uses changed.
  • Loading branch information
eggert committed Jun 13, 2017
1 parent bb5252a commit 1da3b6e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 15 deletions.
2 changes: 2 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,8 @@ LDLIBS=

# Add the following to the end of the "CFLAGS=" line as needed.
# -DBIG_BANG=-9999999LL if the Big Bang occurred at time -9999999 (see zic.c)
# -DDEPRECATE_TWO_DIGIT_YEARS for optional runtime warnings about strftime
# formats that generate only the last two digits of year numbers
# -DHAVE_DECL_ASCTIME_R=0 if <time.h> does not declare asctime_r
# -DHAVE_DECL_ENVIRON if <unistd.h> declares 'environ'
# -DHAVE_DIRECT_H if mkdir needs <direct.h> (MS-Windows)
Expand Down
7 changes: 5 additions & 2 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ Unreleased, experimental changes
or that lack the nsgmls program. Set UTF8_LOCALE to configure
the name of a UTF-8 locale, if you have one.

Y2K runtime checks are no longer enabled by default. Add
-DDEPRECATE_TWO_DIGIT_YEARS to CFLAGS to enable them, instead of
adding -DNO_RUN_TIME_WARNINGS_ABOUT_YEAR_2000_PROBLEMS_THANK_YOU
to disable them. (New name suggested by Brian Inglis.)

The build procedure for zdump now works on AIX 7.1.
(Problem reported by Kees Dekker.)

Expand Down Expand Up @@ -81,8 +86,6 @@ Unreleased, experimental changes
other two variables as optional. Also, USG_COMPAT is now 1 or 0:
if not defined, the code attempts to guess it from other macros.

Y2K runtime checks have been removed, as Y2K was years ago.

localtime.c and difftime.c no longer require stdio.h, and .c files
other than zic.c no longer require sys/wait.h.

Expand Down
70 changes: 57 additions & 13 deletions strftime.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#include <locale.h>
#include <stdio.h>

#ifndef DEPRECATE_TWO_DIGIT_YEARS
# define DEPRECATE_TWO_DIGIT_YEARS false
#endif

struct lc_time_T {
const char * mon[MONSPERYEAR];
const char * month[MONSPERYEAR];
Expand Down Expand Up @@ -100,11 +104,18 @@ static const struct lc_time_T C_time_locale = {
"%a %b %e %H:%M:%S %Z %Y"
};

enum warn { IN_NONE, IN_SOME, IN_THIS, IN_ALL };

static char * _add(const char *, char *, const char *);
static char * _conv(int, const char *, char *, const char *);
static char * _fmt(const char *, const struct tm *, char *, const char *);
static char * _fmt(const char *, const struct tm *, char *, const char *,
enum warn *);
static char * _yconv(int, int, bool, bool, char *, char const *);

#ifndef YEAR_2000_NAME
#define YEAR_2000_NAME "CHECK_STRFTIME_FORMATS_FOR_TWO_DIGIT_YEARS"
#endif /* !defined YEAR_2000_NAME */

#if HAVE_STRFTIME_L
size_t
strftime_l(char *s, size_t maxsize, char const *format, struct tm const *t,
Expand All @@ -119,17 +130,31 @@ size_t
strftime(char *s, size_t maxsize, const char *format, const struct tm *t)
{
char * p;
enum warn warn = IN_NONE;

tzset();
p = _fmt(format, t, s, s + maxsize);
p = _fmt(format, t, s, s + maxsize, &warn);
if (DEPRECATE_TWO_DIGIT_YEARS
&& warn != IN_NONE && getenv(YEAR_2000_NAME)) {
fprintf(stderr, "\n");
fprintf(stderr, "strftime format \"%s\" ", format);
fprintf(stderr, "yields only two digits of years in ");
if (warn == IN_SOME)
fprintf(stderr, "some locales");
else if (warn == IN_THIS)
fprintf(stderr, "the current locale");
else fprintf(stderr, "all locales");
fprintf(stderr, "\n");
}
if (p == s + maxsize)
return 0;
*p = '\0';
return p - s;
}

static char *
_fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
_fmt(const char *format, const struct tm *t, char *pt,
const char *ptlim, enum warn *warnp)
{
for ( ; *format; ++format) {
if (*format == '%') {
Expand Down Expand Up @@ -175,10 +200,18 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
true, false, pt, ptlim);
continue;
case 'c':
pt = _fmt(Locale->c_fmt, t, pt, ptlim);
{
enum warn warn2 = IN_SOME;

pt = _fmt(Locale->c_fmt, t, pt, ptlim, &warn2);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'D':
pt = _fmt("%m/%d/%y", t, pt, ptlim);
pt = _fmt("%m/%d/%y", t, pt, ptlim, warnp);
continue;
case 'd':
pt = _conv(t->tm_mday, "%02d", pt, ptlim);
Expand All @@ -199,7 +232,7 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
pt = _conv(t->tm_mday, "%2d", pt, ptlim);
continue;
case 'F':
pt = _fmt("%Y-%m-%d", t, pt, ptlim);
pt = _fmt("%Y-%m-%d", t, pt, ptlim, warnp);
continue;
case 'H':
pt = _conv(t->tm_hour, "%02d", pt, ptlim);
Expand Down Expand Up @@ -263,10 +296,10 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
pt, ptlim);
continue;
case 'R':
pt = _fmt("%H:%M", t, pt, ptlim);
pt = _fmt("%H:%M", t, pt, ptlim, warnp);
continue;
case 'r':
pt = _fmt("%I:%M:%S %p", t, pt, ptlim);
pt = _fmt("%I:%M:%S %p", t, pt, ptlim, warnp);
continue;
case 'S':
pt = _conv(t->tm_sec, "%02d", pt, ptlim);
Expand All @@ -289,7 +322,7 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
}
continue;
case 'T':
pt = _fmt("%H:%M:%S", t, pt, ptlim);
pt = _fmt("%H:%M:%S", t, pt, ptlim, warnp);
continue;
case 't':
pt = _add("\t", pt, ptlim);
Expand Down Expand Up @@ -391,6 +424,7 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
pt = _conv(w, "%02d",
pt, ptlim);
else if (*format == 'g') {
*warnp = IN_ALL;
pt = _yconv(year, base,
false, true,
pt, ptlim);
Expand All @@ -405,7 +439,7 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
** "date as dd-bbb-YYYY"
** (ado, 1993-05-24)
*/
pt = _fmt("%e-%b-%Y", t, pt, ptlim);
pt = _fmt("%e-%b-%Y", t, pt, ptlim, warnp);
continue;
case 'W':
pt = _conv((t->tm_yday + DAYSPERWEEK -
Expand All @@ -418,12 +452,21 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
pt = _conv(t->tm_wday, "%d", pt, ptlim);
continue;
case 'X':
pt = _fmt(Locale->X_fmt, t, pt, ptlim);
pt = _fmt(Locale->X_fmt, t, pt, ptlim, warnp);
continue;
case 'x':
pt = _fmt(Locale->x_fmt, t, pt, ptlim);
{
enum warn warn2 = IN_SOME;

pt = _fmt(Locale->x_fmt, t, pt, ptlim, &warn2);
if (warn2 == IN_ALL)
warn2 = IN_THIS;
if (warn2 > *warnp)
*warnp = warn2;
}
continue;
case 'y':
*warnp = IN_ALL;
pt = _yconv(t->tm_year, TM_YEAR_BASE,
false, true,
pt, ptlim);
Expand Down Expand Up @@ -516,7 +559,8 @@ _fmt(const char *format, const struct tm *t, char *pt, const char *ptlim)
#endif
continue;
case '+':
pt = _fmt(Locale->date_fmt, t, pt, ptlim);
pt = _fmt(Locale->date_fmt, t, pt, ptlim,
warnp);
continue;
case '%':
/*
Expand Down

0 comments on commit 1da3b6e

Please sign in to comment.