How do I get the UTC time of "midnight" for a given timezone?
Solution 1
@hop's answer is wrong on the day of transition from Daylight Saving Time (DST) e.g., Apr 1, 2012. To fix it tz.localize()
could be used:
tz = pytz.timezone("Australia/Melbourne")
today = datetime.now(tz).date()
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
utc_dt = midnight.astimezone(pytz.utc)
The same with comments:
#!/usr/bin/env python
from datetime import datetime, time
import pytz # pip instal pytz
tz = pytz.timezone("Australia/Melbourne") # choose timezone
# 1. get correct date for the midnight using given timezone.
today = datetime.now(tz).date()
# 2. get midnight in the correct timezone (taking into account DST)
#NOTE: tzinfo=None and tz.localize()
# assert that there is no dst transition at midnight (`is_dst=None`)
midnight = tz.localize(datetime.combine(today, time(0, 0)), is_dst=None)
# 3. convert to UTC (no need to call `utc.normalize()` due to UTC has no
# DST transitions)
fmt = '%Y-%m-%d %H:%M:%S %Z%z'
print midnight.astimezone(pytz.utc).strftime(fmt)
Solution 2
This is more straightforward with dateutil.tz than pytz:
>>>import datetime
>>>import dateutil.tz
>>>midnight=(datetime.datetime
.now(dateutil.tz.gettz('Australia/Melbourne'))
.replace(hour=0, minute=0, second=0, microsecond=0)
.astimezone(dateutil.tz.tzutc()))
>>>print(midnight)
2019-04-26 14:00:00+00:00
The tzinfo documentation recommends dateutil.tz since Python 3.6. The tzinfo objects from dateutil.tz have no problems with anomalies like DST without requiring the localize functionality of pytz. Using the example from user3850:
>>> now = (datetime.datetime(2012, 4, 1, 5,
... tzinfo = dateutil.tz.gettz('Australia/Melbourne')))
>>> print(now.replace(hour = 0).astimezone(dateutil.tz.tzutc()))
2012-03-31 13:00:00+00:00
Tom
I'm mostly a Python & JavaScript developer at the moment but I've done a lot of things...
Updated on March 28, 2020Comments
-
Tom about 4 years
The best I can come up with for now is this monstrosity:
>>> datetime.utcnow() \ ... .replace(tzinfo=pytz.UTC) \ ... .astimezone(pytz.timezone("Australia/Melbourne")) \ ... .replace(hour=0,minute=0,second=0,microsecond=0) \ ... .astimezone(pytz.UTC) \ ... .replace(tzinfo=None) datetime.datetime(2008, 12, 16, 13, 0)
I.e., in English, get the current time (in UTC), convert it to some other timezone, set the time to midnight, then convert back to UTC.
I'm not just using now() or localtime() as that would use the server's timezone, not the user's timezone.
I can't help feeling I'm missing something, any ideas?
-
Tom over 15 yearsAside from not wanting to use the TZ variable to control this, that doesn't actually tell me how to find midnight, just the current time.
-
Tom over 15 yearsI think you're on the right track, but how do you know what date to start with? i.e. a few hours ago, it was the 17th here in Melbourne, while it was still the 16th in UTC.
-
Admin over 15 yearsadding/substracting tz differences by hand might have issues around the switch from and to DST
-
Admin almost 12 yearsI'm a bit confused. The DST switch happened at 3 a.m., so midnight on that day should still be at 14:00 UTC, not 13:00. no?
-
jfs almost 12 years@hop: convert 2012 Mar 31 13:00 UTC to Melbourne timezone and see for yourself (it is still +11 timezone (DST), not +10 (standard))
-
mik about 6 years
time()
is the same astime(0, 0)
, but shorter