Python time to age, part 2: timezones
New in version 2.6.
For a naive object, the %z and %Z
format codes are replaced by empty
strings.
It looks like this is implemented only in >= 2.6, and I think you have to manually parse it.
I can't see another solution than to remove the time zone data:
from datetime import timedelta,datetime
try:
offset = int("Tue, 22 Jul 2008 08:17:41 +0300"[-5:])
except:
print "Error"
delta = timedelta(hours = offset / 100)
fmt = "%a, %d %b %Y %H:%M:%S"
time = datetime.strptime("Tue, 22 Jul 2008 08:17:41 +0200"[:-6], fmt)
time -= delta
How to preserve timezone when parsing date/time strings with strptime()?
The datetime
module documentation says:
Return a datetime corresponding to date_string, parsed according to format. This is equivalent to
datetime(*(time.strptime(date_string, format)[0:6]))
.
See that [0:6]
? That gets you (year, month, day, hour, minute, second)
. Nothing else. No mention of timezones.
Interestingly, [Win XP SP2, Python 2.6, 2.7] passing your example to time.strptime
doesn't work but if you strip off the " %Z" and the " EST" it does work. Also using "UTC" or "GMT" instead of "EST" works. "PST" and "MEZ" don't work. Puzzling.
It's worth noting this has been updated as of version 3.2 and the same documentation now also states the following:
When the %z directive is provided to the strptime() method, an aware datetime object will be produced. The tzinfo of the result will be set to a timezone instance.
Note that this doesn't work with %Z, so the case is important. See the following example:
In [1]: from datetime import datetime
In [2]: start_time = datetime.strptime('2018-04-18-17-04-30-AEST','%Y-%m-%d-%H-%M-%S-%Z')
In [3]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: None
In [4]: start_time = datetime.strptime('2018-04-18-17-04-30-+1000','%Y-%m-%d-%H-%M-%S-%z')
In [5]: print("TZ NAME: {tz}".format(tz=start_time.tzname()))
TZ NAME: UTC+10:00
Python time to age
You need to use the module datetime
and the object datetime.timedelta
from datetime import datetime
t1 = datetime.strptime("Mon, 17 Nov 2008 01:45:32 +0200","%a, %d %b %Y %H:%M:%S +0200")
t2 = datetime.now()
tdelta = t2 - t1 # actually a datetime.timedelta object
print tdelta.days
How do you convert a datetime/timestamp from one timezone to another timezone?
If you know your origin timezone and the new timezone that you want to convert it to, it turns out to be very straightforward:
Make two
pytz.timezone
objects, one for the current timezone and one for the new timezone e.g.pytz.timezone("US/Pacific")
. You can find a list of all official timezones inpytz
library:import pytz; pytz.all_timezones
Localize the datetime/timestamp of interest to the current timezone e.g.
current_timezone = pytz.timezone("US/Eastern")
localized_timestamp = current_timezone.localize(timestamp)
- Convert to new timezone using
.astimezone()
on the newly localized datetime/timestamp from step 2 with the desired timezone's pytz object as input e.g.localized_timestamp.astimezone(new_timezone)
.
Done!
As a full example:
import datetime
import pytz
# a timestamp I'd like to convert
my_timestamp = datetime.datetime.now()
# create both timezone objects
old_timezone = pytz.timezone("US/Eastern")
new_timezone = pytz.timezone("US/Pacific")
# two-step process
localized_timestamp = old_timezone.localize(my_timestamp)
new_timezone_timestamp = localized_timestamp.astimezone(new_timezone)
# or alternatively, as an one-liner
new_timezone_timestamp = old_timezone.localize(my_timestamp).astimezone(new_timezone)
Bonus: but if all you need is the current time in a specific timezone, you can conveniently pass that timezone directly into datetime.now() to get the current times directly:
datetime.datetime.now(new_timezone)
When it comes to needing timezones conversions generally, I would strongly advise that one should store all timestamps in your database in UTC, which has no daylight savings time (DST) transition. And as a good practice, one should always choose to enable time zone support (even if your users are all in a single time zone!). This will help you avoid the DST transition problem that plagues so much software today.
Beyond DST, time in software can be generally quite tricky. To get a sense of just how difficult it is to deal with time in software in general, here is a potentially enlightening resource: http://yourcalendricalfallacyis.com
Even a seemingly simple operation as converting a datetime/timestamp into a date can become non-obvious. As this helpful documentation points out:
A datetime represents a point in time. It’s absolute: it doesn’t depend on anything. On the contrary, a date is a calendaring concept. It’s a period of time whose bounds depend on the time zone in which the date is considered. As you can see, these two concepts are fundamentally different.
Understanding this difference is a key step towards avoiding time-based bugs. Good luck.
How to parse dates with -0400 timezone string in Python?
You can use the parse function from dateutil:
>>> from dateutil.parser import parse
>>> d = parse('2009/05/13 19:19:30 -0400')
>>> d
datetime.datetime(2009, 5, 13, 19, 19, 30, tzinfo=tzoffset(None, -14400))
This way you obtain a datetime object you can then use.
As answered, dateutil2.0 is written for Python 3.0 and does not work with Python 2.x. For Python 2.x dateutil1.5 needs to be used.
How to convert a UTC datetime to a local datetime using only standard library?
I think I figured it out: computes number of seconds since epoch, then converts to a local timzeone using time.localtime, and then converts the time struct back into a datetime...
EPOCH_DATETIME = datetime.datetime(1970,1,1)
SECONDS_PER_DAY = 24*60*60
def utc_to_local_datetime( utc_datetime ):
delta = utc_datetime - EPOCH_DATETIME
utc_epoch = SECONDS_PER_DAY * delta.days + delta.seconds
time_struct = time.localtime( utc_epoch )
dt_args = time_struct[:6] + (delta.microseconds,)
return datetime.datetime( *dt_args )
It applies the summer/winter DST correctly:
>>> utc_to_local_datetime( datetime.datetime(2010, 6, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 6, 6, 19, 29, 7, 730000)
>>> utc_to_local_datetime( datetime.datetime(2010, 12, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 12, 6, 18, 29, 7, 730000)
How to convert time zone of datetime column in pandas, then remove time zone?
Just add a last step of .tz_localize(None)
:
import pandas as pd
d = pd.Series(['2018-11-15 19:57:55', '2018-11-15 19:59:46'])
d = pd.to_datetime(d)
d
0 2018-11-15 19:57:55
1 2018-11-15 19:59:46
dtype: datetime64[ns]
d_pacific_tz_aware = d.dt.tz_localize("GMT").dt.tz_convert('America/Los_Angeles')
d_pacific_tz_aware
0 2018-11-15 11:57:55-08:00
1 2018-11-15 11:59:46-08:00
dtype: datetime64[ns, America/Los_Angeles]
d_pacific_tz_naive = d.dt.tz_localize("GMT").dt.tz_convert('America/Los_Angeles').dt.tz_localize(None)
d_pacific_tz_naive
0 2018-11-15 11:57:55
1 2018-11-15 11:59:46
dtype: datetime64[ns]
Parsing date with timezone from an email?
email.utils
has a parsedate()
function for the RFC 2822 format, which as far as I know is not deprecated.
>>> import email.utils
>>> import time
>>> import datetime
>>> email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0100')
(2009, 11, 16, 13, 32, 2, 0, 1, -1)
>>> time.mktime((2009, 11, 16, 13, 32, 2, 0, 1, -1))
1258378322.0
>>> datetime.datetime.fromtimestamp(1258378322.0)
datetime.datetime(2009, 11, 16, 13, 32, 2)
Please note, however, that the parsedate
method does not take into account the time zone and time.mktime
always expects a local time tuple.
>>> (time.mktime(email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0900')) ==
... time.mktime(email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0100'))
True
So you'll still need to parse out the time zone and take into account the local time difference, too:
>>> REMOTE_TIME_ZONE_OFFSET = +9 * 60 * 60
>>> (time.mktime(email.utils.parsedate('Mon, 16 Nov 2009 13:32:02 +0900')) +
... time.timezone - REMOTE_TIME_ZONE_OFFSET)
1258410122.0
Converting string with UTC offset to a datetime object
It looks as if strptime doesn't always support %z
. Python appears to just call the C function, and strptime doesn't support %z
on your platform.
Note: from Python 3.2 onwards it will always work.
Related Topics
Segmenting License Plate Characters
How to Cycle Through Line Styles in Matplotlib
How to Set a Default Value for a Wtforms Selectfield
Securely Erasing Password in Memory (Python)
Dynamically Adding @Property in Python
Destroywindow Does Not Close Window on MAC Using Python and Opencv
How to Use Python Numpy.Savetxt to Write Strings and Float Number to an Ascii File
How to Flatten a List of Lists/Nested Lists
How to Use a Multiprocessing Queue in a Function Called by Pool.Imap
Python: Excluding Modules Pyinstaller
Will Ordereddict Become Redundant in Python 3.7
About the Pil Error -- Ioerror: Decoder Zip Not Available
Print Combining Strings and Numbers
Read Unicode Characters from Command-Line Arguments in Python 2.X on Windows
How to Get the Executable's Current Directory in Py2Exe
Positional Argument Follows Keyword Argument
I Have Python on My Ubuntu System, But Gcc Can't Find Python.H