From 1ba6bed4c8675d30480461473a72b1b0287b13e3 Mon Sep 17 00:00:00 2001 From: Fabien Loffredo Date: Fri, 23 Dec 2016 13:52:19 +0100 Subject: add incomplete month date support --- src/isodate/__init__.py | 6 ++++-- src/isodate/isodates.py | 7 ++++++- src/isodate/isostrf.py | 3 ++- src/isodate/tests/test_date.py | 8 +++++--- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/isodate/__init__.py b/src/isodate/__init__.py index 83c8cf8..50862e1 100644 --- a/src/isodate/__init__.py +++ b/src/isodate/__init__.py @@ -43,7 +43,8 @@ from isodate.isostrf import DATE_BAS_COMPLETE, DATE_BAS_ORD_COMPLETE from isodate.isostrf import DATE_BAS_WEEK, DATE_BAS_WEEK_COMPLETE from isodate.isostrf import DATE_CENTURY, DATE_EXT_COMPLETE from isodate.isostrf import DATE_EXT_ORD_COMPLETE, DATE_EXT_WEEK -from isodate.isostrf import DATE_EXT_WEEK_COMPLETE, DATE_MONTH, DATE_YEAR +from isodate.isostrf import DATE_EXT_WEEK_COMPLETE, DATE_YEAR +from isodate.isostrf import DATE_BAS_MONTH, DATE_EXT_MONTH from isodate.isostrf import TIME_BAS_COMPLETE, TIME_BAS_MINUTE from isodate.isostrf import TIME_EXT_COMPLETE, TIME_EXT_MINUTE from isodate.isostrf import TIME_HOUR @@ -61,7 +62,8 @@ __all__ = ['parse_date', 'date_isoformat', 'parse_time', 'time_isoformat', 'strftime', 'DATE_BAS_COMPLETE', 'DATE_BAS_ORD_COMPLETE', 'DATE_BAS_WEEK', 'DATE_BAS_WEEK_COMPLETE', 'DATE_CENTURY', 'DATE_EXT_COMPLETE', 'DATE_EXT_ORD_COMPLETE', 'DATE_EXT_WEEK', - 'DATE_EXT_WEEK_COMPLETE', 'DATE_MONTH', 'DATE_YEAR', + 'DATE_EXT_WEEK_COMPLETE', 'DATE_YEAR', + 'DATE_BAS_MONTH', 'DATE_EXT_MONTH', 'TIME_BAS_COMPLETE', 'TIME_BAS_MINUTE', 'TIME_EXT_COMPLETE', 'TIME_EXT_MINUTE', 'TIME_HOUR', 'TZ_BAS', 'TZ_EXT', 'TZ_HOUR', 'DT_BAS_COMPLETE', 'DT_EXT_COMPLETE', 'DT_BAS_ORD_COMPLETE', diff --git a/src/isodate/isodates.py b/src/isodate/isodates.py index 37d42f8..092712e 100644 --- a/src/isodate/isodates.py +++ b/src/isodate/isodates.py @@ -108,6 +108,10 @@ def build_date_regexps(yeardigits=4, expanded=False): cache_entry.append(re.compile(r"(?P[+-]){%d}(?P[0-9]{%d})" r"-(?P[0-9]{2})" % (sign, yeardigits))) + # YYYMM or +-YYYYYYMM ... basic incomplete month date format + cache_entry.append(re.compile(r"(?P[+-]){%d}(?P[0-9]{%d})" + r"(?P[0-9]{2})" + % (sign, yeardigits))) # 6. year dates: # YYYY or +-YYYYYY ... reduced accuracy specific year cache_entry.append(re.compile(r"(?P[+-]){%d}(?P[0-9]{%d})" @@ -143,6 +147,7 @@ def parse_date(datestring, yeardigits=4, expanded=False): YYYY-DDD +-YYYYYY-DDD extended ordinal date YYYYWww +-YYYYYYWww basic incomplete week date YYYY-Www +-YYYYYY-Www extended incomplete week date + YYYMM +-YYYYYYMM basic incomplete month date YYY-MM +-YYYYYY-MM incomplete month date YYYY +-YYYYYY incomplete year date YY +-YYYY incomplete century date @@ -181,7 +186,7 @@ def parse_date(datestring, yeardigits=4, expanded=False): (((isotuple[1] == 1) and 1) or 0), days=-isotuple[2] + days) elif 'day' in groups: # ordinal date - return ret + timedelta(days=int(groups['day'])-1) + return ret + timedelta(days=int(groups['day']) - 1) else: # year date return ret # year-, month-, or complete date diff --git a/src/isodate/isostrf.py b/src/isodate/isostrf.py index 1afc810..642044b 100644 --- a/src/isodate/isostrf.py +++ b/src/isodate/isostrf.py @@ -48,7 +48,8 @@ DATE_BAS_ORD_COMPLETE = '%Y%j' DATE_EXT_ORD_COMPLETE = '%Y-%j' DATE_BAS_WEEK = '%YW%W' DATE_EXT_WEEK = '%Y-W%W' -DATE_MONTH = '%Y-%m' +DATE_BAS_MONTH = '%Y%m' +DATE_EXT_MONTH = '%Y-%m' DATE_YEAR = '%Y' DATE_CENTURY = '%C' diff --git a/src/isodate/tests/test_date.py b/src/isodate/tests/test_date.py index fdc1043..2519e68 100644 --- a/src/isodate/tests/test_date.py +++ b/src/isodate/tests/test_date.py @@ -30,7 +30,8 @@ Test cases for the isodate module. import unittest from datetime import date from isodate import parse_date, ISO8601Error, date_isoformat -from isodate import DATE_CENTURY, DATE_YEAR, DATE_MONTH +from isodate import DATE_CENTURY, DATE_YEAR +from isodate import DATE_BAS_MONTH, DATE_EXT_MONTH from isodate import DATE_EXT_COMPLETE, DATE_BAS_COMPLETE from isodate import DATE_BAS_ORD_COMPLETE, DATE_EXT_ORD_COMPLETE from isodate import DATE_BAS_WEEK, DATE_BAS_WEEK_COMPLETE @@ -42,7 +43,8 @@ from isodate import DATE_EXT_WEEK, DATE_EXT_WEEK_COMPLETE # and 6 digit years. TEST_CASES = {4: [('19', date(1901, 1, 1), DATE_CENTURY), ('1985', date(1985, 1, 1), DATE_YEAR), - ('1985-04', date(1985, 4, 1), DATE_MONTH), + ('1985-04', date(1985, 4, 1), DATE_EXT_MONTH), + ('198504', date(1985, 4, 1), DATE_BAS_MONTH), ('1985-04-12', date(1985, 4, 12), DATE_EXT_COMPLETE), ('19850412', date(1985, 4, 12), DATE_BAS_COMPLETE), ('1985102', date(1985, 4, 12), DATE_BAS_ORD_COMPLETE), @@ -56,7 +58,7 @@ TEST_CASES = {4: [('19', date(1901, 1, 1), DATE_CENTURY), ('1-W1-1', None, DATE_BAS_WEEK_COMPLETE)], 6: [('+0019', date(1901, 1, 1), DATE_CENTURY), ('+001985', date(1985, 1, 1), DATE_YEAR), - ('+001985-04', date(1985, 4, 1), DATE_MONTH), + ('+001985-04', date(1985, 4, 1), DATE_EXT_MONTH), ('+001985-04-12', date(1985, 4, 12), DATE_EXT_COMPLETE), ('+0019850412', date(1985, 4, 12), DATE_BAS_COMPLETE), ('+001985102', date(1985, 4, 12), DATE_BAS_ORD_COMPLETE), -- cgit v1.2.1 From f609b08adde6a522fc7de9c01a77a70802d668bb Mon Sep 17 00:00:00 2001 From: Fabien Loffredo Date: Fri, 23 Dec 2016 15:30:50 +0100 Subject: add ability to choose default month and day when incomplete date --- src/isodate/isodates.py | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/isodate/isodates.py b/src/isodate/isodates.py index 092712e..aab5684 100644 --- a/src/isodate/isodates.py +++ b/src/isodate/isodates.py @@ -126,7 +126,9 @@ def build_date_regexps(yeardigits=4, expanded=False): return DATE_REGEX_CACHE[(yeardigits, expanded)] -def parse_date(datestring, yeardigits=4, expanded=False): +def parse_date( + datestring, + yeardigits=4, expanded=False, defaultmonth=1, defaultday=1): ''' Parse an ISO 8601 date string into a datetime.date object. @@ -172,7 +174,9 @@ def parse_date(datestring, yeardigits=4, expanded=False): # FIXME: negative dates not possible with python standard types sign = (groups['sign'] == '-' and -1) or 1 if 'century' in groups: - return date(sign * (int(groups['century']) * 100 + 1), 1, 1) + return date( + sign * (int(groups['century']) * 100 + 1), + defaultmonth, defaultday) if 'month' not in groups: # weekdate or ordinal date ret = date(sign * int(groups['year']), 1, 1) if 'week' in groups: @@ -188,14 +192,14 @@ def parse_date(datestring, yeardigits=4, expanded=False): elif 'day' in groups: # ordinal date return ret + timedelta(days=int(groups['day']) - 1) else: # year date - return ret + return ret.replace(month=defaultmonth, day=defaultday) # year-, month-, or complete date if 'day' not in groups or groups['day'] is None: - day = 1 + day = defaultday else: day = int(groups['day']) return date(sign * int(groups['year']), - int(groups['month']) or 1, day) + int(groups['month']) or defaultmonth, day) raise ISO8601Error('Unrecognised ISO 8601 date format: %r' % datestring) -- cgit v1.2.1