# -*- coding: utf-8 -*- # Copyright (c) 2021, Brandon Nielsen # All rights reserved. # # This software may be modified and distributed under the terms # of the BSD license. See the LICENSE file for details. from aniso8601.builders import TupleBuilder from aniso8601.builders.python import PythonTimeBuilder from aniso8601.compat import is_string from aniso8601.exceptions import ISOFormatError from aniso8601.resolution import DateResolution def get_date_resolution(isodatestr): # Valid string formats are: # # Y[YYY] # YYYY-MM-DD # YYYYMMDD # YYYY-MM # YYYY-Www # YYYYWww # YYYY-Www-D # YYYYWwwD # YYYY-DDD # YYYYDDD isodatetuple = parse_date(isodatestr, builder=TupleBuilder) if isodatetuple.DDD is not None: # YYYY-DDD # YYYYDDD return DateResolution.Ordinal if isodatetuple.D is not None: # YYYY-Www-D # YYYYWwwD return DateResolution.Weekday if isodatetuple.Www is not None: # YYYY-Www # YYYYWww return DateResolution.Week if isodatetuple.DD is not None: # YYYY-MM-DD # YYYYMMDD return DateResolution.Day if isodatetuple.MM is not None: # YYYY-MM return DateResolution.Month # Y[YYY] return DateResolution.Year def parse_date(isodatestr, builder=PythonTimeBuilder): # Given a string in any ISO 8601 date format, return a datetime.date # object that corresponds to the given date. Valid string formats are: # # Y[YYY] # YYYY-MM-DD # YYYYMMDD # YYYY-MM # YYYY-Www # YYYYWww # YYYY-Www-D # YYYYWwwD # YYYY-DDD # YYYYDDD if is_string(isodatestr) is False: raise ValueError("Date must be string.") if isodatestr.startswith("+") or isodatestr.startswith("-"): raise NotImplementedError( "ISO 8601 extended year representation " "not supported." ) if len(isodatestr) == 0 or isodatestr.count("-") > 2: raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr)) yearstr = None monthstr = None daystr = None weekstr = None weekdaystr = None ordinaldaystr = None if len(isodatestr) <= 4: # Y[YYY] yearstr = isodatestr elif "W" in isodatestr: if len(isodatestr) == 10: # YYYY-Www-D yearstr = isodatestr[0:4] weekstr = isodatestr[6:8] weekdaystr = isodatestr[9] elif len(isodatestr) == 8: if "-" in isodatestr: # YYYY-Www yearstr = isodatestr[0:4] weekstr = isodatestr[6:] else: # YYYYWwwD yearstr = isodatestr[0:4] weekstr = isodatestr[5:7] weekdaystr = isodatestr[7] elif len(isodatestr) == 7: # YYYYWww yearstr = isodatestr[0:4] weekstr = isodatestr[5:] elif len(isodatestr) == 7: if "-" in isodatestr: # YYYY-MM yearstr = isodatestr[0:4] monthstr = isodatestr[5:] else: # YYYYDDD yearstr = isodatestr[0:4] ordinaldaystr = isodatestr[4:] elif len(isodatestr) == 8: if "-" in isodatestr: # YYYY-DDD yearstr = isodatestr[0:4] ordinaldaystr = isodatestr[5:] else: # YYYYMMDD yearstr = isodatestr[0:4] monthstr = isodatestr[4:6] daystr = isodatestr[6:] elif len(isodatestr) == 10: # YYYY-MM-DD yearstr = isodatestr[0:4] monthstr = isodatestr[5:7] daystr = isodatestr[8:] else: raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr)) hascomponent = False for componentstr in [yearstr, monthstr, daystr, weekstr, weekdaystr, ordinaldaystr]: if componentstr is not None: hascomponent = True if componentstr.isdigit() is False: raise ISOFormatError( '"{0}" is not a valid ISO 8601 date.'.format(isodatestr) ) if hascomponent is False: raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr)) return builder.build_date( YYYY=yearstr, MM=monthstr, DD=daystr, Www=weekstr, D=weekdaystr, DDD=ordinaldaystr, )