Package: ciso8601
ciso8601convertsISO 8601orRFC 3339date time strings into Python datetime objects.Since it’s written as a C module, it is much faster than other Python libraries.
Tested with cPython 2.7, 3.4, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12.(Interested in working on projects like this?Closeis looking forgreat engineersto join our team)ContentsQuick startMigration to v2When should I not useciso8601?Error handlingBenchmarkSupported subset of ISO 8601Date formatsTime formatsTime zone informationStrict RFC 3339 parsingIgnoring time zone information while parsingQuick start%pipinstallciso8601In[1]:importciso8601In[2]:ciso8601.parse_datetime('2014-12-05T12:30:45.123456-05:30')Out[2]:datetime.datetime(2014,12,5,12,30,45,123456,tzinfo=pytz.FixedOffset(330))In[3]:ciso8601.parse_datetime('20141205T123045')Out[3]:datetime.datetime(2014,12,5,12,30,45)Migration to v2Version 2.0.0 ofciso8601changed the core implementation. This was not entirely backwards compatible, and care should be taken when migrating
SeeCHANGELOGfor the Migration Guide.When should I not useciso8601?ciso8601is not necessarily the best solution for every use case (especially since Python 3.11). SeeShould I use ciso8601?Error handlingStarting in v2.0.0,ciso8601offers strong guarantees when it comes to parsing strings.parse_datetime(dt: String): datetimeis a function that takes a string and either:Returns a properly parsed Python datetime,if and only iftheentirestring conforms to the supported subset of ISO 8601Raises aValueErrorwith a description of the reason why the string doesn’t conform to the supported subset of ISO 8601If time zone information is provided, an aware datetime object will be returned. Otherwise, a naive datetime is returned.BenchmarkParsing a timestamp with no time zone information (e.g.,2014-01-09T21:48:00):ModulePython 3.12Python 3.11Python 3.10Python 3.9Relative slowdown (versus ciso8601, latest Python)…Python 3.8Python 3.7Python 2.7ciso860198 nsec90 nsec122 nsec122 nsecN/A…118 nsec124 nsec134 nsecbackports.datetime_fromisoformatN/AN/A112 nsec108 nsec0.9x…106 nsec118 nsecN/Adatetime (builtin)129 nsec132 nsecN/AN/A1.3x…N/AN/AN/ApendulumN/A180 nsec187 nsec186 nsec2.0x…196 nsec200 nsec8.52 usecudatetime695 nsec662 nsec674 nsec692 nsec7.1x…724 nsec713 nsec586 nsecstr2date6.86 usec5.78 usec6.59 usec6.4 usec70.0x…6.66 usec6.96 usec❌iso8601utilsN/AN/AN/A8.59 usec70.5x…8.6 usec9.59 usec11.2 useciso860110 usec8.24 usec8.96 usec9.21 usec102.2x…9.14 usec9.63 usec25.7 usecisodate11.1 usec8.76 usec10.2 usec9.76 usec113.6x…9.92 usec11 usec44.1 usecPySO860117.2 usec13.6 usec16 usec15.8 usec175.3x…16.1 usec17.1 usec17.7 usecaniso860122.2 usec17.8 usec23.2 usec23.1 usec227.0x…24.3 usec27.2 usec30.7 useczulu23.3 usec19 usec22 usec21.3 usec237.9x…21.6 usec22.7 usecN/AmayaN/A36.1 usec42.5 usec42.7 usec401.6x…41.3 usec44.2 usecN/Apython-dateutil57.6 usec51.4 usec63.3 usec62.6 usec587.7x…63.7 usec67.3 usec119 usecarrow62 usec54 usec65.5 usec65.7 usec633.0x…66.6 usec70.2 usec78.8 usecmetomi-isodatetime1.29 msec1.33 msec1.76 msec1.77 msec13201.1x…1.79 msec1.91 msecN/Amoment1.81 msec1.65 msec1.75 msec1.79 msec18474.8x…1.78 msec1.84 msecN/Aciso8601 takes 98 nsec, which is1.3x faster than datetime (builtin), the next fastest Python 3.12 parser in this comparison.Parsing a timestamp with time zone information (e.g.,2014-01-09T21:48:00-05:30):ModulePython 3.12Python 3.11Python 3.10Python 3.9Relative slowdown (versus ciso8601, latest Python)…Python 3.8Python 3.7Python 2.7ciso860195 nsec96.8 nsec128 nsec123 nsecN/A…125 nsec125 nsec140 nsecbackports.datetime_fromisoformatN/AN/A147 nsec149 nsec1.1x…138 nsec149 nsecN/Adatetime (builtin)198 nsec207 nsecN/AN/A2.1x…N/AN/AN/ApendulumN/A225 nsec214 nsec211 nsec2.3x…219 nsec224 nsec13.5 usecudatetime799 nsec803 nsec805 nsec830 nsec8.4x…827 nsec805 nsec768 nsecstr2date7.73 usec6.75 usec7.78 usec7.8 usec81.4x…7.74 usec8.13 usec❌iso860113.7 usec11.3 usec12.7 usec12.5 usec143.8x…12.4 usec12.6 usec31.1 usecisodate13.7 usec11.3 usec12.9 usec12.7 usec144.0x…12.7 usec13.9 usec46.7 useciso8601utilsN/AN/AN/A21.4 usec174.9x…22.1 usec23.4 usec28.3 usecPySO860125.1 usec20.4 usec23.2 usec23.8 usec263.8x…23.5 usec24.8 usec25.3 useczulu26.3 usec21.4 usec25.7 usec24 usec277.2x…24.5 usec25.3 usecN/Aaniso860127.7 usec23.7 usec30.3 usec30 usec291.3x…31.6 usec33.8 usec39.2 usecmayaN/A36 usec41.3 usec41.8 usec372.0x…42.4 usec42.7 usecN/Apython-dateutil70.7 usec65.1 usec77.9 usec80.2 usec744.0x…79.4 usec83.6 usec100 usecarrow73 usec62.8 usec74.5 usec73.9 usec768.6x…75.1 usec80 usec148 usecmetomi-isodatetime1.22 msec1.25 msec1.72 msec1.72 msec12876.3x…1.76 msec1.83 msecN/Amoment❌❌❌❌2305822.8x…❌❌N/Aciso8601 takes 95 nsec, which is2.1x faster than datetime (builtin), the next fastest Python 3.12 parser in this comparison.Tested on Linux 5.15.49-linuxkit using the following modules:aniso8601==9.0.1arrow==1.3.0(onPython3.8,3.9,3.10,3.11,3.12),arrow==1.2.3(onPython3.7),arrow==0.17.0(onPython2.7)backports.datetime_fromisoformat==2.0.1ciso8601==2.3.0iso8601==2.1.0(onPython3.8,3.9,3.10,3.11,3.12),iso8601==0.1.16(onPython2.7)iso8601utils==0.1.2isodate==0.6.1maya==0.6.1metomi-isodatetime==1!3.1.0moment==0.12.1pendulum==2.1.2PySO8601==0.2.0python-dateutil==2.8.2str2date==0.905udatetime==0.0.17zulu==2.0.0For full benchmarking details (or to run the benchmark yourself), seebenchmarking/README.rstSupported subset of ISO 8601ciso8601only supports a subset of ISO 8601, but supports a superset of what is supported by Python itself (datetime.fromisoformat), and supports the entirety of theRFC 3339specification.Date formatsThe following date formats are supported:FormatExampleSupportedYYYY-MM-DD(extended)2018-04-29✅YYYY-MM(extended)2018-04✅YYYYMMDD(basic)20180429✅YYYY-Www-D(week date)2009-W01-1✅YYYY-Www(week date)2009-W01✅YYYYWwwD(week date)2009W011✅YYYYWww(week date)2009W01✅YYYY-DDD(ordinal date)1981-095✅YYYYDDD(ordinal date)1981095✅Uncommon ISO 8601 date formats are not supported:FormatExampleSupported--MM-DD(omitted year)--04-29❌--MMDD(omitted year)--0429❌±YYYYY-MM(>4 digit year)+10000-04❌+YYYY-MM(leading +)+2018-04❌-YYYY-MM(negative -)-2018-04❌Time formatsTimes are optional and are separated from the date by the letterT.Consistent withRFC 3339,ciso8601also allows either a space character, or a lower-caset, to be used instead of aT.The following time formats are supported:FormatExampleSupportedhh11✅hhmm1130✅hh:mm11:30✅hhmmss113059✅hh:mm:ss11:30:59✅hhmmss.ssssss113059.123456✅hh:mm:ss.ssssss11:30:59.123456✅hhmmss,ssssss113059,123456✅hh:mm:ss,ssssss11:30:59,123456✅Midnight (special case)24:00:00✅hh.hhh(fractional hours)11.5❌hh:mm.mmm(fractional minutes)11:30.5❌Note:Python datetime objects only have microsecond precision (6 digits). Any additional precision will be truncated.Time zone informationTime zone information may be provided in one of the following formats:FormatExampleSupportedZZ✅zz✅±hh+11✅±hhmm+1130✅±hh:mm+11:30✅While the ISO 8601 specification allows the use of MINUS SIGN (U+2212) in the time zone separator,ciso8601only supports the use of the HYPHEN-MINUS (U+002D) character.Consistent withRFC 3339,ciso8601also allows a lower-casezto be used instead of aZ.Strict RFC 3339 parsingciso8601parses ISO 8601 datetimes, which can be thought of as a superset ofRFC 3339(roughly). In cases where you might want strict RFC 3339 parsing,ciso8601offers aparse_rfc3339method, which behaves in a similar manner toparse_datetime:parse_rfc3339(dt: String): datetimeis a function that takes a string and either:Returns a properly parsed Python datetime,if and only iftheentirestring conforms to RFC 3339.Raises aValueErrorwith a description of the reason why the string doesn’t conform to RFC 3339.Ignoring time zone information while parsingIt takes more time to parse timestamps with time zone information, especially if they’re not in UTC. However, there are times when you don’t care about time zone information, and wish to produce naive datetimes instead.
For example, if you are certain that your program will only parse timestamps from a single time zone, you might want to strip the time zone information and only output naive datetimes.In these limited cases, there is a second function provided.parse_datetime_as_naivewill ignore any time zone information it finds and, as a result, is faster for timestamps containing time zone information.In[1]:importciso8601In[2]:ciso8601.parse_datetime_as_naive('2014-12-05T12:30:45.123456-05:30')Out[2]:datetime.datetime(2014,12,5,12,30,45,123456)NOTE:parse_datetime_as_naiveis only useful in the case where your timestamps have time zone information, but you want to ignore it. This is somewhat unusual.
If your timestamps don’t have time zone information (i.e. are naive), simply useparse_datetime. It is just as fast.