Related
I have a CSV dumpfile from a Blackberry IPD backup, created using IPDDump.
The date/time strings in here look something like this
(where EST is an Australian time-zone):
Tue Jun 22 07:46:22 EST 2010
I need to be able to parse this date in Python. At first, I tried to use the strptime() function from datettime.
>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')
However, for some reason, the datetime object that comes back doesn't seem to have any tzinfo associated with it.
I did read on this page that apparently datetime.strptime silently discards tzinfo, however, I checked the documentation, and I can't find anything to that effect documented here.
Is there any way to get strptime() to play nicely with timezones?
I recommend using python-dateutil. Its parser has been able to parse every date format I've thrown at it so far.
>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)
and so on. No dealing with strptime() format nonsense... just throw a date at it and it Does The Right Thing.
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
Since strptime returns a datetime object which has tzinfo attribute, We can simply replace it with desired timezone.
>>> import datetime
>>> date_time_str = '2018-06-29 08:15:27.243860'
>>> date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S.%f').replace(tzinfo=datetime.timezone.utc)
>>> date_time_obj.tzname()
'UTC'
Your time string is similar to the time format in rfc 2822 (date format in email, http headers). You could parse it using only stdlib:
>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)
See solutions that yield timezone-aware datetime objects for various Python versions: parsing date with timezone from an email.
In this format, EST is semantically equivalent to -0500. Though, in general, a timezone abbreviation is not enough, to identify a timezone uniquely.
Ran into this exact problem.
What I ended up doing:
# starting with date string
sdt = "20190901"
std_format = '%Y%m%d'
# create naive datetime object
from datetime import datetime
dt = datetime.strptime(sdt, sdt_format)
# extract the relevant date time items
dt_formatters = ['%Y','%m','%d']
dt_vals = tuple(map(lambda formatter: int(datetime.strftime(dt,formatter)), dt_formatters))
# set timezone
import pendulum
tz = pendulum.timezone('utc')
dt_tz = datetime(*dt_vals,tzinfo=tz)
This question already has answers here:
Weird timezone issue with pytz
(3 answers)
Python datetime object show wrong timezone offset
(2 answers)
Closed 13 days ago.
Consider the following:
from datetime import datetime
import pytz
new_years_in_new_york = datetime(
year=2020,
month=1,
day=1,
hour=0,
minute=0,
tzinfo = pytz.timezone('US/Eastern'))
I now I have a datetime object representing January 1, midnight, in New York. Oddly, if I use pytz to convert this to UTC, I'll get an odd datetime off by several minutes:
new_years_in_new_york.astimezone(pytz.utc)
# datetime.datetime(2020, 1, 1, 4, 56, tzinfo=<UTC>)
Notice that midnight in New York, in pytz, is 4:56 in UTC. Elsewhere on Stack Overflow, I learned that's because pytz uses your /usr/share/zoneinfo data, which uses local mean time to account for timezones before standardization. This can be shown here:
pytz.timezone('US/Eastern')
# <DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>
See that LMK-1 day, 19:04:00 STD? That's a local mean time offset, not the offset I want, which is US/Eastern not during daylight savings time.
Is there a way I can force pytz to use what is currently the standard set of offsets based on a current date? On New Years 2020, it should just be UTC-5. If the date I supplied were during daylight savings time, I would want UTC-4. I'm confused as to why pytz would use a LMT-based offset for a 2020 date.
>>> new_years_in_new_york
datetime.datetime(2020, 1, 1, 0, 0, tzinfo=<DstTzInfo 'US/Eastern' LMT-1 day, 19:04:00 STD>)
Notice the odd offset in that datetime. You're not creating this datetime correctly.
This library only supports two ways of building a localized time. The
first is to use the localize() method provided by the pytz library.
This is used to localize a naive datetime (datetime with no timezone
information):
>>> loc_dt = eastern.localize(datetime(2002, 10, 27, 6, 0, 0))
>>> print(loc_dt.strftime(fmt))
2002-10-27 06:00:00 EST-0500
The second way of building a localized time is by converting an
existing localized time using the standard astimezone() method:
>>> ams_dt = loc_dt.astimezone(amsterdam)
>>> ams_dt.strftime(fmt)
'2002-10-27 12:00:00 CET+0100'
Unfortunately using the tzinfo argument of the standard datetime
constructors ‘’does not work’’ with pytz for many timezones.
>>> datetime(2002, 10, 27, 12, 0, 0, tzinfo=amsterdam).strftime(fmt)
'2002-10-27 12:00:00 LMT+0020'
http://pytz.sourceforge.net/#localized-times-and-date-arithmetic
I get the server date and I need to get the difference of this date from GMT
I get
Datetime = "2011-04-27 2:17:45"
I would like to get the result like
Datetime = "2011-04-27 2:17:45 +0500"
Try this:
import datetime, pytz
now = datetime.datetime.now(pytz.timezone('Asia/Kolkata'))
print now.strftime('%Y-%m-%d %H:%M:%S %z')
# prints: '2011-04-27 13:56:09 +0530'
From the example you have given, it looks to me that what you are looking for is datetime.isoformat. The example in the page shows how to convert the datetime values to the ISO format with the time zone information.
To do this, you have to know the timezone (or the UTC offset) of the server date. What you have here is a "naive" date, without timezone info, you can't guess the UTC difference.
I think the datetime module is what you need here:
>>> from datetime import datetime
>>> datetime.now()
datetime.datetime(2011, 4, 27, 11, 8, 26, 149000)
>>> datetime.utcnow()
datetime.datetime(2011, 4, 27, 8, 8, 47, 712000)
For a difference between two dates:
>>> dtnow = datetime.now()
>>> dtutc = datetime.utcnow()
>>> dtnow - dtutc
datetime.timedelta(0, 10792, 847000)
Look up the datetime module and the relevant classes in Python's docs.
A very powerful extension of the datetime standard python library is the dateutil one, that allows you to easily:
set the delta of your time zone:
parse dates with various convenient options (in our case we will use the default option, which will allow us to set our time zone)
So 1st set time zone, and default date with this zone:
>>> from datetime import datetime
>>> from dateutil import parser
>>> from dateutil.tz import tzoffset
>>> tz_plus_5 = tzoffset(None, 5 * 60 * 60) # offset is in seconds !
>>> default = datetime.now(tz_plus_5)
Now use this default date in the parsing:
>>> Datetime = "2011-04-27 2:17:45"
>>> my_date = parser.parse(Datetime, default=default)
>>> my_date
datetime.datetime(2011, 4, 27, 2, 17, 45, tzinfo=tzoffset(None, 18000))
>>> my_date.strftime("%Y-%m-%d %H:%M:%S %z")
'2011-04-27 02:17:45 +0500'
For those that simply need to get the offset between local time and UTC, the time module has an attribute time.altzone that specifies the difference between UTC and local time in seconds:
The offset of the local DST timezone, in seconds west of UTC, if one is defined. This is negative if the local DST timezone is east of UTC (as in Western Europe, including the UK). Only use this if daylight is nonzero.
Here's an example of how it works:
>>> datetime.now().isoformat()
'2011-09-01T17:26:46.971000'
>>> datetime.utcnow().isoformat()
'2011-09-01T15:27:32.699000'
>>> time.altzone / (60*60)
-2
Doesn't get much cleaner than that.
I am trying to convert a string timestamp into a proper datetime object. The problem I am having is that there is a timezone offset and everything I am doing doesn't seem to work.
Ultimately I want to convert the string timestamp into a datetime object in my machines timezone.
# string timestamp
date = "Fri, 16 Jul 2010 07:08:23 -0700"
The dateutil package is handy for parsing date/times:
In [10]: date = u"Fri, 16 Jul 2010 07:08:23 -0700"
In [11]: from dateutil.parser import parse
In [12]: parse(date)
Out[12]: datetime.datetime(2010, 7, 16, 7, 8, 23, tzinfo=tzoffset(None, -25200))
Finally, to convert into your local timezone,
In [13]: parse(date).astimezone(YOUR_LOCAL_TIMEZONE)
It looks like datetime.datetime.strptime(d, '%a, %d %b %Y %H:%M:%S %z') should work, but according to this bug report there are issues with the %z processing. So you'll probably have to handle the timezone on your own:
import datetime
d = u"Fri, 16 Jul 2010 07:08:23 -0700"
d, tz_info = d[:-5], d[-5:]
neg, hours, minutes = tz_info[0], int(tz_info[1:3]), int(tz_info[3:])
if neg == '-':
hours, minutes = hours * -1, minutes * -1
d = datetime.datetime.strptime(d, '%a, %d %b %Y %H:%M:%S ')
print d
print d + datetime.timedelta(hours = hours, minutes = minutes)
Here's a stdlib solution:
>>> from datetime import datetime
>>> from email.utils import mktime_tz, parsedate_tz
>>> datetime.fromtimestamp(mktime_tz(parsedate_tz(u"Fri, 16 Jul 2010 07:08:23 -0700")))
datetime.datetime(2010, 7, 16, 16, 8, 23) # your local time may be different
See also, Python: parsing date with timezone from an email.
Note: fromtimestamp() may fail if the local timezone had different UTC offset in the past (2010) and if it does not use a historical timezone database on the given platform. To fix it, you could use tzlocal.get_localzone(), to get a pytz tzinfo object representing your local timezone. pytz provides access to the tz database in a portable manner:
>>> timestamp = mktime_tz(parsedate_tz(u"Fri, 16 Jul 2010 07:08:23 -0700"))
>>> import tzlocal # $ pip install tzlocal
>>> str(datetime.fromtimestamp(timestamp, tzlocal.get_localzone()))
'2010-07-16 16:08:23+02:00'
I have a CSV dumpfile from a Blackberry IPD backup, created using IPDDump.
The date/time strings in here look something like this
(where EST is an Australian time-zone):
Tue Jun 22 07:46:22 EST 2010
I need to be able to parse this date in Python. At first, I tried to use the strptime() function from datettime.
>>> datetime.datetime.strptime('Tue Jun 22 12:10:20 2010 EST', '%a %b %d %H:%M:%S %Y %Z')
However, for some reason, the datetime object that comes back doesn't seem to have any tzinfo associated with it.
I did read on this page that apparently datetime.strptime silently discards tzinfo, however, I checked the documentation, and I can't find anything to that effect documented here.
Is there any way to get strptime() to play nicely with timezones?
I recommend using python-dateutil. Its parser has been able to parse every date format I've thrown at it so far.
>>> from dateutil import parser
>>> parser.parse("Tue Jun 22 07:46:22 EST 2010")
datetime.datetime(2010, 6, 22, 7, 46, 22, tzinfo=tzlocal())
>>> parser.parse("Fri, 11 Nov 2011 03:18:09 -0400")
datetime.datetime(2011, 11, 11, 3, 18, 9, tzinfo=tzoffset(None, -14400))
>>> parser.parse("Sun")
datetime.datetime(2011, 12, 18, 0, 0)
>>> parser.parse("10-11-08")
datetime.datetime(2008, 10, 11, 0, 0)
and so on. No dealing with strptime() format nonsense... just throw a date at it and it Does The Right Thing.
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
Since strptime returns a datetime object which has tzinfo attribute, We can simply replace it with desired timezone.
>>> import datetime
>>> date_time_str = '2018-06-29 08:15:27.243860'
>>> date_time_obj = datetime.datetime.strptime(date_time_str, '%Y-%m-%d %H:%M:%S.%f').replace(tzinfo=datetime.timezone.utc)
>>> date_time_obj.tzname()
'UTC'
Your time string is similar to the time format in rfc 2822 (date format in email, http headers). You could parse it using only stdlib:
>>> from email.utils import parsedate_tz
>>> parsedate_tz('Tue Jun 22 07:46:22 EST 2010')
(2010, 6, 22, 7, 46, 22, 0, 1, -1, -18000)
See solutions that yield timezone-aware datetime objects for various Python versions: parsing date with timezone from an email.
In this format, EST is semantically equivalent to -0500. Though, in general, a timezone abbreviation is not enough, to identify a timezone uniquely.
Ran into this exact problem.
What I ended up doing:
# starting with date string
sdt = "20190901"
std_format = '%Y%m%d'
# create naive datetime object
from datetime import datetime
dt = datetime.strptime(sdt, sdt_format)
# extract the relevant date time items
dt_formatters = ['%Y','%m','%d']
dt_vals = tuple(map(lambda formatter: int(datetime.strftime(dt,formatter)), dt_formatters))
# set timezone
import pendulum
tz = pendulum.timezone('utc')
dt_tz = datetime(*dt_vals,tzinfo=tz)