1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
#[cfg(feature = "parse")]
mod tests {
use deep_time::{Lang, TSpan};
fn assert_duration(input: &str, expected_millis: i64) {
let trimmed = input.trim();
let dur = TSpan::from_str(trimmed, Lang::default())
.unwrap_or_else(|e| panic!("Failed '{}': {}", input, e));
let actual_millis = dur.to_ms() as i64;
assert_eq!(actual_millis, expected_millis, "Input: '{}'", input);
}
#[test]
fn duration_comprehensive() {
let cases: Vec<(&str, i64)> = vec![
// === Legacy / basic ===
("0", 0),
("5000", 5000),
("86400000", 86400000),
("-250", -250),
// === ISO 8601 ===
("PT2H30M", 9000000),
("P1DT12H", 129600000),
("P3D", 259200000),
("P2W", 1209600000),
// ("PT1.5H", 5400000),
// ("P1Y", 31_557_600_000),
// ("P6M", 15778800000),
("-PT2H30M", -9000000),
("PT1H30M45S", 5445000),
("PT999.999999999S", 999999),
// === Common formats ===
("5sec", 5000),
("1hr", 3600000),
("30min", 1800000),
("2days", 172800000),
("1wk", 604800000),
("1 hour", 3600000),
("2 days", 172800000),
("1hr 30min", 5400000),
("2 hours 30 minutes", 9000000),
("1 day and 2 hours", 93600000),
("1.5 hours", 5400000),
(".5hr", 1800000),
("0hr", 0),
("0 days", 0),
("and 5 minutes", 300000),
("1 day, 2 hours", 93600000),
("1mo", 2629800000),
// === Comma as thousands separator (English style) ===
("1,000 days", 86400000000), // 1000 days
("2,500,000 seconds", 2500000000), // 2,500,000 s = 2.5 billion ms
("10,000 minutes", 600000000), // 10,000 min
("1,234,567 milliseconds", 1234567),
("100,000,000 nanoseconds", 100),
("-1,500 seconds", -1500000),
// === Decimal comma still works exactly as before (no regression) ===
("1.5 hours", 5400000), // 1.5 hours
("123.45 minutes", 7407000), // 123.45 min
("0.5 seconds", 500),
("2.75 days", 237600000),
("999.999999999 seconds", 999999),
// === Mixed thousands + decimal ===
("1,234.5 seconds", 1234500),
("10,000.75 hours", 36002700000),
("1,234,567.89 milliseconds", 1234567),
// === Edge cases for the thousands-comma heuristic ===
("1.23 seconds", 1230), // comma = decimal (1.23 s)
("1,234 seconds", 1234000), // comma = thousands (1,234 s)
("1,000,000,000 seconds", 1000000000000),
("1,000.0secs", 1000000),
("0.0005 hours", 1800),
(".5hr", 1800000), // accepted as 0.5 h (consistent with .5h)
// === Core "1d ,5h" style quirks (comma decimal + spaces in every possible spot) ===
("1d .5hr", 88_200_000),
("1d 5hr", 104_400_000),
("1d 5hr", 104_400_000),
("1d, 5hr", 104_400_000),
("1 day,5 hours", 104_400_000),
("1 day .5 hours", 88_200_000),
("1 day, 5 hours", 104_400_000),
("1 day , 5 hours", 104_400_000),
(" 1d , 5hr ", 104_400_000),
("1d .5 hours", 88_200_000),
// === Decimal comma with "and" and mixed separators ===
("1 day and .5hr", 88_200_000),
("1d and 0.5 hours", 88_200_000),
("1 day, and .75hr", 89_100_000),
// === Other quirky decimal commas ===
(".5hr", 1_800_000),
(".75 days", 64_800_000),
("0.5days", 43_200_000),
("2.5 hours", 9_000_000),
("30.5 minutes", 1_830_000),
("5min,30.5sec", 330_500),
("1hr,30.5min", 5_430_000),
// === Thousands comma vs decimal comma ===
("1,234 seconds", 1_234_000),
("1,234,567 milliseconds", 1_234_567), // should be treated as integer + ms unit
// === Mixed separators, full words, abbreviations ===
("1 day, 2 hours, 30 minutes", 95_400_000),
("2 hours, 15 minutes and 30 seconds", 8_130_000),
("1day and 2hr 30min", 95_400_000),
// === Negative, positive sign, leading zero quirks ===
("-1day .5hr", -88_200_000),
("+1d,5hr", 104_400_000),
("-1d,5hr", -104_400_000),
("-0.5 hours", -1_800_000),
// === Edge-case whitespace and punctuation combos ===
("1day and .5hr", 88_200_000),
(" .25day and 3 hours ", 32_400_000),
("1.5 days, and 30.5m", 131_430_000),
("1hr 30.5min 20sec", 5_450_000),
// === ADDED: More comprehensive edge cases (concatenated components, heavy whitespace, multiple fractions, etc.) ===
("2day5hr", 190_800_000), // concatenated shorthand: 2d + 5h
("1hr30min", 5_400_000), // concatenated shorthand: 1h + 30m
(" .5 seconds", 500), // leading decimal comma + whitespace
("- .25day", -21_600_000), // negative leading decimal comma
("+ .75 hours", 2_700_000), // positive leading decimal comma
("1.5day 2.75hr", 139_500_000), // 1.5d + 2.75h
("1.5hr 30.25min", 7_215_000), // 1.5h + 30.25m
("0.5day, 0.25hr, 15.5min", 45_030_000), // multiple fractional components anywhere
("1,234.567 seconds and .5 minutes", 1_264_567), // thousands + decimal comma + "and"
(" .5 days and 10.25 minutes ", 43_815_000), // heavy whitespace around leading decimal
("- .8day", -69_120_000), // negative leading decimal comma (different fraction)
("and .75 hours", 2_700_000), // "and" + leading decimal comma
("999,999,999 milliseconds", 999_999_999), // large thousands + unit
("1,000,000,000,000 nanoseconds", 1_000_000), // 1 trillion ns = exactly 1 second
("1day ,and 30min", 88_200_000), // decimal comma right before "and"
("2hr,30min", 9_000_000), // list-separator comma (no space before)
(" .999 days", 86_313_600), // leading decimal close to 1.0
("1 day and .25 hours", 87_300_000), // 1d + 0.25h
("1day , .5hr", 88_200_000),
("1day 5hr ,", 104_400_000),
(".5hr ,", 1_800_000),
("1hr2min3sec", 3_723_000),
("1 day and", 86_400_000),
// ("P1Y2M3DT4.5H", 37_092_600_000),
("1_000_000_000_000 nanoseconds", 1_000_000),
(
"1 day, 5.5 hours, 30 minutes, 30 seconds, and 500 microseconds",
108_030_000,
),
("5 seconds", 5000),
("2 minutes", 120000),
("1.5 hours", 5400000),
("3 days", 259200000),
// Unit-first (new foreign-language support)
("hours 3", 10800000),
("days 5", 432000000),
("minutes 45", 2700000),
// Scientific notation (e) – positive exponent
("1e3 seconds", 1000000),
("2.5e3 ms", 2500), // 2500 milliseconds
("1.5e4 milliseconds", 15000),
// Scientific notation (e) – negative exponent + decimal
("1.5e-2 seconds", 15), // 0.015 s = 15 ms
("5e-3 hours", 18000), // 0.005 h = 18 s = 18000 ms
// Negative durations with e
("-2e3 milliseconds", -2000),
("-4e1 minutes", -2400000), // -40 minutes
// Mixed: unit-first + e notation
("seconds 1.23e4", 12300000), // 12300 seconds
("hours 2.5e1", 90000000), // 25 hours
// Combined units (still works with new logic)
("1 hour 30 minutes", 5400000),
("2.5e2 seconds", 250000),
];
for (input, expected) in cases {
assert_duration(input, expected);
}
}
}