<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Mark Costello</title>
 <link href="http://markcostello.net/atom.xml" rel="self"/>
 <link href="http://markcostello.net/"/>
 <updated>2012-12-29T10:22:13-08:00</updated>
 <id>http://markcostello.net/</id>
 <author>
   <name>Mark Costello</name>
   <email>mark@markcostello.net</email>
 </author>

 
 <entry>
   <title>Interesting Python Timezone Behaviour</title>
   <link href="http://markcostello.net/2012/06/21/Interesting-Python-Timezone-Behaviour/"/>
   <updated>2012-06-21T00:00:00-07:00</updated>
   <id>http://markcostello.net/2012/06/21/Interesting-Python-Timezone-Behaviour</id>
   <content type="html">&lt;p&gt;I had some interesting behaviour crop up in my code today. I was debugging a service I wrote for our application at work where users can schedule updates to be sent to their social media sites (Twitter, Facebook and LinkedIn).&lt;/p&gt;

&lt;p&gt;Quick note for anyone working with dates, times and timezones: you should always use UTC (&lt;a href='http://en.wikipedia.org/wiki/Coordinated_Universal_Time/'&gt;http://en.wikipedia.org/wiki/Coordinated_Universal_Time/&lt;/a&gt;) as the standard timezone for all time-sensitive operations.&lt;/p&gt;

&lt;p&gt;So, here is what I ran into: I was converting from the user&amp;#8217;s timezone to UTC. To do this, I use the very impressive pytz (&lt;a href='http://pytz.sourceforge.net/'&gt;http://pytz.sourceforge.net/&lt;/a&gt;) library and then using some native python datetime functionality to perform the conversion.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s the interesting part, when I did this:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;timestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;datetime&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strptime&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;input_timestamp&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;TIME_FORMAT&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;usertimestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;timestamp&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;tzinfo&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;usertz&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;utcusertimestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;usertimestamp&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;astimezone&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;utc&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;utcusertimestamp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;I kept getting times that were off by one hour - i.e. they weren&amp;#8217;t taking into account Daylight Saving Time.&lt;/p&gt;

&lt;p&gt;It turns out that the following line was the problem:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;usertimestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;timestamp&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;replace&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;tzinfo&lt;/span&gt;&lt;span class='o'&gt;=&lt;/span&gt;&lt;span class='n'&gt;usertz&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Doing a replace of the timezone information on in the datetime object doesn&amp;#8217;t actually take into account Daylight Saving Time (&lt;a href='http://en.wikipedia.org/wiki/Daylight_saving_time/'&gt;http://en.wikipedia.org/wiki/Daylight_saving_time/&lt;/a&gt;). It turns out that I needed to do the conversion this way instead:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;usertimestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;usertz&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;localize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;timestamp&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Here&amp;#8217;s the final conversion code I used:&lt;/p&gt;
&lt;div class='highlight'&gt;&lt;pre&gt;&lt;code class='python'&gt;&lt;span class='n'&gt;timestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;datetime&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;strptime&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;input_timestamp&lt;/span&gt;&lt;span class='p'&gt;,&lt;/span&gt; &lt;span class='n'&gt;TIME_FORMAT&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;usertimestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;usertz&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;localize&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;timestamp&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='n'&gt;utcusertimestamp&lt;/span&gt; &lt;span class='o'&gt;=&lt;/span&gt; &lt;span class='n'&gt;usertimestamp&lt;/span&gt;&lt;span class='o'&gt;.&lt;/span&gt;&lt;span class='n'&gt;astimezone&lt;/span&gt;&lt;span class='p'&gt;(&lt;/span&gt;&lt;span class='n'&gt;utc&lt;/span&gt;&lt;span class='p'&gt;)&lt;/span&gt;
&lt;span class='k'&gt;return&lt;/span&gt; &lt;span class='n'&gt;utcusertimestamp&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;Let&amp;#8217;s hope this bug doesn&amp;#8217;t rear it&amp;#8217;s head again when the clocks go back later this year!&lt;/p&gt;</content>
 </entry>
 
 
</feed>