Skip to content

rfc3339

stac_fastapi.types.rfc3339

rfc3339.

datetime_to_str

datetime_to_str(dt: datetime, timespec: str = 'auto') -> str

Converts a :class:datetime.datetime instance to an ISO8601 string in the RFC 3339, section 5.6 <https://datatracker.ietf.org/doc/html/rfc3339#section-5.6>__ format required by the :stac-spec:STAC Spec <master/item-spec/common-metadata.md#date-and-time>.

Parameters:

  • dt

    The datetime to convert.

  • timespec (str, default: 'auto' ) –

    An optional argument that specifies the number of additional terms of the time to include. Valid options are 'auto', 'hours', 'minutes', 'seconds', 'milliseconds' and 'microseconds'. The default value is 'auto'.

Returns:

  • str ( str ) –

    The ISO8601 (RFC 3339) formatted string representing the datetime.

Source code in stac_fastapi/types/rfc3339.py
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def datetime_to_str(dt: datetime, timespec: str = "auto") -> str:
    """Converts a :class:`datetime.datetime` instance to an ISO8601 string in the
    `RFC 3339, section 5.6
    <https://datatracker.ietf.org/doc/html/rfc3339#section-5.6>`__ format required by
    the :stac-spec:`STAC Spec <master/item-spec/common-metadata.md#date-and-time>`.

    Args:
        dt : The datetime to convert.
        timespec: An optional argument that specifies the number of additional
            terms of the time to include. Valid options are 'auto', 'hours',
            'minutes', 'seconds', 'milliseconds' and 'microseconds'. The default value
            is 'auto'.

    Returns:
        str: The ISO8601 (RFC 3339) formatted string representing the datetime.
    """
    if dt.tzinfo is None:
        dt = dt.replace(tzinfo=timezone.utc)

    timestamp = dt.isoformat(timespec=timespec)
    zulu = "+00:00"
    if timestamp.endswith(zulu):
        timestamp = f"{timestamp[: -len(zulu)]}Z"

    return timestamp

now_in_utc

now_in_utc() -> datetime

Return a datetime value of now with the UTC timezone applied.

Source code in stac_fastapi/types/rfc3339.py
151
152
153
def now_in_utc() -> datetime:
    """Return a datetime value of now with the UTC timezone applied."""
    return datetime.now(timezone.utc)

now_to_rfc3339_str

now_to_rfc3339_str() -> str

Return an RFC 3339 string representing now.

Source code in stac_fastapi/types/rfc3339.py
156
157
158
def now_to_rfc3339_str() -> str:
    """Return an RFC 3339 string representing now."""
    return datetime_to_str(now_in_utc())

parse_single_date

parse_single_date(date_str: str) -> datetime

Parse a single RFC3339 date string into a datetime object.

Parameters:

  • date_str (str) –

    A string representing the date in RFC3339 format.

Returns:

  • datetime ( datetime ) –

    A datetime object parsed from the date_str.

Raises:

  • ValueError

    If the date_str is empty or contains the placeholder '..'.

Source code in stac_fastapi/types/rfc3339.py
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
def parse_single_date(date_str: str) -> datetime:
    """
    Parse a single RFC3339 date string into a datetime object.

    Args:
        date_str (str): A string representing the date in RFC3339 format.

    Returns:
        datetime: A datetime object parsed from the date_str.

    Raises:
        ValueError: If the date_str is empty or contains the placeholder '..'.
    """
    if ".." in date_str or not date_str:
        raise ValueError("Invalid date format.")
    return rfc3339_str_to_datetime(date_str)

rfc3339_str_to_datetime

rfc3339_str_to_datetime(s: str) -> datetime

Convert a string conforming to RFC 3339 to a :class:datetime.datetime.

Uses :meth:iso8601.parse_date under the hood.

Parameters:

  • s (str) ) –

    The string to convert to :class:datetime.datetime.

Returns:

  • str ( datetime ) –

    The datetime represented by the ISO8601 (RFC 3339) formatted string.

Raises:

  • ValueError

    If the string is not a valid RFC 3339 string.

Source code in stac_fastapi/types/rfc3339.py
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
def rfc3339_str_to_datetime(s: str) -> datetime:
    """Convert a string conforming to RFC 3339 to a :class:`datetime.datetime`.

    Uses :meth:`iso8601.parse_date` under the hood.

    Args:
        s (str) : The string to convert to :class:`datetime.datetime`.

    Returns:
        str: The datetime represented by the ISO8601 (RFC 3339) formatted string.

    Raises:
        ValueError: If the string is not a valid RFC 3339 string.
    """
    # Uppercase the string
    s = s.upper()

    # Match against RFC3339 regex.
    result = re.match(RFC33339_PATTERN, s)
    if not result:
        raise ValueError("Invalid RFC3339 datetime.")

    # Parse with pyiso8601
    return iso8601.parse_date(s)

str_to_interval

str_to_interval(interval: Optional[str]) -> Optional[DateTimeType]

Extract a single datetime object or a tuple of datetime objects from an interval string defined by the OGC API. The interval can either be a single datetime or a range with start and end datetime.

Parameters:

  • interval (Optional[str]) –

    The interval string to convert to datetime objects,

Returns:

  • Optional[DateTimeType]

    Optional[DateTimeType]: A single datetime.datetime object, a tuple of

  • Optional[DateTimeType]

    datetime.datetime objects, or None if input is None.

Raises:

  • HTTPException

    If the string is not valid for various reasons such as being empty,

Source code in stac_fastapi/types/rfc3339.py
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
def str_to_interval(interval: Optional[str]) -> Optional[DateTimeType]:
    """
    Extract a single datetime object or a tuple of datetime objects from an
    interval string defined by the OGC API. The interval can either be a
    single datetime or a range with start and end datetime.

    Args:
        interval (Optional[str]): The interval string to convert to datetime objects,
        or None if no datetime is specified.

    Returns:
        Optional[DateTimeType]: A single datetime.datetime object, a tuple of
        datetime.datetime objects, or None if input is None.

    Raises:
        HTTPException: If the string is not valid for various reasons such as being empty,
        having more than one slash, or if date formats are invalid.
    """
    if interval is None:
        return None

    if not interval:
        raise HTTPException(status_code=400, detail="Empty interval string is invalid.")

    values = interval.split("/")
    if len(values) > 2:
        raise HTTPException(
            status_code=400,
            detail="Interval string contains more than one forward slash.",
        )

    try:
        start = parse_single_date(values[0]) if values[0] not in ["..", ""] else None
        if len(values) == 1:
            return start

        end = (
            parse_single_date(values[1])
            if len(values) > 1 and values[1] not in ["..", ""]
            else None
        )
    except (ValueError, iso8601.ParseError) as e:
        raise HTTPException(status_code=400, detail=str(e))

    if start is None and end is None:
        raise HTTPException(
            status_code=400, detail="Double open-ended intervals are not allowed."
        )
    if start is not None and end is not None and start > end:
        raise HTTPException(
            status_code=400, detail="Start datetime cannot be before end datetime."
        )

    return start, end  # type: ignore