datetime.py 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. import datetime
  2. from wtforms import widgets
  3. from wtforms.fields.core import Field
  4. from wtforms.utils import clean_datetime_format_for_strptime
  5. __all__ = (
  6. "DateTimeField",
  7. "DateField",
  8. "TimeField",
  9. "MonthField",
  10. "DateTimeLocalField",
  11. "WeekField",
  12. )
  13. class DateTimeField(Field):
  14. """
  15. A text field which stores a :class:`datetime.datetime` matching one or
  16. several formats. If ``format`` is a list, any input value matching any
  17. format will be accepted, and the first format in the list will be used
  18. to produce HTML values.
  19. """
  20. widget = widgets.DateTimeInput()
  21. def __init__(
  22. self, label=None, validators=None, format="%Y-%m-%d %H:%M:%S", **kwargs
  23. ):
  24. super().__init__(label, validators, **kwargs)
  25. self.format = format if isinstance(format, list) else [format]
  26. self.strptime_format = clean_datetime_format_for_strptime(self.format)
  27. def _value(self):
  28. if self.raw_data:
  29. return " ".join(self.raw_data)
  30. return self.data and self.data.strftime(self.format[0]) or ""
  31. def process_formdata(self, valuelist):
  32. if not valuelist:
  33. return
  34. date_str = " ".join(valuelist)
  35. for format in self.strptime_format:
  36. try:
  37. self.data = datetime.datetime.strptime(date_str, format)
  38. return
  39. except ValueError:
  40. self.data = None
  41. raise ValueError(self.gettext("Not a valid datetime value."))
  42. class DateField(DateTimeField):
  43. """
  44. Same as :class:`~wtforms.fields.DateTimeField`, except stores a
  45. :class:`datetime.date`.
  46. """
  47. widget = widgets.DateInput()
  48. def __init__(self, label=None, validators=None, format="%Y-%m-%d", **kwargs):
  49. super().__init__(label, validators, format, **kwargs)
  50. def process_formdata(self, valuelist):
  51. if not valuelist:
  52. return
  53. date_str = " ".join(valuelist)
  54. for format in self.strptime_format:
  55. try:
  56. self.data = datetime.datetime.strptime(date_str, format).date()
  57. return
  58. except ValueError:
  59. self.data = None
  60. raise ValueError(self.gettext("Not a valid date value."))
  61. class TimeField(DateTimeField):
  62. """
  63. Same as :class:`~wtforms.fields.DateTimeField`, except stores a
  64. :class:`datetime.time`.
  65. """
  66. widget = widgets.TimeInput()
  67. def __init__(self, label=None, validators=None, format="%H:%M", **kwargs):
  68. super().__init__(label, validators, format, **kwargs)
  69. def process_formdata(self, valuelist):
  70. if not valuelist:
  71. return
  72. time_str = " ".join(valuelist)
  73. for format in self.strptime_format:
  74. try:
  75. self.data = datetime.datetime.strptime(time_str, format).time()
  76. return
  77. except ValueError:
  78. self.data = None
  79. raise ValueError(self.gettext("Not a valid time value."))
  80. class MonthField(DateField):
  81. """
  82. Same as :class:`~wtforms.fields.DateField`, except represents a month,
  83. stores a :class:`datetime.date` with `day = 1`.
  84. """
  85. widget = widgets.MonthInput()
  86. def __init__(self, label=None, validators=None, format="%Y-%m", **kwargs):
  87. super().__init__(label, validators, format, **kwargs)
  88. class WeekField(DateField):
  89. """
  90. Same as :class:`~wtforms.fields.DateField`, except represents a week,
  91. stores a :class:`datetime.date` of the monday of the given week.
  92. """
  93. widget = widgets.WeekInput()
  94. def __init__(self, label=None, validators=None, format="%Y-W%W", **kwargs):
  95. super().__init__(label, validators, format, **kwargs)
  96. def process_formdata(self, valuelist):
  97. if not valuelist:
  98. return
  99. time_str = " ".join(valuelist)
  100. for format in self.strptime_format:
  101. try:
  102. if "%w" not in format:
  103. # The '%w' week starting day is needed. This defaults it to monday
  104. # like ISO 8601 indicates.
  105. self.data = datetime.datetime.strptime(
  106. f"{time_str}-1", f"{format}-%w"
  107. ).date()
  108. else:
  109. self.data = datetime.datetime.strptime(time_str, format).date()
  110. return
  111. except ValueError:
  112. self.data = None
  113. raise ValueError(self.gettext("Not a valid week value."))
  114. class DateTimeLocalField(DateTimeField):
  115. """
  116. Same as :class:`~wtforms.fields.DateTimeField`, but represents an
  117. ``<input type="datetime-local">``.
  118. """
  119. widget = widgets.DateTimeLocalInput()
  120. def __init__(self, *args, **kwargs):
  121. kwargs.setdefault(
  122. "format",
  123. [
  124. "%Y-%m-%d %H:%M:%S",
  125. "%Y-%m-%dT%H:%M:%S",
  126. "%Y-%m-%d %H:%M",
  127. "%Y-%m-%dT%H:%M",
  128. ],
  129. )
  130. super().__init__(*args, **kwargs)