title: Datetime Timezone conversion using pytz
body: <p>This is just another post on <code>pytz</code>. </p>
  
  <p>There are two functions to convert datetime objects between two timezones. The second functions works for all cases. The first function fails in two cases, (3) and (4). Similar <a href="https://stackoverflow.com/questions/1379740/pytz-localize-vs-datetime-replace">SO post</a> did not have an issue like this. Any explanation based on the difference between <code>localize(datetime.datetime)</code> and <code>replace(tzinfo)</code> would be a great help.</p>
  
  <pre><code>&gt;&gt;&gt; from dateutil.parser import parse
  &gt;&gt;&gt; import pytz
  </code></pre>
  
  <h1>First function (buggy)</h1>
  
  <p>The function below uses <code>datetime.datetime.replace(tzinfo)</code>.</p>
  
  <pre><code>def buggy_timezone_converter(input_dt, current_tz='UTC', target_tz='US/Eastern'):
      '''input_dt is a datetime.datetime object'''
      current_tz = pytz.timezone(current_tz)
      target_tz = pytz.timezone(target_tz)
      target_dt = input_dt.replace(tzinfo=current_tz).astimezone(target_tz)
      return target_tz.normalize(target_dt)
  </code></pre>
  
  <p>Notice the four datetime conversion now. </p>
  
  <p>(1) from UTC to EST -- OK</p>
  
  <pre><code>&gt;&gt;&gt; buggy_timezone_converter(parse('2013-02-26T04:00:00'))
  Out[608]: datetime.datetime(2013, 2, 25, 23, 0, tzinfo=&lt;DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD&gt;)
  </code></pre>
  
  <p>(2) from UTC to EDT -- OK</p>
  
  <pre><code>&gt;&gt;&gt; buggy_timezone_converter(parse('2013-05-26T04:00:00'))
  Out[609]: datetime.datetime(2013, 5, 26, 0, 0, tzinfo=&lt;DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST&gt;)
  </code></pre>
  
  <p>(3) from EST to UTC -- Not OK. Time offset is 4 hours 56 minutes. It is supposed to be 5 hours</p>
  
  <pre><code>&gt;&gt;&gt; buggy_timezone_converter(parse('2013-02-26T04:00:00'), target_tz='UTC', current_tz='US/Eastern')
  Out[610]: datetime.datetime(2013, 2, 26, 8, 56, tzinfo=&lt;UTC&gt;)
  </code></pre>
  
  <p>(4) from EDT to UTC -- Not OK. Time offset is 4 hours 56 minutes. It is supposed to be 4 hours. Daylight saving is not considered.</p>
  
  <pre><code>&gt;&gt;&gt; buggy_timezone_converter(parse('2013-05-26T04:00:00'), current_tz='US/Eastern', target_tz='UTC')
  Out[611]: datetime.datetime(2013, 5, 26, 8, 56, tzinfo=&lt;UTC&gt;)
  </code></pre>
  
  <h1>Second function (Works perfectly)</h1>
  
  <p>The function below uses <code>pytz.timezone.localize(datetime.datetime)</code>. It works perfectly</p>
  
  <pre><code>def good_timezone_converter(input_dt, current_tz='UTC', target_tz='US/Eastern'):
      current_tz = pytz.timezone(current_tz)
      target_tz = pytz.timezone(target_tz)
      target_dt = current_tz.localize(input_dt).astimezone(target_tz)
      return target_tz.normalize(target_dt) 
  </code></pre>
  
  <p>(1) from UTC to EST -- OK</p>
  
  <pre><code>&gt;&gt;&gt; good_timezone_converter(parse('2013-02-26T04:00:00'))
  Out[618]: datetime.datetime(2013, 2, 25, 23, 0, tzinfo=&lt;DstTzInfo 'US/Eastern' EST-1 day, 19:00:00 STD&gt;)
  </code></pre>
  
  <p>(2) from UTC to EDT -- OK</p>
  
  <pre><code>&gt;&gt;&gt; good_timezone_converter(parse('2013-05-26T04:00:00'))
  Out[619]: datetime.datetime(2013, 5, 26, 0, 0, tzinfo=&lt;DstTzInfo 'US/Eastern' EDT-1 day, 20:00:00 DST&gt;)
  </code></pre>
  
  <p>(3) from EST to UTC -- OK.</p>
  
  <pre><code>&gt;&gt;&gt; good_timezone_converter(parse('2013-02-26T04:00:00'), current_tz='US/Eastern', target_tz='UTC')
  Out[621]: datetime.datetime(2013, 2, 26, 9, 0, tzinfo=&lt;UTC&gt;)
  </code></pre>
  
  <p>(4) from EDT to UTC -- OK.</p>
  
  <pre><code>&gt;&gt;&gt; good_timezone_converter(parse('2013-05-26T04:00:00'), current_tz='US/Eastern', target_tz='UTC')
  Out[620]: datetime.datetime(2013, 5, 26, 8, 0, tzinfo=&lt;UTC&gt;)
  </code></pre>