2

The following code works well on Windows, the results in Linux[Ubuntu] is weird. My python version is 2.7

from datetime import datetime
from datetime import timedelta
import time

def time_diff(date_str_1, date_str_2):
    time_stamp_1 = time.mktime(time.strptime(date_str_1, '%Y-%m-%d-%H-%M-%S'))
    time_stamp_2 = time.mktime(time.strptime(date_str_2, '%Y-%m-%d-%H-%M-%S'))
    print '==='
    print date_str_1,date_str_2
    print time_stamp_1,time_stamp_2
    delta1 = time_stamp_2 - time_stamp_1
    return delta1

print time_diff('2015-11-01-01-00-00', '2015-11-01-01-30-00')
print time_diff('2015-11-01-01-00-00', '2015-11-01-02-00-00')
print time_diff('2015-11-01-01-00-00', '2015-11-01-02-30-00')
print time_diff('2015-11-01-01-00-00', '2015-11-01-03-00-00')

results in Windows

===
2015-11-01-01-00-00 2015-11-01-01-30-00
1446310800.0 1446312600.0
1800.0
===
2015-11-01-01-00-00 2015-11-01-02-00-00
1446310800.0 1446314400.0
3600.0
===
2015-11-01-01-00-00 2015-11-01-02-30-00
1446310800.0 1446316200.0
5400.0
===
2015-11-01-01-00-00 2015-11-01-03-00-00
1446310800.0 1446318000.0
7200.0

results in Linux

===
2015-11-01-01-00-00 2015-11-01-01-30-00
1446364800.0 1446366600.0
1800.0
===
2015-11-01-01-00-00 2015-11-01-02-00-00
1446364800.0 1446372000.0
7200.0
===
2015-11-01-01-00-00 2015-11-01-02-30-00
1446368400.0 1446373800.0
5400.0
===
2015-11-01-01-00-00 2015-11-01-03-00-00
1446368400.0 1446375600.0
7200.0

on Linux '2015-11-01-01-00-00' sometimes is 1446364800.0 and then it becomes 1446368400.0

What's the reason? is it a bug?

4 Answers4

0

I guess the glitch is in your linux system. I ran on a macOS that is BSD unix-like, and also on pythonanywhere, a linux server, an both got the exact same outcome as your Windows.

===
2015-11-01-01-00-00 2015-11-01-01-30-00
1446339600.0 1446341400.0
1800.0
===
2015-11-01-01-00-00 2015-11-01-02-00-00
1446339600.0 1446343200.0
3600.0
===
2015-11-01-01-00-00 2015-11-01-02-30-00
1446339600.0 1446345000.0
5400.0
===
2015-11-01-01-00-00 2015-11-01-03-00-00
1446339600.0 1446346800.0
7200.0

I suggest you check all locale configs for that change things like datetime. You can check that by typing locale in bash. Both my envs here had LC_CTYPE="UTF-8" on them. Others were either "C"or POSIX.

LANG=
LC_COLLATE="C"
LC_CTYPE="UTF-8"
LC_MESSAGES="C"
LC_MONETARY="C"
LC_NUMERIC="C"
LC_TIME="C"
LC_ALL=
JeanPaulDepraz
  • 625
  • 7
  • 12
  • The result depends on the local timezone (i.e., if you and OP run the code on computers from different timezones then the results may be different). `mktime()` may use the tz database on Linux (utc offset for the local timezone may be different at different times). – jfs May 20 '16 at 04:16
0

The time.mktime() returns the seconds adding OS timezone since 1970.01.01 00:00:00 . If the value is changed, maybe your OS timezone was changed.

deepin@deepin-pc:~/test$ python testtime.py 
===
2015-11-01-01-00-00 2015-11-01-01-30-00
1446310800.0 1446312600.0
1800.0
===
2015-11-01-01-00-00 2015-11-01-02-00-00
1446310800.0 1446314400.0
3600.0
===
2015-11-01-01-00-00 2015-11-01-02-30-00
1446310800.0 1446316200.0
5400.0
===
2015-11-01-01-00-00 2015-11-01-03-00-00
1446310800.0 1446318000.0
7200.0
deepin@deepin-pc:~/test$ date -R
Fri, 20 May 2016 11:26:43 +0800
deepin@deepin-pc:~/test$ python testtime.py 
===
2015-11-01-01-00-00 2015-11-01-01-30-00
1446373800.0 1446375600.0
1800.0
===
2015-11-01-01-00-00 2015-11-01-02-00-00
1446373800.0 1446377400.0
3600.0
===
2015-11-01-01-00-00 2015-11-01-02-30-00
1446373800.0 1446379200.0
5400.0
===
2015-11-01-01-00-00 2015-11-01-03-00-00
1446373800.0 1446381000.0
7200.0
deepin@deepin-pc:~/test$ date -R
Thu, 19 May 2016 17:56:59 -0930
deepin@deepin-pc:~/test$
Aaron
  • 29
  • 2
0

Both 1446364800.0 and 1446368400.0 are valid timestamps for the '2015-11-01 01:00:00' input (in America/Los_Angeles timezone):

>>> from datetime import datetime
>>> import pytz     # $ pip install pytz
>>> import tzlocal  # $ pip install tzlocal
>>> tz = tzlocal.get_localzone()
>>> epoch = datetime(1970, 1, 1, tzinfo=pytz.utc)
>>> (tz.localize(datetime(2015, 11, 1, 1), is_dst=True) - epoch).total_seconds()
1446364800.0
>>> (tz.localize(datetime(2015, 11, 1, 1), is_dst=False) - epoch).total_seconds()
1446368400.0

time.mktime() is a thin wrapper around the corresponding C mktime() function. mktime() may have access to the tz database on Linux and therefore it tries to find the correct utc offset there. If the time is ambiguous as in your case then the result may depend on the history of mktime() calls:

>>> import time
>>> time.mktime((2015, 11, 1, 1, 0, 0, -1, -1, -1)) # ambiguous time in Los Angeles
1446364800.0                                        # random value
>>> time.mktime((2015, 11, 1, 3, 0, 0, -1, -1, -1)) # unambiguous
1446375600.0                                        # EST time
>>> time.mktime((2015, 11, 1, 1, 0, 0, -1, -1, -1)) # EST utc offset is chosen
1446368400.0
>>> time.mktime((2015, 11, 1, 0, 0, 0, -1, -1, -1)) # unambiguous
1446361200.0                                        # EDT time
>>> time.mktime((2015, 11, 1, 1, 0, 0, -1, -1, -1)) # EDT utc offset is chosen
1446364800.0

In this case, mktime() defaults to the last utc offset (on my machine) if the input is ambiguous.

Windows doesn't provide the access to the tz database to python process and therefore mktime() may use the current (perhaps incorrect for past dates) utc offset there.

See python converting string in localtime to UTC epoch timestamp.

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
0

Looks like DST issues ...

Most of the dates have just roundoff error, except ...

2015-11-01-01-00-00 2015-11-01-02-00-00

Where windows gives 3600.0 vs linux 7200.0. That is exactly one hour's difference.

Those two dates you picked just happen to be the transition hour from daylight savings time back to standard time for the year 2015.

So, all other factors being equal (e.g. timezones are set correctly) maybe that's a factor as to how this is handled. Whether the date is considered before or after DST conversion.

That is, does mktime think you have a date expressed in DST or not. This may vary according to the libc mktime implementation.

I needed a [better] mktime implementation for my perl code a while back, so I looked at the mktime source in glibc vs (e.g. netBSD) and they are definitely different as to how they do things.

I looked at a number of implementations on *BSD, android, minux, and, IIRC, they are all similar/identical to the netBSD version. Dunno, it's been a while since I did this. However, the glibc version looks like it was written from scratch and not derived from any of the others.

Obviously, I don't know about the Window's version, but if they wanted to borrow some code, they'd probably borrow the BSD-style implementation, partly for licensing, but also because they probably borrowed the code before linux came on the scene. Again, dunno.

The DST transitions for 2015 were:

03/08/2015 02:00:00 [Sun] --> 03/08/2015 03:00:00 [Sun] (spring forward)
11/01/2015 01:00:00 [Sun] <-- 11/01/2015 02:00:00 [Sun] (fall back)
Craig Estey
  • 30,627
  • 4
  • 24
  • 48