21

Using '%z' pattern of datetime.strptime()

I have a string text that represent a date and I'm perfectly able to parse it and transform it into a clean datetime object:

date = "[24/Aug/2014:17:57:26"
dt = datetime.strptime(date, "[%d/%b/%Y:%H:%M:%S")  

Except that I can't catch the entire date string with the timezone using the %z pattern as specified here

date_tz = 24/Aug/2014:17:57:26 +0200
dt = datetime.strptime(date, "[%d/%b/%Y:%H:%M:%S %z]")
>>> ValueError: 'z' is a bad directive in format '[%d/%b/%Y:%H:%M:%S %z]'

Because as this bug report says

strftime() is implemented per platform

I precise that there is no such a problem with the naive tzinfo directive '%Z'

Workaround : Casting tzinfo string into tzinfo object

I can perfectly make the following workaround by transforming the GST time format string into a tzinfo object [as suggested here][4] using dateutil module and then insert tzinfo into datetime object

Question: Make %z available for my plateform?

But as I will obviously need %z pattern for further project I would like to find a solution to avoid this workaround and using external module for this simple task. Can you suggest me some reading on it? I supposed that newer version of python (I'm on 2.7) can handle it but I'd rather not changing my version now for this little but crucial detail.

[EDIT]

Well, seeing comments make me reformulated my question how to parse Email time zone indicator using strptime() without being aware of locale time?

Community
  • 1
  • 1
c24b
  • 5,278
  • 6
  • 27
  • 35
  • 2
    If it's not supported by the underlying C library that Python depends on, you're not going to get it. – Mark Ransom Oct 02 '14 at 17:25
  • So I imagine that I have no other option that doing every time this ugly and unefficient workaround? – c24b Oct 02 '14 at 17:28
  • I'm not aware of any way to do it, and I'm sure the question has been asked before. – Mark Ransom Oct 02 '14 at 17:31
  • For timezone stuff, you may want to look into `pytz` -> http://pytz.sourceforge.net/ – Gohn67 Oct 02 '14 at 18:09
  • pytz doesn't cast a string format like '+0400' into a tzinfo object. I need that it doesn't take in count my locale but the input string. – c24b Oct 02 '14 at 22:57
  • 1
    Related to http://stackoverflow.com/questions/23940551/why-z-is-not-supported-by-pythons-strptime – wanghq Nov 04 '14 at 00:14

3 Answers3

28

strptime() is implemented in pure Python. Unlike strftime(); it [which directives are supported] doesn't depend on platform. %z is supported since Python 3.2:

>>> from datetime import datetime
>>> datetime.strptime('24/Aug/2014:17:57:26 +0200', '%d/%b/%Y:%H:%M:%S %z')
datetime.datetime(2014, 8, 24, 17, 57, 26, tzinfo=datetime.timezone(datetime.timedelta(0, 7200)))

how to parse Email time zone indicator using strptime() without being aware of locale time?

There is no concrete timezone implementation in Python 2.7. You could easily implement the UTC offset parsing, see How to parse dates with -0400 timezone string in python?

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
15

In continue to @j-f-sebastians 's answer, here is a fix for python 2.7

Instead of using:

datetime.strptime(t,'%Y-%m-%dT%H:%M %z')

use the timedelta to account for the timezone, like this:

from datetime import datetime,timedelta
def dt_parse(t):
    ret = datetime.strptime(t[0:16],'%Y-%m-%dT%H:%M')
    if t[17]=='+':
       ret-=timedelta(hours=int(t[18:20]),minutes=int(t[20:]))
    elif t[17]=='-':
       ret+=timedelta(hours=int(t[18:20]),minutes=int(t[20:]))
    return ret

print(dt_parse('2017-01-12T14:12 -0530'))
Rene B.
  • 6,557
  • 7
  • 46
  • 72
Uri Goren
  • 13,386
  • 6
  • 58
  • 110
  • should'nt it be timedelta(hours=int(t[19:22]),minutes=int(t[23:])) ?? – guilhermecgs Oct 20 '16 at 15:52
  • 1
    @guilhermecgs if the intent is to return corresponding UTC time, the sign is correct: "local time = utc time + utc offset", therefore given local time and the offset, to get utc time: "utc time = local time - utc offset" For example, "18:00 +0200" corresponds to 16:00 UTC. To disambiguate, return timezone aware datetime object: `return utc_dt.replace(tzinfo=DT.timezone.utc)` – jfs Sep 11 '22 at 11:20
2

The Answer of Uri is great, saved my life, but when you have USE_TZ = True you need to be careful with the time, for avoid the warning "RuntimeWarning: DateTimeField" is better if you add the utc to the return.

import pytz
from datetime import datetime, timedelta
def dt_parse(t):
    ret = datetime.strptime(t[0:19],'%Y-%m-%dT%H:%M:%S')
    if t[23]=='+':
        ret-=timedelta(hours=int(t[24:26]), minutes=int(t[27:]))
    elif t[23]=='-':
        ret+=timedelta(hours=int(t[24:26]), minutes=int(t[27:]))
    return ret.replace(tzinfo=pytz.UTC)
LaBE
  • 117
  • 1
  • 9