This is the mail archive of the libc-alpha@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Ensure mktime sets errno on error (bug 23789)


* Zack Weinberg:

> On Thu, Oct 25, 2018 at 10:03 AM Albert ARIBAUD <albert.aribaud@3adev.fr> wrote:
>
>> Hmm... Posix defines the value returned by mktime to be "Seconds since
>> the Epoch" thus: <http://pubs.opengroup.org/onlinepubs/9699919799/>.
>> According to this definition, a year below 1970 makes the corresponding
>> seconds since the epoch value undefined, so I wonder whether the struct
>> tm above is not outside the allowed limits for mktime().
>
> That may be true per the letter of POSIX, but there are enough
> programs that expect to be able to use negative time_t values to work
> with dates prior to 1970 that glibc needs to support this usage
> anyway.

There is also this:

| 4.16 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

<http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_16>

I think the formula is only valid for the year 1970 and later years.
Running the test program below gives me:

  error: tm_yday: expected 4, got 5
  gmtime-before-1970: errors found for year 1968, exiting

So negative epoch values are clearly an extension over POSIX, but it's a
widely used one, I think.

Thanks,
Florian

#include <err.h>
#include <inttypes.h>
#include <stdbool.h>
#include <stdio.h>
#include <time.h>

static void
check (const char *what, bool *good, int64_t expected, int64_t actual)
{
  if (expected != actual)
    {
      printf ("error: %s: expected %" PRId64 ", got %" PRId64 "\n",
              what, expected, actual);
      *good = false;
    }
}

int
main (void)
{
  int64_t tm_sec = 1;
  int64_t tm_min = 2;
  int64_t tm_hour = 3;
  int64_t tm_yday = 4;
  for (int64_t tm_year = 120; tm_year > -500; --tm_year)
    {
      int64_t epoch = 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;
      time_t time_epoch = epoch;
      struct tm *tm = gmtime (&time_epoch);
      if (tm == NULL)
        err (1, "gmtime");
      bool good = true;
      check ("tm_sec", &good, tm_sec, tm->tm_sec);
      check ("tm_min", &good, tm_min, tm->tm_min);
      check ("tm_hour", &good, tm_hour, tm->tm_hour);
      check ("tm_yday", &good, tm_yday, tm->tm_yday);
      check ("tm_year", &good, tm_year, tm->tm_year);
      if (!good)
        errx (1, "errors found for year %" PRId64 ", exiting",
              1900 + tm_year);
    }
  return 0;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]