In December 2016, a user reported an interesting bug to the dateutil tracker. The bug is summarized as follows :

from datetime import datetime from dateutil import tz LON = tz . gettz ( 'Europe/London' ) # Construct a datetime x = datetime ( 2007 , 3 , 25 , 1 , 0 , tzinfo = LON ) ts = x . timestamp () # Get a timestamp representing the same datetime # Get the same datetime from the timestamp y = datetime . fromtimestamp ( ts , LON ) # Get the same datetime from the timestamp with a fresh instance of LON z = datetime . fromtimestamp ( ts , tz . gettz ( 'Europe/London' )) print ( x == y ) # False print ( x == z ) # True print ( y == z ) # True

To summarize: x , y and z should all represent the same datetime – they all have the same time zone, and y and z are the result of converting x into a timestamp and then back into a datetime , but for some reason x != y , and, even more curiously, x == z , even though the only difference between y and z is that z uses a different tzinfo object (representing the same zone). Even stranger, the equality relationship between the three is non-transitive, because x != y even though x == z and y == z . What the hell is going on? There are two key facts you need in order to understand what's happening here.

Imaginary times The first piece of information you need to know is that the datetime constructor will not prevent you from creating a datetime that does not exist, which is what here: x = datetime ( 2007 , 3 , 25 , 1 , 0 , tzinfo = LON ) print ( tz . datetime_exists ( x )) # False Turns out that Daylight Saving Time started at 01:00 on 25 March 2007 in London, so times from 01:00:00 to 01:59:59 were skipped over that day. Imaginary datetimes like this violate an assumption built in to the datetime.fromtimestamp(x.timestamp()) round trip, which is that all datetimes should be able to survive a round trip to and from UTC, or, in code: dt . astimezone ( tz . tzutc ()) . astimezone ( dt . tzinfo ) == dt This is true for all real datetimes, but it cannot be true for an imaginary datetime because astimezone is guaranteed to produce a real datetime - since this datetime never existed, there's no time in UTC to map to it. Any trip from an erroneously constructed imaginary datetime to UTC is necessarily one-way. Looking at the actual datetimes produced, you can thus see why x == y is not obviously True : print ( x ) # 2007-03-25 01:00:00+01:00 print ( y ) # 2007-03-25 00:00:00+00:00 But now the question is, if x == y is False , why is x == z True ?