date.py 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. # -*- coding: utf-8 -*-
  2. # Copyright (c) 2021, Brandon Nielsen
  3. # All rights reserved.
  4. #
  5. # This software may be modified and distributed under the terms
  6. # of the BSD license. See the LICENSE file for details.
  7. from aniso8601.builders import TupleBuilder
  8. from aniso8601.builders.python import PythonTimeBuilder
  9. from aniso8601.compat import is_string
  10. from aniso8601.exceptions import ISOFormatError
  11. from aniso8601.resolution import DateResolution
  12. def get_date_resolution(isodatestr):
  13. # Valid string formats are:
  14. #
  15. # Y[YYY]
  16. # YYYY-MM-DD
  17. # YYYYMMDD
  18. # YYYY-MM
  19. # YYYY-Www
  20. # YYYYWww
  21. # YYYY-Www-D
  22. # YYYYWwwD
  23. # YYYY-DDD
  24. # YYYYDDD
  25. isodatetuple = parse_date(isodatestr, builder=TupleBuilder)
  26. if isodatetuple.DDD is not None:
  27. # YYYY-DDD
  28. # YYYYDDD
  29. return DateResolution.Ordinal
  30. if isodatetuple.D is not None:
  31. # YYYY-Www-D
  32. # YYYYWwwD
  33. return DateResolution.Weekday
  34. if isodatetuple.Www is not None:
  35. # YYYY-Www
  36. # YYYYWww
  37. return DateResolution.Week
  38. if isodatetuple.DD is not None:
  39. # YYYY-MM-DD
  40. # YYYYMMDD
  41. return DateResolution.Day
  42. if isodatetuple.MM is not None:
  43. # YYYY-MM
  44. return DateResolution.Month
  45. # Y[YYY]
  46. return DateResolution.Year
  47. def parse_date(isodatestr, builder=PythonTimeBuilder):
  48. # Given a string in any ISO 8601 date format, return a datetime.date
  49. # object that corresponds to the given date. Valid string formats are:
  50. #
  51. # Y[YYY]
  52. # YYYY-MM-DD
  53. # YYYYMMDD
  54. # YYYY-MM
  55. # YYYY-Www
  56. # YYYYWww
  57. # YYYY-Www-D
  58. # YYYYWwwD
  59. # YYYY-DDD
  60. # YYYYDDD
  61. if is_string(isodatestr) is False:
  62. raise ValueError("Date must be string.")
  63. if isodatestr.startswith("+") or isodatestr.startswith("-"):
  64. raise NotImplementedError(
  65. "ISO 8601 extended year representation " "not supported."
  66. )
  67. if len(isodatestr) == 0 or isodatestr.count("-") > 2:
  68. raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr))
  69. yearstr = None
  70. monthstr = None
  71. daystr = None
  72. weekstr = None
  73. weekdaystr = None
  74. ordinaldaystr = None
  75. if len(isodatestr) <= 4:
  76. # Y[YYY]
  77. yearstr = isodatestr
  78. elif "W" in isodatestr:
  79. if len(isodatestr) == 10:
  80. # YYYY-Www-D
  81. yearstr = isodatestr[0:4]
  82. weekstr = isodatestr[6:8]
  83. weekdaystr = isodatestr[9]
  84. elif len(isodatestr) == 8:
  85. if "-" in isodatestr:
  86. # YYYY-Www
  87. yearstr = isodatestr[0:4]
  88. weekstr = isodatestr[6:]
  89. else:
  90. # YYYYWwwD
  91. yearstr = isodatestr[0:4]
  92. weekstr = isodatestr[5:7]
  93. weekdaystr = isodatestr[7]
  94. elif len(isodatestr) == 7:
  95. # YYYYWww
  96. yearstr = isodatestr[0:4]
  97. weekstr = isodatestr[5:]
  98. elif len(isodatestr) == 7:
  99. if "-" in isodatestr:
  100. # YYYY-MM
  101. yearstr = isodatestr[0:4]
  102. monthstr = isodatestr[5:]
  103. else:
  104. # YYYYDDD
  105. yearstr = isodatestr[0:4]
  106. ordinaldaystr = isodatestr[4:]
  107. elif len(isodatestr) == 8:
  108. if "-" in isodatestr:
  109. # YYYY-DDD
  110. yearstr = isodatestr[0:4]
  111. ordinaldaystr = isodatestr[5:]
  112. else:
  113. # YYYYMMDD
  114. yearstr = isodatestr[0:4]
  115. monthstr = isodatestr[4:6]
  116. daystr = isodatestr[6:]
  117. elif len(isodatestr) == 10:
  118. # YYYY-MM-DD
  119. yearstr = isodatestr[0:4]
  120. monthstr = isodatestr[5:7]
  121. daystr = isodatestr[8:]
  122. else:
  123. raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr))
  124. hascomponent = False
  125. for componentstr in [yearstr, monthstr, daystr, weekstr, weekdaystr, ordinaldaystr]:
  126. if componentstr is not None:
  127. hascomponent = True
  128. if componentstr.isdigit() is False:
  129. raise ISOFormatError(
  130. '"{0}" is not a valid ISO 8601 date.'.format(isodatestr)
  131. )
  132. if hascomponent is False:
  133. raise ISOFormatError('"{0}" is not a valid ISO 8601 date.'.format(isodatestr))
  134. return builder.build_date(
  135. YYYY=yearstr,
  136. MM=monthstr,
  137. DD=daystr,
  138. Www=weekstr,
  139. D=weekdaystr,
  140. DDD=ordinaldaystr,
  141. )