Skip to content

Commit c6293b5

Browse files
committed
Parse duration to hour minute second
1 parent fd0c948 commit c6293b5

File tree

2 files changed

+70
-16
lines changed

2 files changed

+70
-16
lines changed

src/duration.rs

Lines changed: 25 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,22 @@ impl fmt::Display for Duration {
7070
}
7171
}
7272
if self.second != 0 || self.microsecond != 0 {
73-
write!(f, "T{}", self.second)?;
74-
if self.microsecond != 0 {
75-
let s = format!("{:06}", self.microsecond);
76-
write!(f, ".{}", s.trim_end_matches('0'))?;
73+
let (hour, minute, sec) = self.to_hms();
74+
write!(f, "T")?;
75+
if hour != 0 {
76+
write!(f, "{hour}H")?;
77+
}
78+
if minute != 0 {
79+
write!(f, "{minute}M")?;
80+
}
81+
if sec != 0 || self.microsecond != 0 {
82+
write!(f, "{sec}")?;
83+
if self.microsecond != 0 {
84+
let s = format!("{:06}", self.microsecond);
85+
write!(f, ".{}", s.trim_end_matches('0'))?;
86+
}
87+
write!(f, "S")?;
7788
}
78-
write!(f, "S")?;
7989
}
8090
if self.second == 0 && self.microsecond == 0 && self.day == 0 {
8191
write!(f, "T0S")?;
@@ -84,6 +94,16 @@ impl fmt::Display for Duration {
8494
}
8595
}
8696

97+
impl Duration {
98+
fn to_hms(&self) -> (u32, u32, u32) {
99+
let hours = self.second / 3600;
100+
let minutes = (self.second % 3600) / 60;
101+
let remaining_seconds = self.second % 60;
102+
103+
(hours, minutes, remaining_seconds)
104+
}
105+
}
106+
87107
impl PartialOrd for Duration {
88108
/// Compare two durations by inequality.
89109
///

tests/main.rs

Lines changed: 45 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -858,7 +858,7 @@ fn test_ok_values_txt() {
858858
let mut success = 0;
859859
for (i, line) in contents.split('\n').enumerate() {
860860
let line_no = i + 1;
861-
if line.starts_with('#') || line.is_empty() {
861+
if line.starts_with('#') || line.is_empty() || line == "\r" {
862862
continue;
863863
} else if line.starts_with("date:") {
864864
let (input, expected_str) = extract_values(line, "date:");
@@ -1053,6 +1053,40 @@ fn duration_new_err() {
10531053
}
10541054
}
10551055

1056+
#[test]
1057+
fn duration_hours() {
1058+
let d = Duration::parse_str("PT5H45M").unwrap();
1059+
assert_eq!(
1060+
d,
1061+
Duration {
1062+
positive: true,
1063+
day: 0,
1064+
second: 20700,
1065+
microsecond: 0
1066+
}
1067+
);
1068+
assert_eq!(d.to_string(), "PT5H45M");
1069+
assert_eq!(d.signed_total_seconds(), (5 * 60 * 60) + (45 * 60));
1070+
assert_eq!(d.signed_microseconds(), 0);
1071+
}
1072+
1073+
#[test]
1074+
fn duration_minutes() {
1075+
let d = Duration::parse_str("PT30M").unwrap();
1076+
assert_eq!(
1077+
d,
1078+
Duration {
1079+
positive: true,
1080+
day: 0,
1081+
second: 1800,
1082+
microsecond: 0
1083+
}
1084+
);
1085+
assert_eq!(d.to_string(), "PT30M");
1086+
assert_eq!(d.signed_total_seconds(), 30 * 60);
1087+
assert_eq!(d.signed_microseconds(), 0);
1088+
}
1089+
10561090
param_tests! {
10571091
Duration,
10581092
duration_too_short1: err => "", TooShort;
@@ -1064,24 +1098,24 @@ param_tests! {
10641098
duration_1m: ok => "P1M", "P30D";
10651099
duration_1_5m: ok => "P1.5M", "P45D";
10661100
duration_1w: ok => "P1W", "P7D";
1067-
duration_1_1w: ok => "P1.1W", "P7DT60480S";
1068-
duration_1_123w: ok => "P1.123W", "P7DT74390.4S";
1101+
duration_1_1w: ok => "P1.1W", "P7DT16H48M";
1102+
duration_1_123w: ok => "P1.123W", "P7DT20H39M50.4S";
10691103
duration_simple_negative: ok => "-P1Y", "-P1Y";
10701104
duration_simple_positive: ok => "+P1Y", "P1Y";
10711105
duration_fraction1: ok => "PT0.555555S", "PT0.555555S";
1072-
duration_fraction2: ok => "P1Y1DT2H0.5S", "P1Y1DT7200.5S";
1106+
duration_fraction2: ok => "P1Y1DT2H0.5S", "P1Y1DT2H0.5S";
10731107
duration_1: ok => "P1DT1S", "P1DT1S";
1074-
duration_all: ok => "P1Y2M3DT4H5M6S", "P1Y63DT14706S";
1108+
duration_all: ok => "P1Y2M3DT4H5M6S", "P1Y63DT4H5M6S";
10751109
duration: err => "PD", DurationInvalidNumber;
10761110
duration: err => "P1DT1MT1S", DurationTRepeated;
10771111
duration: err => "P1DT1.1M1S", DurationInvalidFraction;
10781112
duration: err => "P1DT1X", DurationInvalidTimeUnit;
10791113
duration_invalid_day_unit1: err => "P1X", DurationInvalidDateUnit;
10801114
duration_invalid_day_unit2: err => "P1", DurationInvalidDateUnit;
10811115
duration_time_42s: ok => "00:00:42", "PT42S";
1082-
duration_time_1m: ok => "00:01", "PT60S";
1083-
duration_time_1h_2m_3s: ok => "01:02:03", "PT3723S";
1084-
duration_time_fraction: ok => "00:01:03.123", "PT63.123S";
1116+
duration_time_1m: ok => "00:01", "PT1M";
1117+
duration_time_1h_2m_3s: ok => "01:02:03", "PT1H2M3S";
1118+
duration_time_fraction: ok => "00:01:03.123", "PT1M3.123S";
10851119
duration_time_extra: err => "00:01:03.123x", ExtraCharacters;
10861120
duration_time_timezone: err => "00:01:03x", ExtraCharacters;
10871121
duration_time_invalid_hour: err => "24:01:03", OutOfRangeHour;
@@ -1109,7 +1143,7 @@ param_tests! {
11091143
duration_days_123days: ok => "123days", "P123D";
11101144
duration_days_time: ok => "1 day 00:00:42", "P1DT42S";
11111145
duration_days_time_neg: ok => "-1 day 00:00:42", "-P1DT42S";
1112-
duration_exceeds_day: ok => "PT86500S", "P1DT100S";
1146+
duration_exceeds_day: ok => "PT86500S", "P1DT1M40S";
11131147
duration_days_time_too_short: err => "1 day 00:", TooShort;
11141148
duration_days_time_wrong: err => "1 day 00:xx", InvalidCharMinute;
11151149
duration_days_time_extra: err => "1 day 00:00:00.123 ", InvalidCharTzSign;
@@ -1133,14 +1167,14 @@ fn duration_large() {
11331167
#[test]
11341168
fn duration_limit() {
11351169
let d = Duration::new(true, 999_999_999, 86399, 999_999).unwrap();
1136-
assert_eq!(d.to_string(), "P2739726Y9DT86399.999999S");
1170+
assert_eq!(d.to_string(), "P2739726Y9DT23H59M59.999999S");
11371171

11381172
match Duration::new(true, 999_999_999, 86399, 999_999 + 1) {
11391173
Ok(t) => panic!("unexpectedly valid -> {t:?}"),
11401174
Err(e) => assert_eq!(e, ParseError::DurationDaysTooLarge),
11411175
}
11421176
let d = Duration::new(false, 999_999_999, 86399, 999_999).unwrap();
1143-
assert_eq!(d.to_string(), "-P2739726Y9DT86399.999999S");
1177+
assert_eq!(d.to_string(), "-P2739726Y9DT23H59M59.999999S");
11441178

11451179
match Duration::new(false, 999_999_999, 86399, 999_999 + 1) {
11461180
Ok(t) => panic!("unexpectedly valid -> {t:?}"),

0 commit comments

Comments
 (0)