Skip to content

Commit 9bc4c86

Browse files
committed
Document formatting and parsing
1 parent db921b7 commit 9bc4c86

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

src/calendar_duration.rs

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,88 @@ use crate::{expect, try_opt};
5454
/// // Encoding 1½ year as a duration in seconds:
5555
/// let _duration = CalendarDuration::new().with_seconds(548 * 24 * 60 * 60).unwrap();
5656
/// ```
57+
///
58+
/// # Formatting and parsing
59+
///
60+
/// The [`Display`](fmt::Display) implementation will format a `CalendarDuration` to the ISO 8601
61+
/// duration format with designators.
62+
///
63+
/// The [`FromStr`](str::FromStr) implementation currently only supports the same duration with
64+
/// designators format, and not yet the ISO 8601 alternate format that is similar to how dates and
65+
/// times are encoded.
66+
///
67+
/// The designator format always starts with `P` (period), followed by number-designator pairs.
68+
/// First are the pairs for the "nominal" components, then a `T` (time), and then the pairs for the
69+
/// "accurate" components. Any number-designator pair may be missing when zero, as long as there is
70+
/// at least one pair. The last pair may contain a decimal fraction instead of an integer.
71+
///
72+
/// Supported formats:
73+
/// - `Pnn̲Ynn̲Mnn̲DTnn̲Hnn̲Mnn̲S`. Components: `Y` for years, `M` for months, `D` for days, `H` for
74+
/// hours, `M` for minutes, and `S` for seconds.
75+
/// - `Pnn̲W`. The only allowed component is `W` for weeks.
76+
///
77+
/// ```
78+
/// # #[cfg(feature = "alloc")] {
79+
/// use std::str::FromStr;
80+
/// use chrono::CalendarDuration;
81+
///
82+
/// let duration = CalendarDuration::new().with_months(105).with_days(5).with_hms(6, 5, 4).unwrap();
83+
///
84+
/// // Formatting and parsing
85+
/// let formatted = duration.to_string();
86+
/// assert_eq!(formatted, "P8Y9M5DT6H5M4S"); // months and minutes are decomposed
87+
/// assert_eq!(CalendarDuration::from_str(&formatted)?, duration);
88+
/// assert_eq!(formatted.parse(), Ok(duration));
89+
///
90+
/// // Seconds are not decomposed
91+
/// assert_eq!(CalendarDuration::new().with_seconds(123_456).unwrap().to_string(), "PT123456S");
92+
///
93+
/// // Multiple ISO 8601 duration strings can parse to the same `CalendarDate` because we consider
94+
/// // years a shorthand for 12 months, and consider hours a shorthand for 60 minutes.
95+
/// assert_eq!("P105M5DT6H5M4S".parse(), Ok(duration));
96+
/// assert_eq!("P8Y9M5DT6H5M4S".parse(), Ok(duration));
97+
/// assert_eq!("P8Y9M5DT365M4S".parse(), Ok(duration));
98+
///
99+
/// // The weeks format can be parsed, but we consistently format a duration with days.
100+
/// assert_eq!("P5W".parse(), Ok(CalendarDuration::new().with_weeks_and_days(5, 0).unwrap()));
101+
/// assert_eq!("P5W".parse::<CalendarDuration>()?.to_string(), "P35D");
102+
///
103+
/// // Any number-designator pair can be used to encode a duration of zero. We format it as "P0D".
104+
/// assert_eq!(CalendarDuration::new().to_string(), "P0D");
105+
/// assert_eq!("PT0S".parse(), Ok(CalendarDuration::new())); // 0 seconds equals 0 days
106+
///
107+
/// # }
108+
/// # Ok::<(), chrono::ParseError>(())
109+
/// ```
110+
///
111+
/// ## Fractional values
112+
///
113+
/// ISO 8601 optionally allows fractional values, even in places where they are ill-defined. Chrono
114+
/// only supports parsing a fractional value for components that can be encoded in the same base
115+
/// component:
116+
/// - Fractional years will be expressed in months.
117+
/// - Fractional weeks will be expressed in days.
118+
/// - Fractional hours, minutes or seconds will be expressed in minutes, seconds and nanoseconds.
119+
///
120+
/// The ISO 8601 format has no designator for subsecond components but expects them to be specified
121+
/// as a fraction. We format nanoseconds as a fraction of a second without trailing zero's.
122+
///
123+
/// Both `,` and `.` are supported as decimal separators when parsing. Although the comma is
124+
/// preferred by ISO 8601 we use `.` when formatting.
125+
///
126+
/// ```
127+
/// # #[cfg(feature = "alloc")] {
128+
/// # use chrono::CalendarDuration;
129+
/// let duration = CalendarDuration::new().with_hms(0, 3, 5).unwrap().with_millis(330).unwrap();
130+
/// assert_eq!(duration.to_string(), "PT3M5.33S");
131+
/// assert_eq!("PT3M5,33S".parse(), Ok(duration));
132+
///
133+
/// assert_eq!("P12,5Y".parse(), Ok(CalendarDuration::new().with_years_and_months(12, 6).unwrap()));
134+
/// assert_eq!("P1.43W".parse(), Ok(CalendarDuration::new().with_days(10))); // horrible :-)
135+
/// assert_eq!("PT6,25H".parse(), Ok(CalendarDuration::new().with_hms(6, 15, 0).unwrap()));
136+
/// # }
137+
/// # Ok::<(), chrono::ParseError>(())
138+
/// ```
57139
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
58140
pub struct CalendarDuration {
59141
// Components with a nominal duration

0 commit comments

Comments
 (0)