Skip to content

Commit 9bf82fa

Browse files
committed
Fix the output of negative duration
Technically speaking, negative duration is not valid ISO 8601, but we need to print it anyway. If `d` is a positive duration with the output `xxxxxxx`, then the expected output of negative `-d` value is `-xxxxxxx`. I.e. the idea is to print negative durations as positive with a leading minus sign. Closes #18181.
1 parent a34b8de commit 9bf82fa

File tree

1 file changed

+18
-13
lines changed

1 file changed

+18
-13
lines changed

src/libstd/time/duration.rs

+18-13
Original file line numberDiff line numberDiff line change
@@ -317,26 +317,29 @@ impl Div<i32,Duration> for Duration {
317317

318318
impl fmt::Show for Duration {
319319
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
320-
let days = self.num_days();
321-
let secs = self.secs - days * SECS_PER_DAY;
320+
// technically speaking, negative duration is not valid ISO 8601,
321+
// but we need to print it anyway.
322+
let (abs, sign) = if self.secs < 0 { (-self, "-") } else { (*self, "") };
323+
324+
let days = abs.secs / SECS_PER_DAY;
325+
let secs = abs.secs - days * SECS_PER_DAY;
322326
let hasdate = days != 0;
323-
let hastime = (secs != 0 || self.nanos != 0) || !hasdate;
327+
let hastime = (secs != 0 || abs.nanos != 0) || !hasdate;
328+
329+
try!(write!(f, "{}P", sign));
324330

325-
try!(write!(f, "P"));
326331
if hasdate {
327-
// technically speaking the negative part is not the valid ISO 8601,
328-
// but we need to print it anyway.
329332
try!(write!(f, "{}D", days));
330333
}
331334
if hastime {
332-
if self.nanos == 0 {
335+
if abs.nanos == 0 {
333336
try!(write!(f, "T{}S", secs));
334-
} else if self.nanos % NANOS_PER_MILLI == 0 {
335-
try!(write!(f, "T{}.{:03}S", secs, self.nanos / NANOS_PER_MILLI));
336-
} else if self.nanos % NANOS_PER_MICRO == 0 {
337-
try!(write!(f, "T{}.{:06}S", secs, self.nanos / NANOS_PER_MICRO));
337+
} else if abs.nanos % NANOS_PER_MILLI == 0 {
338+
try!(write!(f, "T{}.{:03}S", secs, abs.nanos / NANOS_PER_MILLI));
339+
} else if abs.nanos % NANOS_PER_MICRO == 0 {
340+
try!(write!(f, "T{}.{:06}S", secs, abs.nanos / NANOS_PER_MICRO));
338341
} else {
339-
try!(write!(f, "T{}.{:09}S", secs, self.nanos));
342+
try!(write!(f, "T{}.{:09}S", secs, abs.nanos));
340343
}
341344
}
342345
Ok(())
@@ -540,13 +543,15 @@ mod tests {
540543
let d: Duration = Zero::zero();
541544
assert_eq!(d.to_string(), "PT0S".to_string());
542545
assert_eq!(Duration::days(42).to_string(), "P42D".to_string());
543-
assert_eq!(Duration::days(-42).to_string(), "P-42D".to_string());
546+
assert_eq!(Duration::days(-42).to_string(), "-P42D".to_string());
544547
assert_eq!(Duration::seconds(42).to_string(), "PT42S".to_string());
545548
assert_eq!(Duration::milliseconds(42).to_string(), "PT0.042S".to_string());
546549
assert_eq!(Duration::microseconds(42).to_string(), "PT0.000042S".to_string());
547550
assert_eq!(Duration::nanoseconds(42).to_string(), "PT0.000000042S".to_string());
548551
assert_eq!((Duration::days(7) + Duration::milliseconds(6543)).to_string(),
549552
"P7DT6.543S".to_string());
553+
assert_eq!(Duration::seconds(-86401).to_string(), "-P1DT1S".to_string());
554+
assert_eq!(Duration::nanoseconds(-1).to_string(), "-PT0.000000001S".to_string());
550555

551556
// the format specifier should have no effect on `Duration`
552557
assert_eq!(format!("{:30}", Duration::days(1) + Duration::milliseconds(2345)),

0 commit comments

Comments
 (0)