examples.28_date_parsing

Demonstrates parsing date strings in multiple formats and validating that the resulting date is within an acceptable range.

This example shows:
  • How to accept multiple common date formats (ISO, European, etc.).
  • How to convert strings into datetime.date objects via a transformation pipeline.
  • How to use RangeValue to validate that a parsed date lies within a specified valid range.
Supported formats:
  • "%Y-%m-%d" → ISO format (e.g., "2000-01-31")
  • "%d/%m/%Y" → European format (e.g., "31/01/2000")
  • "%d-%b-%Y" → Month abbreviation (e.g., "31-Jan-2000")
Run directly:

python examples/28_date_parsing.py

Expected output:

parsed: OK 2000-01-31 in-range: OK

 1"""Demonstrates parsing date strings in multiple formats and validating that the
 2resulting date is within an acceptable range.
 3
 4This example shows:
 5  * How to accept multiple common date formats (ISO, European, etc.).
 6  * How to convert strings into `datetime.date` objects via a transformation pipeline.
 7  * How to use :class:`RangeValue` to validate that a parsed date lies within
 8    a specified valid range.
 9
10Supported formats:
11  * `"%Y-%m-%d"` → ISO format (e.g., `"2000-01-31"`)
12  * `"%d/%m/%Y"` → European format (e.g., `"31/01/2000"`)
13  * `"%d-%b-%Y"` → Month abbreviation (e.g., `"31-Jan-2000"`)
14
15Run directly:
16
17    python examples/28_date_parsing.py
18
19Expected output:
20
21    parsed: OK 2000-01-31
22    in-range: OK
23"""
24
25import sys
26import pathlib
27from datetime import date, datetime
28from typing import List
29
30# ---------------------------------------------------------------------------
31# Make repo root importable when running this file directly
32# ---------------------------------------------------------------------------
33sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[1]))
34
35from constrained_values import Response, Status, TypeValidationStrategy, RangeValue
36from constrained_values.value import TransformationStrategy, ConstrainedValue, PipeLineStrategy
37
38
39FORMATS = ["%Y-%m-%d", "%d/%m/%Y", "%d-%b-%Y"]
40
41
42class ToDate(TransformationStrategy[str, date]):
43    """Transform a string into a `datetime.date` object using multiple formats."""
44
45    def transform(self, value: str) -> Response[date]:
46        """Attempt to parse a date from the input string using known formats.
47
48        Args:
49            value: The input date string.
50
51        Returns:
52            Response[date]:
53                * `status = Status.OK` and the parsed date if successful.
54                * `status = Status.EXCEPTION` and an error message if all formats fail.
55        """
56        v = value.strip()
57        for fmt in FORMATS:
58            try:
59                parsed = datetime.strptime(v, fmt).date()
60            except ValueError:
61                continue  # Try the next format
62            else:
63                return Response(Status.OK, fmt, parsed)
64        return Response(Status.EXCEPTION, f"no matching formats for {v!r}; tried {FORMATS}", None)
65
66
67class BirthDate(ConstrainedValue[date]):
68    """A constrained value that parses and validates date strings."""
69
70    def get_strategies(self) -> List[PipeLineStrategy]:
71        """Return the transformation pipeline (string → date)."""
72        return [TypeValidationStrategy(str), ToDate()]
73
74
75def main() -> None:
76    """Run the date parsing and range validation demonstration.
77
78    Steps:
79        1. Parse a valid date string using `BirthDate`.
80        2. Validate the parsed date against a valid range using `RangeValue`.
81
82    Prints:
83        * `"parsed: OK 2000-01-31"`
84        * `"in-range: OK"`
85    """
86    d = BirthDate("2000-01-31")
87    print("parsed:", d.status.name, d.value)
88    r = RangeValue(d.value, date(1900, 1, 1), date(2100, 1, 1))
89    print("in-range:", r.status.name)
90
91
92if __name__ == "__main__":
93    main()
FORMATS = ['%Y-%m-%d', '%d/%m/%Y', '%d-%b-%Y']
class ToDate(constrained_values.value.TransformationStrategy[str, datetime.date]):
43class ToDate(TransformationStrategy[str, date]):
44    """Transform a string into a `datetime.date` object using multiple formats."""
45
46    def transform(self, value: str) -> Response[date]:
47        """Attempt to parse a date from the input string using known formats.
48
49        Args:
50            value: The input date string.
51
52        Returns:
53            Response[date]:
54                * `status = Status.OK` and the parsed date if successful.
55                * `status = Status.EXCEPTION` and an error message if all formats fail.
56        """
57        v = value.strip()
58        for fmt in FORMATS:
59            try:
60                parsed = datetime.strptime(v, fmt).date()
61            except ValueError:
62                continue  # Try the next format
63            else:
64                return Response(Status.OK, fmt, parsed)
65        return Response(Status.EXCEPTION, f"no matching formats for {v!r}; tried {FORMATS}", None)

Transform a string into a datetime.date object using multiple formats.

def transform(self, value: str) -> constrained_values.Response[datetime.date]:
46    def transform(self, value: str) -> Response[date]:
47        """Attempt to parse a date from the input string using known formats.
48
49        Args:
50            value: The input date string.
51
52        Returns:
53            Response[date]:
54                * `status = Status.OK` and the parsed date if successful.
55                * `status = Status.EXCEPTION` and an error message if all formats fail.
56        """
57        v = value.strip()
58        for fmt in FORMATS:
59            try:
60                parsed = datetime.strptime(v, fmt).date()
61            except ValueError:
62                continue  # Try the next format
63            else:
64                return Response(Status.OK, fmt, parsed)
65        return Response(Status.EXCEPTION, f"no matching formats for {v!r}; tried {FORMATS}", None)

Attempt to parse a date from the input string using known formats.

Arguments:
  • value: The input date string.
Returns:

Response[date]: * status = Status.OK and the parsed date if successful. * status = Status.EXCEPTION and an error message if all formats fail.

class BirthDate(constrained_values.value.ConstrainedValue[datetime.date]):
68class BirthDate(ConstrainedValue[date]):
69    """A constrained value that parses and validates date strings."""
70
71    def get_strategies(self) -> List[PipeLineStrategy]:
72        """Return the transformation pipeline (string → date)."""
73        return [TypeValidationStrategy(str), ToDate()]

A constrained value that parses and validates date strings.

def get_strategies(self) -> List[constrained_values.value.PipeLineStrategy]:
71    def get_strategies(self) -> List[PipeLineStrategy]:
72        """Return the transformation pipeline (string → date)."""
73        return [TypeValidationStrategy(str), ToDate()]

Return the transformation pipeline (string → date).

Inherited Members
constrained_values.value.ConstrainedValue
ConstrainedValue
status
details
value
unwrap
ok
def main() -> None:
76def main() -> None:
77    """Run the date parsing and range validation demonstration.
78
79    Steps:
80        1. Parse a valid date string using `BirthDate`.
81        2. Validate the parsed date against a valid range using `RangeValue`.
82
83    Prints:
84        * `"parsed: OK 2000-01-31"`
85        * `"in-range: OK"`
86    """
87    d = BirthDate("2000-01-31")
88    print("parsed:", d.status.name, d.value)
89    r = RangeValue(d.value, date(1900, 1, 1), date(2100, 1, 1))
90    print("in-range:", r.status.name)

Run the date parsing and range validation demonstration.

Steps:
  1. Parse a valid date string using BirthDate.
  2. Validate the parsed date against a valid range using RangeValue.
Prints:
  • "parsed: OK 2000-01-31"
  • "in-range: OK"