diff --git a/CHANGELOG.md b/CHANGELOG.md index 06164d59..c32888f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,43 +12,43 @@ - `SystemDateTime` has been removed and merged into `ZonedDateTime` - To create a more consistent and intuitive API, the SystemDateTime class + To create a more consistent and intuitive API, the `SystemDateTime` class has been removed. Its functionality is now fully integrated into an - enhanced ZonedDateTime, which now serves as the single, canonical class + enhanced `ZonedDateTime`, which now serves as the single, canonical class for all timezone-aware datetimes, including those based on the system's local timezone. **Rationale:** - The SystemDateTime class, while useful, created several challenges that + The `SystemDateTime` class, while useful, created several challenges that compromised the library's consistency and predictability: - * Inconsistent Behavior: Methods like replace() and add() on a - SystemDateTime instance would use the current system timezone definition, + * Inconsistent Behavior: Methods like `replace()` and `add()` on a + `SystemDateTime` instance would use the current system timezone definition, not necessarily the one that was active when the instance was created. This could lead to subtle and unpredictable bugs if the system timezone changed during the program's execution. - * API Division: Despite having nearly identical interfaces, SystemDateTime - and ZonedDateTime were not interchangeable. A function expecting a - ZonedDateTime could not accept a SystemDateTime, forcing users to write - more complex code with Union type hints. + * API Division: Despite having nearly identical interfaces, `SystemDateTime` + and `ZonedDateTime` were not interchangeable. A function expecting a + `ZonedDateTime` could not accept a `SystemDateTime`, forcing users to write + more complex code with `Union` type hints. * Maintenance Overhead: Maintaining two parallel APIs for timezone-aware datetimes led to significant code duplication and a higher maintenance burden. This change unifies the API by integrating system timezone support - directly into ZonedDateTime, providing a single, consistent way to handle - all timezone-aware datetimes. The original use cases for SystemDateTime - are fully supported by the improved ZonedDateTime. + directly into `ZonedDateTime`, providing a single, consistent way to handle + all timezone-aware datetimes. The original use cases for `SystemDateTime` + are fully supported by the improved `ZonedDateTime`. This new, unified approach also provides two major benefits: - * Performance: Operations on a ZonedDateTime representing a system time are - now orders of magnitude faster than they were on the old SystemDateTime. - * Cross-Platform Consistency: The new whenever.reset_system_tz() function + * Performance: Operations on a `ZonedDateTime` representing a system time are + now orders of magnitude faster than they were on the old `SystemDateTime`. + * Cross-Platform Consistency: The new `whenever.reset_system_tz()` function provides a reliable, cross-platform way to update the library's view of the system timezone, replacing the previous reliance on the Unix-only - time.tzset(). + `time.tzset()`. **Migration:** - Replace all `SystemDateTime` with `ZonedDateTime` in all type hints. diff --git a/docs/api.rst b/docs/api.rst index 74144571..edaa477d 100644 --- a/docs/api.rst +++ b/docs/api.rst @@ -49,6 +49,7 @@ Concrete classes .. autoclass:: whenever.Instant :members: from_utc, + format_iso, format_rfc2822, parse_rfc2822, add, @@ -63,6 +64,7 @@ Concrete classes .. autoclass:: whenever.PlainDateTime :members: + format_iso, assume_utc, assume_fixed_offset, assume_tz, @@ -78,6 +80,7 @@ Concrete classes .. autoclass:: whenever.OffsetDateTime :members: + format_iso, format_rfc2822, parse_rfc2822, parse_strptime, @@ -86,6 +89,7 @@ Concrete classes .. autoclass:: whenever.ZonedDateTime :members: + format_iso, now_in_system_tz, from_system_tz, tz, diff --git a/docs/overview.rst b/docs/overview.rst index 21d0d779..ba929865 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -673,6 +673,15 @@ parts of the standard to support. ``whenever`` targets the most common and widely-used subset of the standard, while avoiding the more obscure and rarely-used parts, which are often the source of confusion and bugs. +.. note:: + + The ISO formats in ``whenever`` are designed so you can format and parse + them without losing information. + This makes it ideal for JSON serialization and other data interchange formats. + +Parsing +******* + ``whenever``'s :meth:`~whenever._BasicConversions.parse_iso` methods take mostly `after Temporal `_, @@ -696,6 +705,10 @@ namely: - In the duration format, the ``W`` unit may be used alongside other calendar units (``Y``, ``M``, ``D``). + +Formatting +********** + Below are the default string formats you get for calling each type's :meth:`~whenever._BasicConversions.format_iso` method: @@ -711,22 +724,44 @@ Below are the default string formats you get for calling each type's | :class:`~whenever.OffsetDateTime` | ``YYYY-MM-DDTHH:MM:SS±HH:MM`` | +-----------------------------------------+------------------------------------------------+ -Where applicable, the outputs can be customized using the ``unit``, ``basic``, ``sep``, -and ``tz`` keyword arguments. See the method documentation for details. +Where applicable, the outputs can be customized using these parameters: -Example usage: +- ``unit`` controls the smallest unit to include, ranging from ``"hour"`` to ``"nanosecond"``. + The default is ``"auto"``, which includes full precision, but without trailing zeros: ->>> d = OffsetDateTime(2023, 12, 28, 11, 30, offset=+5) ->>> d.format_iso() -'2023-12-28T11:30:00+05:00' ->>> OffsetDateTime.parse_iso('2021-07-13T09:45:00-09:00') -OffsetDateTime("2021-07-13 09:45:00-09:00") + >>> i = Instant.now() + >>> i.format_iso(unit="auto") + '2025-09-28T21:24:17.664328Z' + >>> d.format_iso(unit="minute") + '2025-09-28T21:24Z' + >>> d.format_iso(unit="nanosecond") + '2025-09-28T21:24:17.664328000Z' # fixed number of digits -.. note:: +- ``basic`` controls whether to use the "basic" format (i.e. no date and time separators). + By default, the extended format is used. + + >>> i.format_iso(basic=True) + '20250928T212417.664328Z' + >>> i.format_iso(basic=False) + '2025-09-28T21:24:17.664328Z' + +- ``sep`` controls the separator between the date and time parts. `T` by default, + but a space (``" "``) may be used instead. Other separators may be allowed in the future. + + >>> i.format_iso(sep=" ") + '2025-09-28 21:24:17.664328Z' + +- ``tz`` controls whether to include the IANA timezone identifier in square brackets. + Default is ``"always"`` which will raise an error if there is no timezone identifier + (this may be the case for some system timezones). Use ``"never"`` to omit the timezone identifier, + or ``"auto"`` to include it if available. + + >>> d = ZonedDateTime.now("Europe/Amsterdam") + >>> d.format_iso(tz="auto") + '2025-09-28T23:24:17.664328+02:00[Europe/Amsterdam]' + >>> d.format_iso(tz="never") + '2025-09-28T23:24:17.664328+02:00' - The ISO formats in ``whenever`` are designed so you can format and parse - them without losing information. - This makes it ideal for JSON serialization and other data interchange formats. .. admonition:: Why not support the full ISO 8601 spec? diff --git a/pysrc/whenever/_pywhenever.py b/pysrc/whenever/_pywhenever.py index ba0dd0ef..a54735a0 100644 --- a/pysrc/whenever/_pywhenever.py +++ b/pysrc/whenever/_pywhenever.py @@ -3468,7 +3468,7 @@ def format_iso( basic: bool = False, sep: Literal["T", " "] = "T", ) -> str: - """Convert to the popular ISO format ``YYYY-MM-DDTHH:MM:SSZ`` + """Convert to the ISO 8601 string representation. The inverse of the ``parse_iso()`` method. """ diff --git a/src/docstrings.rs b/src/docstrings.rs index 3f33de4a..bd02ff07 100644 --- a/src/docstrings.rs +++ b/src/docstrings.rs @@ -492,7 +492,7 @@ pub(crate) const INSTANT_FORMAT_ISO: &CStr = c"\ format_iso($self, *, unit='auto', basic=False, sep='T') -- -Convert to the popular ISO format ``YYYY-MM-DDTHH:MM:SSZ`` +Convert to the ISO 8601 string representation. The inverse of the ``parse_iso()`` method. ";