fields.py 1.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546
  1. import re
  2. from datetime import datetime, timedelta
  3. from typing import Annotated
  4. from django.utils import timezone
  5. from pydantic import BeforeValidator, Field
  6. SlugStr = Annotated[str, Field(pattern=r"^[-a-zA-Z0-9_]+$", max_length=50)]
  7. # RELATIVE_TIME_REGEX = re.compile(r"now[+-]\d+[mhd]")
  8. RELATIVE_TIME_REGEX = re.compile(r"now\s*\-\s*\d+\s*(m|h|d)\s*$")
  9. def parse_relative_datetime(value: str) -> datetime:
  10. """
  11. Allow relative terms like now or now-1h. Only 0 or 1 math operation is permitted.
  12. Accepts
  13. - now
  14. - + (addition)
  15. - - (subtraction)
  16. - m (minutes)
  17. - h (hours)
  18. - d (days)
  19. """
  20. if value == "now":
  21. return timezone.now()
  22. match = RELATIVE_TIME_REGEX.match(value)
  23. if match:
  24. now = timezone.now()
  25. stripped_value = value.replace(" ", "")
  26. sign = 1 if "+" in stripped_value else -1
  27. number = int(re.findall(r"\d+", stripped_value)[0])
  28. if "m" in stripped_value:
  29. return now + sign * timedelta(minutes=number)
  30. elif "h" in stripped_value:
  31. return now + sign * timedelta(hours=number)
  32. elif "d" in stripped_value:
  33. return now + sign * timedelta(days=number)
  34. return value
  35. RelativeDateTime = Annotated[datetime, BeforeValidator(parse_relative_datetime)]