Bug 2027416 - glibc: mktime sometimes returns -1 with errno EOVERFLOW when the tm_isdst=1 for non-DST dates
Summary: glibc: mktime sometimes returns -1 with errno EOVERFLOW when the tm_isdst=1 f...
Keywords:
Status: CLOSED EOL
Alias: None
Product: Fedora
Classification: Fedora
Component: glibc
Version: 34
Hardware: x86_64
OS: Linux
unspecified
unspecified
Target Milestone: ---
Assignee: Carlos O'Donell
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2021-11-29 15:17 UTC by Peter
Modified: 2022-06-08 06:22 UTC (History)
12 users (show)

Fixed In Version:
Clone Of:
Environment:
Last Closed: 2022-06-08 06:22:49 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
test program to reproduce the bug (508 bytes, text/x-csrc)
2021-11-29 15:17 UTC, Peter
no flags Details

Description Peter 2021-11-29 15:17:42 UTC
Created attachment 1844031 [details]
test program to reproduce the bug

Description of problem: mktime returns -1 with errno EOVERFOW when the tm_isdst=1 for non-DST dates


Version-Release number of selected component (if applicable): 
glibc-2.32-10.fc33.x86_64


How reproducible:


Steps to Reproduce:
1. Compile and run the program test_isdst_1: gcc test_isdst_1.c -o test_isdst_1
2. run with: TZ=Europe/Paris ./test_isdst_1
3. run with: TZ=Europe/Moscow ./test_isdst_1

Actual results: 
TZ=Europe/Moscow ./test_isdst_1
<long list from year 1900>
....
2019 1547064000 0 Wed Jan  9 23:00:00 2019
2020 Value too large for defined data type
2021 Value too large for defined data type

Expected results:
At least
...
2019 1547064000 0 Wed Jan  9 23:00:00 2019
2020 1578603600 0 Fri Jan 10 00:00:00 2020
2021 1610226000 0 Sun Jan 10 00:00:00 2021

as in Scientific Linux or Debian or Fedora Core 16
Additional info:

There is another bug that timestamps are changed (9 23:00:00 2019)
when should be exact 10 00:00:00, but this need to be addressed to glibc.

Comment 1 Peter 2021-11-29 15:37:58 UTC
Various time zones show regression in different years

Comment 2 Ben Cotton 2021-11-30 16:04:22 UTC
Fedora 33 changed to end-of-life (EOL) status on 2021-11-30. Fedora 33 is
no longer maintained, which means that it will not receive any further
security or bug fix updates. As a result we are closing this bug.

If you can reproduce this bug against a currently maintained version of
Fedora please feel free to reopen this bug against that version. If you
are unable to reopen this bug, please file a new report against the
current release. If you experience problems, please add a comment to this
bug.

Thank you for reporting this bug and we are sorry it could not be fixed.

Comment 3 Carlos O'Donell 2021-11-30 20:28:01 UTC
Why do you consider the current behaviour a bug?

Please note that timezone data does and will change, so the exact results of mktime will change over time.

In this specific example you have set tm_isdst, which is to say that you have told mktime to presume that DST was in effect for this time.

This means that the function will attempt to find the *nearest* calendar time that fits.

In this case there is no nearby calendar time that has DST set for Europe/Moscow because, since 2010, Moscow does not observe DST.

Since it has been a long time since a DST time was in effect in that zone the heuristics for finding a calendar time that meet your requirement of tm_isdst fail, and -1 / EOVERFLOW is returned.

In general, if you set tm_isdst to 1 then mktime *may* fail if it can't easily find a calendar time that matches.

Are you trying to fix a specific upstream testsuite issue?

Comment 4 Peter 2021-12-01 07:36:49 UTC
Hi, Carlos!

The "bug" -- maybe too strong )). But the regression at least.
Looking at the earlier glibc versions one can see that mktime does not give the different results in the same situation.

First of all the -EOVERFLOW appears sometimes. All other calls of the mktime with isdst=-1 on non-DST dates return the "almost normal" results.
Using various time zones it looks as "noisy" process that unpredictable to the programmer.
By the way, nothing overflows in that cases to set EOVERFLOW error.

When I tell mktime to presume that DST is not in affect (0) at the summer dates, mktime works wery well, 
newer -EOVERFLOF returns and all timestamps are right! Moreover, mktime changes isdst to the right value (0) when DST is not in effect (and do not touch my timestamp !!!+).
This predictable behavior of the mktime is too contrasting with the unpredictable previous.

You wrote that "the function will attempt to find the *nearest* calendar time that fits". 
Ok, but the man page does not say that mktime should to do this at all. 
Exept the normalisation case (say, Jul 40) mktime shouldn't change the user input (to shift seconds counter).
But the procedure of "finding nearest" do this. 
I think that it is a "free interpretation" of the POSIX.

I think the right behavior of the mktime in the case isdst=1 for non-DST dates will be the same as for the cases isdst=0 for DST dates:
"user, you are mistekenly guess that the DST is in effect, it is not )))) 
But never - to find "something that matches". 
But this is philosophical question, you can disagree )))

My interest in this connected with the astronomical and automation software that I'm writing.
Appearance of the "right" time zones and the "almost TAI" time lets the some things simpler. 
But the time support in glibc is a nutshell!! )) Espetially the time zones interface. )))
I was trying use the mktime in the "ambiguous times detection" task.
Sometimes I understand people and companies which are writing theirs own code for the timezone files parsing and timezones database support.

Sincerely,
Peter.

Comment 5 Peter 2021-12-01 12:51:41 UTC
"Please note that timezone data does and will change, so the exact results of mktime will change over time."

By the way, 
zdump -v Europe/Moscow | grep 2014
shows the following:

Europe/Moscow  Sat Oct 25 21:59:59 2014 UT = Sun Oct 26 01:59:59 2014 MSK isdst=0 gmtoff=14400
Europe/Moscow  Sat Oct 25 22:00:00 2014 UT = Sun Oct 26 01:00:00 2014 MSK isdst=0 gmtoff=10800

As can be seeing, isdst=0 in both strings.
Is this right records in time zone file or it can be a bug?

Comment 6 Peter 2021-12-01 13:02:13 UTC
Oh.. Comment 5 can be discarded...

Comment 7 Carlos O'Donell 2021-12-14 19:40:39 UTC
(In reply to Peter from comment #4)
> Looking at the earlier glibc versions one can see that mktime does not give
> the different results in the same situation.

Correct.

This is because the results of the API query depend on dates, and dates are constantly moving forward.

Eventually you will also cross the y2038 border after which things will change again unless you have 64-bit time_t.
 
> First of all the -EOVERFLOW appears sometimes. All other calls of the mktime
> with isdst=-1 on non-DST dates return the "almost normal" results.
> Using various time zones it looks as "noisy" process that unpredictable to
> the programmer.

What software are you testing?

Are you testing C library implementations for portability?

It is possible to give mktime a broken-down time that it cannot reconcile to produce time_t.

In this case you've asked for a time with DST enabled, but no such time exists *near-enough* (heuristically) to your requested time for the search algorithm to find a sensible time.

> By the way, nothing overflows in that cases to set EOVERFLOW error.

POSIX error code EOVERFLOW means "The result cannot be represented."

You are correct that nothing "overflows" the error code is used to represent the case where the algorithm failed to turn the broken down time into time_t.
 
> When I tell mktime to presume that DST is not in affect (0) at the summer
> dates, mktime works wery well, 

Correct, because the algorithm can find a time at which DST is not in effect, in this case clocks do not change in Moscow (DST is not in effect).

> newer -EOVERFLOF returns and all timestamps are right! Moreover, mktime
> changes isdst to the right value (0) when DST is not in effect (and do not
> touch my timestamp !!!+).

If you have specific results that you feel are incorrect, for a given version of glibc, and a given version of tzdata, we should review those.

> This predictable behavior of the mktime is too contrasting with the
> unpredictable previous.

mktime() results depend on tzdata, and as time advances, results will change.

If we can find an incorrect result I can take this upstream.
 
> You wrote that "the function will attempt to find the *nearest* calendar
> time that fits". 
> Ok, but the man page does not say that mktime should to do this at all. 

Then we can fix this in the man page.

Normalization happens *also* for tm_isdst since the API is trying to comply with your request to find a time that exists when DST matches.

> Exept the normalisation case (say, Jul 40) mktime shouldn't change the user
> input (to shift seconds counter).
> But the procedure of "finding nearest" do this. 
> I think that it is a "free interpretation" of the POSIX.

The code in question is this:

glibc/time/mktime.c:

424   /* We have a match.  Check whether tm.tm_isdst has the requested
425      value, if any.  */
426   if (isdst_differ (isdst, tm.tm_isdst))
427     {
428       /* tm.tm_isdst has the wrong value.  Look for a neighboring
429          time with the right value, and use its UTC offset.
430 
431          Heuristic: probe the adjacent timestamps in both directions,
432          looking for the desired isdst.  This should work for all real
433          time zone histories in the tz database.  */

... and this can produce some some interesting results in an attempt to honour finding tm_isdst that matches.

We have used such search heuristics since 1998 for the implementation.

A few things have changed though in 2018 (glibc 2.29) where we started to more eagerly
return EOVERFLOW if we could not find a matching tm_isdst.
 
> I think the right behavior of the mktime in the case isdst=1 for non-DST
> dates will be the same as for the cases isdst=0 for DST dates:
> "user, you are mistekenly guess that the DST is in effect, it is not )))) 
> But never - to find "something that matches". 
> But this is philosophical question, you can disagree )))

I don't have a strong opinion, but the code from 1998 which has been in place
since then attemps to do the match.

The question we can try to answer is: If the exact tm_idst match fails, then what?

Today you get EOVERFLOW. You can re-try the API query with isdst=-1, which means
you don't know? I tested this and it works as expected.

> My interest in this connected with the astronomical and automation software
> that I'm writing.

Thank you, that answers my question about what software you are testing.

> Appearance of the "right" time zones and the "almost TAI" time lets the some
> things simpler. 
> But the time support in glibc is a nutshell!! )) Espetially the time zones
> interface. )))

I think you must retry with tm_isdst=-1 if you get an EOVERFLOW and let the
API tell you what is in effect.

> I was trying use the mktime in the "ambiguous times detection" task.
> Sometimes I understand people and companies which are writing theirs own
> code for the timezone files parsing and timezones database support.

They will face the same problem ;-)

In summary:
- Does retrying with tm_isdst=-1 a solution for you?

Comment 8 Peter 2022-01-09 15:17:52 UTC
(In reply to Carlos O'Donell from comment #7)
> (In reply to Peter from comment #4)
> > Looking at the earlier glibc versions one can see that mktime does not give
> > the different results in the same situation.
> 
> Correct.
> 
> This is because the results of the API query depend on dates, and dates are
> constantly moving forward.

This is not the case. 
Run the following:
TZ=Europe/Paris ./test_isdst_1 

The result the following (from the middle of the output)

1954 -504151200 0 Sat Jan  9 23:00:00 1954
1955 Value too large for defined data type
1956 Value too large for defined data type
1957 Value too large for defined data type
1958 Value too large for defined data type
1959 Value too large for defined data type
1960 Value too large for defined data type
1961 Value too large for defined data type
1962 Value too large for defined data type
1963 Value too large for defined data type
1964 Value too large for defined data type
1965 Value too large for defined data type
1966 Value too large for defined data type
1967 Value too large for defined data type
1968  -62388000 0 Tue Jan  9 23:00:00 1968

This is a historical data. 
The output with the earlier versions of glibc was without the EOWERFLOW.

> It is possible to give mktime a broken-down time that it cannot reconcile to
> produce time_t.
> 
> In this case you've asked for a time with DST enabled, but no such time
> exists *near-enough* (heuristically) to your requested time for the search
> algorithm to find a sensible time.

Take a look, please, at the following example.
TZ=Europe/Moscow ./test_isdst_1
Last strings shows the following:

2010 1263067200 0 Sat Jan  9 23:00:00 2010
2011 1294603200 0 Sun Jan  9 23:00:00 2011
2012 1326139200 0 Tue Jan 10 00:00:00 2012
2013 1357761600 0 Thu Jan 10 00:00:00 2013
2014 1389297600 0 Fri Jan 10 00:00:00 2014
2015 1420833600 0 Fri Jan  9 23:00:00 2015
2016 1452369600 0 Sat Jan  9 23:00:00 2016
2017 1483992000 0 Mon Jan  9 23:00:00 2017
2018 1515528000 0 Tue Jan  9 23:00:00 2018
2019 1547064000 0 Wed Jan  9 23:00:00 2019
2020 Value too large for defined data type
2021 Value too large for defined data type

The expected result:
1) Jan 10 00:00:00
2) dst_flag is not set according to manpage:
"tm_isdst is set (regardless of its initial value) to a positive value or to 0, respectively, to indicate whether DST is or is not in 
effect at the specified time."

Why this resultis expected?
Because date/time given is normalised and exists, and can be represented by the time_t and manpage says that.. see cite above.
(It should be noted, that the DST rules does not applied in the Moscow timezone since October 2010).

Is the following output correct?

2010 1263067200 0 Sat Jan  9 23:00:00 2010

It is not, because the "Jan  9 23:00:00 2010" is not a date/time of interest
(the required date/time is Jan 10 00:00:00 2010).
The tm_isdst flag set correctly according to manpage.

Is the following output correct?

2012 1326139200 0 Tue Jan 10 00:00:00 2012

Yes, it is, because the date/time is as requested and tm_isdst = 0.

But:
what happens at 2020? I'm can't explain. And 2021 too.

All these 3 different results are obtained from the same algorythm with the same mktime call.

The next question is the following:
can these 3 results be useful to the software developer?
Can he make some decision based on these results?

The answer is: partially yes. Partially - I mean the second result, which is right.
More precisely - only 3 string from the program output:

2012 1326139200 0 Tue Jan 10 00:00:00 2012
2013 1357761600 0 Thu Jan 10 00:00:00 2013
2014 1389297600 0 Fri Jan 10 00:00:00 2014

The remaining strings from this example can not be neither used nor explained.

It seems that the main issue is that mktime tries to find something *near-enough*
in context of tm_isdst flag for already normalised end existing broken-down date-time (which can be represented).
But all that required is simply to look in the timezone database and to make correction according correction of the tm_isdst flag
(as was said in the manpage).

By the way, the same behavior of mktime I found in the Fedora 35.

> In summary:
> - Does retrying with tm_isdst=-1 a solution for you?

No, it does not, because at the ambiguous times (where both isdst=0 and isdst=1 values are valid) 
the only one value is set by mktime in this case (tm_isdst=-1).

Comment 9 Ben Cotton 2022-05-12 16:51:29 UTC
This message is a reminder that Fedora Linux 34 is nearing its end of life.
Fedora will stop maintaining and issuing updates for Fedora Linux 34 on 2022-06-07.
It is Fedora's policy to close all bug reports from releases that are no longer
maintained. At that time this bug will be closed as EOL if it remains open with a
'version' of '34'.

Package Maintainer: If you wish for this bug to remain open because you
plan to fix it in a currently maintained version, change the 'version' 
to a later Fedora Linux version.

Thank you for reporting this issue and we are sorry that we were not 
able to fix it before Fedora Linux 34 is end of life. If you would still like 
to see this bug fixed and are able to reproduce it against a later version 
of Fedora Linux, you are encouraged to change the 'version' to a later version
prior to this bug being closed.

Comment 10 Ben Cotton 2022-06-08 06:22:49 UTC
Fedora Linux 34 entered end-of-life (EOL) status on 2022-06-07.

Fedora Linux 34 is no longer maintained, which means that it
will not receive any further security or bug fix updates. As a result we
are closing this bug.

If you can reproduce this bug against a currently maintained version of
Fedora please feel free to reopen this bug against that version. If you
are unable to reopen this bug, please file a new report against the
current release.

Thank you for reporting this bug and we are sorry it could not be fixed.


Note You need to log in before you can comment on or make changes to this bug.