19

I have a database that stores datetime as UTC. I need to look up info from a particular time, but the date and time are given in a local time, let's say 'Europe/Copenhagen'. I'm given these as:

year = 2012; month = 12; day = 2; hour = 13; min = 1;

So, I need to convert these to UTC so I can look them up in the database. I want to do this using pytz. I am looking at localize:

 local_tz = timezone('Europe/Copenhagen')
 t = local_tz.localize(datetime.datetime(year, month, day, hour, min))

But I'm confused about localize(). Is this assuming that year, etc, are given to me in local time? Or, is it assuming that they they are given in UTC and now it has converted them to local time?

print t gives me:

2012-12-02 13:01:00+01:00

So it seems that it assumed that the original year, etc was in utc; hours is now 13+1 instead of 13. So what should I do instead? I have read the pytz documentation and this does not make it clearer to me. It mentions a lot that things are tricky so I'm not sure whether pytz is actually solving these issues. And, I don't always know if the examples are showing me things that work or things that won't work.

I tried normalize:

print local_tz.normalize(t)

That gives me the same result as print t.

EDIT: With the numbers given above for year etc. it should match up with information in the database for 2012-12-2 12:01. (since Copenhagen is utc+1 on that date)

Amrith Krishna
  • 2,768
  • 3
  • 31
  • 65
user984003
  • 28,050
  • 64
  • 189
  • 285

2 Answers2

29

localize() attaches the timezone to a naive datetime.datetime instance in the local timezone.

If you have datetime values in a local timezone, localize to that timezone, then use .astimezone() to cast the value to UTC:

>>> localdt = local_tz.localize(datetime.datetime(year, month, day, hour, min))
>>> localdt.astimezone(pytz.UTC)
datetime.datetime(2012, 12, 2, 12, 1, tzinfo=<UTC>)

Note that you don't need to do this, datetime objects with a timezone can be compared; they'll both be normalized to UTC for the test:

>>> localdt.astimezone(pytz.UTC) == localdt
True
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • That gives the hour as 14:01:00+01:00. The correct local time is 13 and the utc time is 12. – user984003 Nov 12 '12 at 15:08
  • @user984003: Ah, sorry, misread the first sentence. `.astimezone()` is still the way to go, just the other way around. – Martijn Pieters Nov 12 '12 at 15:12
  • Yes, that second way works, thanks. Could you just have that in your answer, otherwise I think it's a bit confusing ;) I see that I was confused about the printed date. "+01:00" tells me that it is one hour ahead of utc, not that I should add one hour to the time. – user984003 Nov 12 '12 at 15:19
  • @user984003: Updated, with a note about comparisons of timezone-aware instances of `datetime.datetime`. – Martijn Pieters Nov 12 '12 at 15:26
  • thanks. Yes, now it's the first answer that answers my question. – user984003 Nov 12 '12 at 15:40
0

If you know the incoming time representation is in the Europe/Copenhagen timezone, you can create it as timezone-aware to begin with:

local_tz = timezone('Europe/Copenhagen')
t = local_tz.localize(datetime.datetime(year, month, day, hour, min))

You can then "convert" this to UTC with:

t_utc = t.astimezone(pytz.UTC)

but this might not be necessary, depending on how sane your database drivers are. t and t_utc represent the same point-in-time and well-behaving code should treat them interchangeably. The (year, month, day, hour, minute, second, …) tuple is merely a human-readable representation of this point-in-time in a specific time zone and calendar system.

millimoose
  • 39,073
  • 9
  • 82
  • 134