I am doing Python date comparizon:
Assume I have a date like this: 'Fri Aug 17 12:34:00 2012 +0000'
I am parsing it in the following manner:
dt=datetime.strptime('Fri Aug 17 12:34:00 2012 +0000', '%a %b %d %H:%M:%S %Y +0000')
I could not find on the documentation page how to handle the remaining +0000?
I want to have a more generic solution then hardcoded value.
Perhaps this is quite easy, any hint?
The default datetime module does not handle timezones very well; beyond your current machine timezone and UTC, they are basically not supported.
You'll have to use an external library for that or handle the timezone offset manually.
External library options:
Use dateutil.parser can handle just about any date and or time format you care to throw at it:
from dateutil import parser
dt = parser.parse(s)
The iso8601 library handles only ISO 8601 formats, which include timezone offsets of the same form:
import iso8601
datetimetext, tz = s.rsplit(None, 1) # only grab the timezone portion.
timezone = iso8601.iso8601.parse_timezone('{}:{}'.format(tz[:3], tz[3:]))
dt = datetime.strptime(datetimetext, '%a %b %d %H:%M:%S %Y').replace(tzinfo=timezone)
Demonstration of each approach:
>>> import datetime
>>> s = 'Fri Aug 17 12:34:00 2012 +0000'
>>> import iso8601
>>> timezone = iso8601.iso8601.parse_timezone('{}:{}'.format(tz[:3], tz[3:]))
>>> datetime.datetime.strptime(datetimetext, '%a %b %d %H:%M:%S %Y').replace(tzinfo=timezone)
datetime.datetime(2012, 8, 17, 12, 34, tzinfo=<FixedOffset '+00:00'>)
>>> from dateutil import parser
>>> parser.parse(s)
datetime.datetime(2012, 8, 17, 12, 34, tzinfo=tzutc())
You might want also give Delorean a look. Which is a wrapper around both pytz and dateutil it provides timezone manipulation as well as easy datetime time zone shift.
Here is how I would solve your question with Delorean.
>>> from delorean import parse
>>> parse("2011/01/01 00:00:00 -0700")
Delorean(datetime=2011-01-01 07:00:00+00:00, timezone=UTC)
From there you can return the datetime by simply return the .datetime attribute. If you wan to do some time shifts simply use the Delorean object and do .shift("UTC") etc.
Use the dateutil.parser:
>>> import dateutil.parser
>>> dateutil.parser.parse('Fri Aug 17 12:34:00 2012 +0000')
>>> datetime.datetime(2012, 8, 17, 12, 34, tzinfo=tzutc())
Related
I have many datetime.datetime object like 2021-06-25 15:00:08+00:00 where the timezone is different for different data.Eg.another data is 2021-06-24 06:33:06-07:00 .I want to save all of them by converting into a local tmezone.How can I do that?
The datetime.datetime.astimezone() method will return a datetime object with the same UTC time but in the local timezone. For your example times:
>>> dt_1 = datettime.fromisoformat(2021-06-25 15:00:08+00:00)
>>> dt_1.astimezone()
datetime.datetime(2021, 6, 25, 11, 0, 8, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000), 'EDT'))
>>> dt_2 = datetime.fromisoformat(2021-06-24 06:33:06-07:00)
>>> dt_2.astimezone()
datetime.datetime(2021, 6, 24, 9, 33, 6, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000), 'EDT'))
Since datetime.datetime objects with tzinfo are timezone-aware, the information will be stored in the objects regardless. This is just a handy way to get the local time.
UPDATE, based on a follow-up question below:
astimezone() doesn't depend on the way the datetime object is created. For differently formatted date/time strings, datetime.strptime can be used to create a timezone-aware datetime objects. From the example given in that follow-up question:
>>> dt_3 = datetime.strptime('Sat, 26 Jun 2021 15:00:09 +0000 (UTC)',
'%a, %d %b %Y %H:%M:%S %z (%Z)')
>>> dt_3.astimezone()
datetime.datetime(2021, 6, 26, 11, 0, 9, tzinfo=datetime.timezone(datetime.timedelta(days=-1, seconds=72000), 'EDT'))
You could use pytz library
from datetime import datetime
import pytz
dt_input = datetime.fromisoformat('2021-06-24 06:33:06-07:00')
print(dt_input) # prints datetime in input timezone
local_tz = pytz.timezone('Asia/Kolkata') #provide your timezone here
dt_local = dt_input.astimezone(local_tz)
print(dt_local) #prints in your local timezone as provided above
You can refer to this SO question similar to your question:
How to convert a UTC datetime to a local datetime using only standard library?
EDIT:
Convert any string to datetime object:
You can use strptime('datestring', 'dateformat')
example from your comment:
#This will convert the string to datetime object
datetime.strptime('Sat, 26 Jun 2021 15:00:09 +0000 (UTC)','%a, %d %b %Y %H:%M:%S %z (%Z)')
Once it is converted to datetime object you can convert it to your local timezone as mentioned above
Here's what I'm trying to do:
>>> from email.utils import parsedate
>>> tup = parsedate("Fri, 22 Jan 2016 10:15:00 GMT")
>>> tup
(2016, 1, 22, 10, 15, 0, 0, 1, -1)
>>> import datetime
>>> import time
>>> timestamp = time.mktime(tup)
>>> timestamp
1453454100.0
>>> datetime.datetime.utcfromtimestamp(timestamp)
datetime.datetime(2016, 1, 22, 9, 15)
I'm using the email.utils.parsedate function to parse an RFC 2822 date to a struct_time. This looks correct, the hour part is 10. Then, I convert it to a timestamp using time.mktime, and then, I try to get a UTC datetime out of it using datetime.utcfromtimestamp, but for some odd reason, the hour in the datetime is 9. I don't really get why.
I'm in UTC+1, so there's probably a conversion to local time happening somewhere, but I have no clue where.
The problem is that mktime expects the tuple to be in local time. There's also calendar.gmtime, which expects it to be in UTC. I might actually just end up using dateutil as #Boaz recommends
I recommend just to use dateutil
https://pypi.python.org/pypi/python-dateutil
It converts it directly to a correct datetime object
from dateutil import parser
parser.parse("Fri, 22 Jan 2016 10:15:00 GMT")
From Time access and conversions:
time.mktime(t):
This is the inverse function of localtime(). Its argument is the struct_time or full 9-tuple (since the dst flag is needed; use -1 as the dst flag if it is unknown) which expresses the time in local time, not UTC.
For correct results you should use calendar.timegm():
>>> calendar.timegm(tup)
1453457700
You can also use datetime.
>>> from datetime import datetime as dt
>>> d = "Fri, 22 Jan 2016 10:15:00 GMT"
>>> dt.strptime(d, "%a, %d %b %Y %H:%M:%S %Z")
datetime.datetime(2016, 1, 22, 10, 15)
I have dates in the current string format: 'Tue Feb 19 00:09:28 +1100 2013'
I'm trying to figure out how many days have passed between the date in the string and the present date.
I've been able to convert the string into a date.
import time
day = time.strptime('Tue Feb 19 00:09:28 +1100 2013', '%a %b %d %H:%M:%S +1100 %Y')
Use the datetime module instead:
import datetime
day = datetime.datetime.strptime('Tue Feb 19 00:09:28 +1100 2013', '%a %b %d %H:%M:%S +1100 %Y')
delta = day - datetime.datetime.now()
print delta.days
Subtracting two datetime.datetime values returns a datetime.timedelta object, which has a days attribute.
Your strings do contain a timezone offset, and you hardcoded it to match; if the value varies you'll have to use a parser that can handle the offset. The python-dateutil package includes both an excellent parser and the timezone support to handle this:
>>> from dateutil import parser
>>> parser.parse('Tue Feb 19 00:09:28 +1100 2013')
datetime.datetime(2013, 2, 19, 0, 9, 28, tzinfo=tzoffset(None, 39600))
Note that because this result includes the timezone, you now need to use timezone-aware datetime objects when using date arithmetic:
>>> from dateutil import tz
>>> import datetime
>>> utcnow = datetime.datetime.now(tz.tzutc())
>>> then = parser.parse('Tue Feb 19 00:09:28 +1100 2013')
>>> utcnow - then
datetime.timedelta(31, 12087, 617740)
>>> (utcnow - then).days
31
I created a utcnow variable in the above example based of the UTC timezone before calculating how long ago the parsed date was.
I have a date time string that I don't know how to parse it in Python.
The string is like this:
Tue May 08 15:14:45 +0800 2012
I tried
datetime.strptime("Tue May 08 15:14:45 +0800 2012","%a %b %d %H:%M:%S %z %Y")
but Python raises
'z' is a bad directive in format '%a %b %d %H:%M:%S %z %Y'
According to Python doc:
%z UTC offset in the form +HHMM or -HHMM (empty string if the the object is naive).
What is the right format to parse this time string?
datetime.datetime.strptime has problems with timezone parsing. Have a look at the dateutil package:
>>> from dateutil import parser
>>> parser.parse("Tue May 08 15:14:45 +0800 2012")
datetime.datetime(2012, 5, 8, 15, 14, 45, tzinfo=tzoffset(None, 28800))
Your best bet is to have a look at strptime()
Something along the lines of
>>> from datetime import datetime
>>> date_str = 'Tue May 08 15:14:45 +0800 2012'
>>> date = datetime.strptime(date_str, '%a %B %d %H:%M:%S +0800 %Y')
>>> date
datetime.datetime(2012, 5, 8, 15, 14, 45)
Im not sure how to do the +0800 timezone unfortunately, maybe someone else can help out with that.
The formatting strings can be found at http://docs.python.org/library/time.html#time.strftime and are the same for formatting the string for printing.
Hope that helps
Mark
PS, Your best bet for timezones in installing pytz from pypi. ( http://pytz.sourceforge.net/ )
in fact I think pytz has a great datetime parsing method if i remember correctly. The standard lib is a little thin on the ground with timezone functionality.
Here's a stdlib solution that supports a variable utc offset in the input time string:
>>> from email.utils import parsedate_tz, mktime_tz
>>> from datetime import datetime, timedelta
>>> timestamp = mktime_tz(parsedate_tz('Tue May 08 15:14:45 +0800 2012'))
>>> utc_time = datetime(1970, 1, 1) + timedelta(seconds=timestamp)
>>> utc_time
datetime.datetime(2012, 5, 8, 7, 14, 45)
It has discussed many times in SO. In short, "%z" is not supported because platform not support it.
My solution is a new one, just skip the time zone.:
datetime.datetime.strptime(re.sub(r"[+-]([0-9])+", "", "Tue May 08 15:14:45 +0800 2012"),"%a %b %d %H:%M:%S %Y")
In [117]: datetime.datetime.strptime?
Type: builtin_function_or_method
Base Class: <type 'builtin_function_or_method'>
String Form: <built-in method strptime of type object at 0x9a2520>
Namespace: Interactive
Docstring:
string, format -> new datetime parsed from a string (like time.strptime()).
I'm having a bad time with date parsing and formatting today.
Points for somebody who can parse this date format into a datetime.date or datetime.datetime (I'm not too fussy but I'd prefer .date):
5th November 2010
Using dateutil:
In [2]: import dateutil.parser as dparser
In [3]: date = dparser.parse('5th November 2010')
In [4]: date
Out[4]: datetime.datetime(2010, 11, 5, 0, 0)
Unfortunately, strptime has no format characters for "skip an ordinal suffix" -- so, I'd do the skipping first, with a little RE, and then parse the resulting "clear" string. I.e.:
>>> import re
>>> import datetime
>>> ordn = re.compile(r'(?<=\d)(st|nd|rd|th)\b')
>>> def parse(s):
... cleans = ordn.sub('', s)
... dt = datetime.datetime.strptime(cleans, '%d %B %Y')
... return dt.date()
...
>>> parse('5th November 2010')
datetime.date(2010, 11, 5)
Your preference for date vs datetime is no problem of course, that's what the .date() method of datetime objects is for;-).
Third-party extensions like dateutil can be useful if you need to do a lot of "fuzzy" date parsing (or other fancy date-related stuff;-), by the way.
If the ordinal is constant then:
datetime.strptime(s, '%dth %B %Y')
Else:
date_str = '5th November 2010'
modified_date_str = date_str[0:1] + date_str[3:]
datetime.strptime(modified_date_str, '%d %B %Y')
Or like ~unutbu said use dateutil :)