This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: bug in time.mktime
Type: behavior Stage: resolved
Components: Library (Lib) Versions:
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: eryksun, kliano, tim.peters
Priority: normal Keywords:

Created on 2017-09-30 00:19 by kliano, last changed 2022-04-11 14:58 by admin. This issue is now closed.

Messages (5)
msg303378 - (view) Author: Kadir Liano (kliano) Date: 2017-09-30 00:19
import time
fmt = '%d-%b-%y %H:%M:%S'
print(time.mktime(time.strptime('09-Mar-14 02:00:00',fmt)))

1394348400.0 in Windows 7, Python 2.7 and 3.6
1394352000.0 in LinuxMint LMDE 2, Python 3.6
msg303390 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2017-09-30 03:50
mktime() is the inverse of localtime(). With the given format string, strptime() sets tm_isdst to -1, for which mktime will use the system's timezone information to determine whether or not it's daylight saving time. You need to verify that the time zones are the same. 

For me the results agree in Linux and Windows with the local timezone on both systems set to the UK.

9 March (GMT, standard time)

    Linux
    >>> time.mktime(time.struct_time((2014, 3, 9, 2, 0, 0, 6, 68, 0)))
    1394330400.0
    >>> time.mktime(time.struct_time((2014, 3, 9, 2, 0, 0, 6, 68, -1)))
    1394330400.0

    Windows
    >>> time.mktime(time.struct_time((2014, 3, 9, 2, 0, 0, 6, 68, 0)))
    1394330400.0
    >>> time.mktime(time.struct_time((2014, 3, 9, 2, 0, 0, 6, 68, -1)))
    1394330400.0

9 August (BST, daylight saving time)

    Linux
    >>> time.mktime(time.struct_time((2014, 8, 9, 2, 0, 0, 6, 68, 1)))
    1407546000.0
    >>> time.mktime(time.struct_time((2014, 8, 9, 2, 0, 0, 6, 68, -1)))
    1407546000.0

    Windows
    >>> time.mktime(time.struct_time((2014, 8, 9, 2, 0, 0, 6, 68, 1)))
    1407546000.0
    >>> time.mktime(time.struct_time((2014, 8, 9, 2, 0, 0, 6, 68, -1)))
    1407546000.0
msg303393 - (view) Author: Kadir Liano (kliano) Date: 2017-09-30 04:48
time.mktime(time.strptime('09-Mar-14 01:00:00',fmt))
time.mktime(time.strptime('09-Mar-14 02:00:00',fmt))

Both statements produce 1394348400.0 in Win7.  The answers are 1394348400.0 and 1394352000.0 in Linux which is the correct behavior.
msg303395 - (view) Author: Eryk Sun (eryksun) * (Python triager) Date: 2017-09-30 06:11
This depends on the way the platform mktime implements folding when the clock is advanced for daylight saving time. It appears the timezone on your systems is set to US/Canada Central Time, for which on March 9th the clocks were advanced forward at 02:00:00 [1]. Windows mktime folds back at 02:00:00, repeating the 01:00:00-01:59:59 timestamps. Linux mktime has a fold at 03:00:00, repeating the 02:00:00-02:59:59 timestamps. What matters is that both are correct on the boundaries for observed local times, i.e. they both give the same values for 01:59:59 and 03:00:00, which are respectively 1394351999 and 1394352000.

[1]: https://www.timeanddate.com/time/dst/2014a.html
msg303415 - (view) Author: Tim Peters (tim.peters) * (Python committer) Date: 2017-09-30 16:55
Note that 2am doesn't exist on the local clock:  it leaps from 1:59:59 to 3:00:00.  You're claiming that one answer is "correct", but why?  The relevant _standards_ don't appear to specify what happens when the input is senseless.  Note that the behavior isn't really due to Python, but to the platform C libraries.

Windows is treating 2am as if DST were already in effect, so senseless times of the form 2:MM:SS are treated the same as 1:MM:SS before DST came into play.  Linux is treating 2am as if the DST switch hadn't yet happened, so senseless times of the form 2:MM:SS are treated the same as 3:MM:SS after DST came into play.

In favor of the Windows approach, since the last second when DST wasn't in effect was 01:59:59, it "makes sense" to treat the senseless 02:00:00 as if the DST switch happened.  In favor of the Linux approach, since 2am in fact doesn't exist on the local clock, it "makes sense" to imagine that the user simply forgot to set the clock forward, so 02:00:00 should be treated as not being in DST.  Neither is compelling.

If you care a lot ;-), on any platform you can _force_ the choice by forcing tm_isdst to a non-negative value.  For example, here on Windows:

    import time
    base = [2014, 3, 9, 2, 0, 0, 0, 0, None]
    for isdst in -1, 0, 1:
        base[-1] = isdst
        print("%2d" % isdst, time.mktime(time.struct_time(base)))

That prints:

-1 1394348400.0
 0 1394352000.0
 1 1394348400.0

Which confirms that Windows is treating the senseless time as if DST were already in effect - but can be forced to treat it as if DST weren't in effect by setting tm_isdst to 0.
History
Date User Action Args
2022-04-11 14:58:52adminsetgithub: 75827
2017-09-30 16:55:53tim.peterssetnosy: + tim.peters
messages: + msg303415
2017-09-30 15:27:30r.david.murraysetstatus: open -> closed
resolution: not a bug
stage: resolved
2017-09-30 06:11:56eryksunsetmessages: + msg303395
2017-09-30 04:48:36klianosetmessages: + msg303393
2017-09-30 03:50:34eryksunsetnosy: + eryksun
messages: + msg303390
2017-09-30 00:19:35klianocreate