1use crate::{
2 fmt::{
3 util::{DecimalFormatter, FractionalFormatter},
4 Write, WriteExt,
5 },
6 Error, SignedDuration, Span, Unit,
7};
8
9const SECS_PER_HOUR: u64 = MINS_PER_HOUR * SECS_PER_MIN;
10const SECS_PER_MIN: u64 = 60;
11const MINS_PER_HOUR: u64 = 60;
12const NANOS_PER_HOUR: u128 =
13 (SECS_PER_MIN * MINS_PER_HOUR * NANOS_PER_SEC) as u128;
14const NANOS_PER_MIN: u128 = (SECS_PER_MIN * NANOS_PER_SEC) as u128;
15const NANOS_PER_SEC: u64 = 1_000_000_000;
16const NANOS_PER_MILLI: u32 = 1_000_000;
17const NANOS_PER_MICRO: u32 = 1_000;
18
19#[derive(Clone, Copy, Debug)]
45#[non_exhaustive]
46pub enum Designator {
47 Verbose,
50 Short,
53 Compact,
58 HumanTime,
85}
86
87#[derive(Clone, Copy, Debug)]
130#[non_exhaustive]
131pub enum Spacing {
132 None,
139 BetweenUnits,
144 BetweenUnitsAndDesignators,
150}
151
152impl Spacing {
153 fn between_units(self) -> &'static str {
154 match self {
155 Spacing::None => "",
156 Spacing::BetweenUnits => " ",
157 Spacing::BetweenUnitsAndDesignators => " ",
158 }
159 }
160
161 fn between_units_and_designators(self) -> &'static str {
162 match self {
163 Spacing::None => "",
164 Spacing::BetweenUnits => "",
165 Spacing::BetweenUnitsAndDesignators => " ",
166 }
167 }
168}
169
170#[derive(Clone, Copy, Debug)]
193#[non_exhaustive]
194pub enum Direction {
195 Auto,
207 Sign,
211 ForceSign,
215 Suffix,
219}
220
221impl Direction {
222 fn sign(
228 self,
229 printer: &SpanPrinter,
230 has_calendar: bool,
231 signum: i8,
232 ) -> Option<DirectionSign> {
233 match self {
234 Direction::Auto => match printer.spacing {
235 Spacing::None => {
236 if signum < 0 {
237 Some(DirectionSign::Prefix("-"))
238 } else {
239 None
240 }
241 }
242 Spacing::BetweenUnits
243 | Spacing::BetweenUnitsAndDesignators => {
244 if signum < 0 {
245 if printer.hms && !has_calendar {
246 Some(DirectionSign::Prefix("-"))
247 } else {
248 Some(DirectionSign::Suffix(" ago"))
249 }
250 } else {
251 None
252 }
253 }
254 },
255 Direction::Sign => {
256 if signum < 0 {
257 Some(DirectionSign::Prefix("-"))
258 } else {
259 None
260 }
261 }
262 Direction::ForceSign => {
263 Some(DirectionSign::Prefix(if signum < 0 { "-" } else { "+" }))
264 }
265 Direction::Suffix => {
266 if signum < 0 {
267 Some(DirectionSign::Suffix(" ago"))
268 } else {
269 None
270 }
271 }
272 }
273 }
274}
275
276#[derive(Clone, Copy, Debug)]
278enum DirectionSign {
279 Prefix(&'static str),
280 Suffix(&'static str),
281}
282
283#[derive(Clone, Copy, Debug)]
317#[non_exhaustive]
318pub enum FractionalUnit {
319 Hour,
324 Minute,
329 Second,
331 Millisecond,
333 Microsecond,
335}
336
337impl From<FractionalUnit> for Unit {
338 fn from(u: FractionalUnit) -> Unit {
339 match u {
340 FractionalUnit::Hour => Unit::Hour,
341 FractionalUnit::Minute => Unit::Minute,
342 FractionalUnit::Second => Unit::Second,
343 FractionalUnit::Millisecond => Unit::Millisecond,
344 FractionalUnit::Microsecond => Unit::Microsecond,
345 }
346 }
347}
348
349#[derive(Clone, Debug)]
456pub struct SpanPrinter {
457 designator: Designator,
458 spacing: Spacing,
459 direction: Direction,
460 fractional: Option<FractionalUnit>,
461 comma_after_designator: bool,
462 hms: bool,
463 padding: Option<u8>,
464 precision: Option<u8>,
465 zero_unit: Unit,
466}
467
468impl SpanPrinter {
469 #[inline]
491 pub const fn new() -> SpanPrinter {
492 SpanPrinter {
493 designator: Designator::Compact,
494 spacing: Spacing::BetweenUnits,
495 direction: Direction::Auto,
496 fractional: None,
497 comma_after_designator: false,
498 hms: false,
499 padding: None,
500 precision: None,
501 zero_unit: Unit::Second,
502 }
503 }
504
505 #[inline]
534 pub const fn designator(self, designator: Designator) -> SpanPrinter {
535 SpanPrinter { designator, ..self }
536 }
537
538 #[inline]
598 pub const fn spacing(self, spacing: Spacing) -> SpanPrinter {
599 SpanPrinter { spacing, ..self }
600 }
601
602 #[inline]
625 pub const fn direction(self, direction: Direction) -> SpanPrinter {
626 SpanPrinter { direction, ..self }
627 }
628
629 #[inline]
679 pub const fn fractional(
680 self,
681 unit: Option<FractionalUnit>,
682 ) -> SpanPrinter {
683 SpanPrinter { fractional: unit, ..self }
684 }
685
686 #[inline]
707 pub const fn comma_after_designator(self, yes: bool) -> SpanPrinter {
708 SpanPrinter { comma_after_designator: yes, ..self }
709 }
710
711 #[inline]
810 pub const fn hours_minutes_seconds(self, yes: bool) -> SpanPrinter {
811 SpanPrinter { hms: yes, ..self }
812 }
813
814 #[inline]
855 pub const fn padding(self, digits: u8) -> SpanPrinter {
856 SpanPrinter { padding: Some(digits), ..self }
857 }
858
859 #[inline]
908 pub const fn precision(self, precision: Option<u8>) -> SpanPrinter {
909 SpanPrinter { precision, ..self }
910 }
911
912 #[inline]
967 pub const fn zero_unit(self, unit: Unit) -> SpanPrinter {
968 SpanPrinter { zero_unit: unit, ..self }
969 }
970
971 #[cfg(any(test, feature = "alloc"))]
987 pub fn span_to_string(&self, span: &Span) -> alloc::string::String {
988 let mut buf = alloc::string::String::with_capacity(4);
989 self.print_span(span, &mut buf).unwrap();
991 buf
992 }
993
994 #[cfg(any(test, feature = "alloc"))]
1028 pub fn duration_to_string(
1029 &self,
1030 duration: &SignedDuration,
1031 ) -> alloc::string::String {
1032 let mut buf = alloc::string::String::with_capacity(4);
1033 self.print_duration(duration, &mut buf).unwrap();
1035 buf
1036 }
1037
1038 #[cfg(any(test, feature = "alloc"))]
1071 pub fn unsigned_duration_to_string(
1072 &self,
1073 duration: &core::time::Duration,
1074 ) -> alloc::string::String {
1075 let mut buf = alloc::string::String::with_capacity(4);
1076 self.print_unsigned_duration(duration, &mut buf).unwrap();
1078 buf
1079 }
1080
1081 pub fn print_span<W: Write>(
1105 &self,
1106 span: &Span,
1107 wtr: W,
1108 ) -> Result<(), Error> {
1109 if self.hms {
1110 return self.print_span_hms(span, wtr);
1111 }
1112 self.print_span_designators(span, wtr)
1113 }
1114
1115 pub fn print_duration<W: Write>(
1148 &self,
1149 duration: &SignedDuration,
1150 wtr: W,
1151 ) -> Result<(), Error> {
1152 if self.hms {
1153 return self.print_signed_duration_hms(duration, wtr);
1154 }
1155 self.print_signed_duration_designators(duration, wtr)
1156 }
1157
1158 pub fn print_unsigned_duration<W: Write>(
1188 &self,
1189 duration: &core::time::Duration,
1190 wtr: W,
1191 ) -> Result<(), Error> {
1192 if self.hms {
1193 return self.print_unsigned_duration_hms(duration, wtr);
1194 }
1195 self.print_unsigned_duration_designators(duration, wtr)
1196 }
1197
1198 fn print_span_designators<W: Write>(
1199 &self,
1200 span: &Span,
1201 mut wtr: W,
1202 ) -> Result<(), Error> {
1203 let mut wtr =
1204 DesignatorWriter::new(self, &mut wtr, false, span.signum());
1205 wtr.maybe_write_prefix_sign()?;
1206 match self.fractional {
1207 None => {
1208 self.print_span_designators_non_fraction(span, &mut wtr)?;
1209 }
1210 Some(unit) => {
1211 self.print_span_designators_fractional(span, unit, &mut wtr)?;
1212 }
1213 }
1214 wtr.maybe_write_zero()?;
1215 wtr.maybe_write_suffix_sign()?;
1216 Ok(())
1217 }
1218
1219 fn print_span_designators_non_fraction<'p, 'w, W: Write>(
1220 &self,
1221 span: &Span,
1222 wtr: &mut DesignatorWriter<'p, 'w, W>,
1223 ) -> Result<(), Error> {
1224 let span = span.abs();
1225 if span.get_years() != 0 {
1226 wtr.write(Unit::Year, span.get_years().unsigned_abs())?;
1227 }
1228 if span.get_months() != 0 {
1229 wtr.write(Unit::Month, span.get_months().unsigned_abs())?;
1230 }
1231 if span.get_weeks() != 0 {
1232 wtr.write(Unit::Week, span.get_weeks().unsigned_abs())?;
1233 }
1234 if span.get_days() != 0 {
1235 wtr.write(Unit::Day, span.get_days().unsigned_abs())?;
1236 }
1237 if span.get_hours() != 0 {
1238 wtr.write(Unit::Hour, span.get_hours().unsigned_abs())?;
1239 }
1240 if span.get_minutes() != 0 {
1241 wtr.write(Unit::Minute, span.get_minutes().unsigned_abs())?;
1242 }
1243 if span.get_seconds() != 0 {
1244 wtr.write(Unit::Second, span.get_seconds().unsigned_abs())?;
1245 }
1246 if span.get_milliseconds() != 0 {
1247 wtr.write(
1248 Unit::Millisecond,
1249 span.get_milliseconds().unsigned_abs(),
1250 )?;
1251 }
1252 if span.get_microseconds() != 0 {
1253 wtr.write(
1254 Unit::Microsecond,
1255 span.get_microseconds().unsigned_abs(),
1256 )?;
1257 }
1258 if span.get_nanoseconds() != 0 {
1259 wtr.write(
1260 Unit::Nanosecond,
1261 span.get_nanoseconds().unsigned_abs(),
1262 )?;
1263 }
1264 Ok(())
1265 }
1266
1267 #[inline(never)]
1268 fn print_span_designators_fractional<'p, 'w, W: Write>(
1269 &self,
1270 span: &Span,
1271 unit: FractionalUnit,
1272 wtr: &mut DesignatorWriter<'p, 'w, W>,
1273 ) -> Result<(), Error> {
1274 let split_at = Unit::from(unit).next().unwrap();
1277 let non_fractional = span.without_lower(split_at);
1278 let fractional = span.only_lower(split_at);
1279 self.print_span_designators_non_fraction(&non_fractional, wtr)?;
1280 wtr.write_fractional_duration(
1281 unit,
1282 &fractional.to_duration_invariant().unsigned_abs(),
1283 )?;
1284 Ok(())
1285 }
1286
1287 fn print_span_hms<W: Write>(
1288 &self,
1289 span: &Span,
1290 mut wtr: W,
1291 ) -> Result<(), Error> {
1292 let span_cal = span.only_calendar();
1293 let mut span_time = span.only_time();
1294 let has_cal = !span_cal.is_zero();
1295
1296 let mut wtr =
1297 DesignatorWriter::new(self, &mut wtr, has_cal, span.signum());
1298 wtr.maybe_write_prefix_sign()?;
1299 if has_cal {
1300 self.print_span_designators_non_fraction(&span_cal, &mut wtr)?;
1301 wtr.finish_preceding()?;
1302 if matches!(self.spacing, Spacing::None) {
1307 wtr.wtr.write_str(" ")?;
1308 }
1309 }
1310 span_time = span_time.abs();
1311
1312 let fmtint =
1313 DecimalFormatter::new().padding(self.padding.unwrap_or(2));
1314 let fmtfraction = FractionalFormatter::new().precision(self.precision);
1315 wtr.wtr.write_int(&fmtint, span_time.get_hours_ranged().get())?;
1316 wtr.wtr.write_str(":")?;
1317 wtr.wtr.write_int(&fmtint, span_time.get_minutes_ranged().get())?;
1318 wtr.wtr.write_str(":")?;
1319 let fp = FractionalPrinter::from_span(
1320 &span_time.only_lower(Unit::Minute),
1321 FractionalUnit::Second,
1322 fmtint,
1323 fmtfraction,
1324 );
1325 fp.print(&mut wtr.wtr)?;
1326 wtr.maybe_write_suffix_sign()?;
1327 Ok(())
1328 }
1329
1330 fn print_signed_duration_designators<W: Write>(
1331 &self,
1332 dur: &SignedDuration,
1333 mut wtr: W,
1334 ) -> Result<(), Error> {
1335 let mut wtr =
1336 DesignatorWriter::new(self, &mut wtr, false, dur.signum());
1337 wtr.maybe_write_prefix_sign()?;
1338 self.print_duration_designators(&dur.unsigned_abs(), &mut wtr)?;
1339 wtr.maybe_write_zero()?;
1340 wtr.maybe_write_suffix_sign()?;
1341 Ok(())
1342 }
1343
1344 fn print_unsigned_duration_designators<W: Write>(
1345 &self,
1346 dur: &core::time::Duration,
1347 mut wtr: W,
1348 ) -> Result<(), Error> {
1349 let mut wtr = DesignatorWriter::new(self, &mut wtr, false, 1);
1350 wtr.maybe_write_prefix_sign()?;
1351 self.print_duration_designators(dur, &mut wtr)?;
1352 wtr.maybe_write_zero()?;
1353 Ok(())
1354 }
1355
1356 fn print_duration_designators<W: Write>(
1357 &self,
1358 dur: &core::time::Duration,
1359 wtr: &mut DesignatorWriter<W>,
1360 ) -> Result<(), Error> {
1361 match self.fractional {
1362 None => {
1363 let mut secs = dur.as_secs();
1364 wtr.write(Unit::Hour, secs / SECS_PER_HOUR)?;
1365 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1366 wtr.write(Unit::Minute, secs / SECS_PER_MIN)?;
1367 wtr.write(Unit::Second, secs % SECS_PER_MIN)?;
1368 let mut nanos = dur.subsec_nanos();
1369 wtr.write(Unit::Millisecond, nanos / NANOS_PER_MILLI)?;
1370 nanos %= NANOS_PER_MILLI;
1371 wtr.write(Unit::Microsecond, nanos / NANOS_PER_MICRO)?;
1372 wtr.write(Unit::Nanosecond, nanos % NANOS_PER_MICRO)?;
1373 }
1374 Some(FractionalUnit::Hour) => {
1375 wtr.write_fractional_duration(FractionalUnit::Hour, &dur)?;
1376 }
1377 Some(FractionalUnit::Minute) => {
1378 let mut secs = dur.as_secs();
1379 wtr.write(Unit::Hour, secs / SECS_PER_HOUR)?;
1380 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1381
1382 let leftovers =
1383 core::time::Duration::new(secs, dur.subsec_nanos());
1384 wtr.write_fractional_duration(
1385 FractionalUnit::Minute,
1386 &leftovers,
1387 )?;
1388 }
1389 Some(FractionalUnit::Second) => {
1390 let mut secs = dur.as_secs();
1391 wtr.write(Unit::Hour, secs / SECS_PER_HOUR)?;
1392 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1393 wtr.write(Unit::Minute, secs / SECS_PER_MIN)?;
1394 secs %= SECS_PER_MIN;
1395
1396 let leftovers =
1397 core::time::Duration::new(secs, dur.subsec_nanos());
1398 wtr.write_fractional_duration(
1399 FractionalUnit::Second,
1400 &leftovers,
1401 )?;
1402 }
1403 Some(FractionalUnit::Millisecond) => {
1404 let mut secs = dur.as_secs();
1405 wtr.write(Unit::Hour, secs / SECS_PER_HOUR)?;
1406 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1407 wtr.write(Unit::Minute, secs / SECS_PER_MIN)?;
1408 wtr.write(Unit::Second, secs % SECS_PER_MIN)?;
1409
1410 let leftovers =
1411 core::time::Duration::new(0, dur.subsec_nanos());
1412 wtr.write_fractional_duration(
1413 FractionalUnit::Millisecond,
1414 &leftovers,
1415 )?;
1416 }
1417 Some(FractionalUnit::Microsecond) => {
1418 let mut secs = dur.as_secs();
1419 wtr.write(Unit::Hour, secs / SECS_PER_HOUR)?;
1420 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1421 wtr.write(Unit::Minute, secs / SECS_PER_MIN)?;
1422 wtr.write(Unit::Second, secs % SECS_PER_MIN)?;
1423 let mut nanos = dur.subsec_nanos();
1424 wtr.write(Unit::Millisecond, nanos / NANOS_PER_MILLI)?;
1425 nanos %= NANOS_PER_MILLI;
1426
1427 let leftovers = core::time::Duration::new(0, nanos);
1428 wtr.write_fractional_duration(
1429 FractionalUnit::Microsecond,
1430 &leftovers,
1431 )?;
1432 }
1433 }
1434 Ok(())
1435 }
1436
1437 fn print_signed_duration_hms<W: Write>(
1438 &self,
1439 dur: &SignedDuration,
1440 mut wtr: W,
1441 ) -> Result<(), Error> {
1442 if dur.is_negative() {
1443 if !matches!(self.direction, Direction::Suffix) {
1444 wtr.write_str("-")?;
1445 }
1446 } else if let Direction::ForceSign = self.direction {
1447 wtr.write_str("+")?;
1448 }
1449 self.print_duration_hms(&dur.unsigned_abs(), &mut wtr)?;
1450 if dur.is_negative() {
1451 if matches!(self.direction, Direction::Suffix) {
1452 wtr.write_str(" ago")?;
1453 }
1454 }
1455 Ok(())
1456 }
1457
1458 fn print_unsigned_duration_hms<W: Write>(
1459 &self,
1460 dur: &core::time::Duration,
1461 mut wtr: W,
1462 ) -> Result<(), Error> {
1463 if let Direction::ForceSign = self.direction {
1464 wtr.write_str("+")?;
1465 }
1466 self.print_duration_hms(dur, &mut wtr)?;
1467 Ok(())
1468 }
1469
1470 fn print_duration_hms<W: Write>(
1471 &self,
1472 udur: &core::time::Duration,
1473 mut wtr: W,
1474 ) -> Result<(), Error> {
1475 let fmtint =
1482 DecimalFormatter::new().padding(self.padding.unwrap_or(2));
1483 let fmtfraction = FractionalFormatter::new().precision(self.precision);
1484
1485 let mut secs = udur.as_secs();
1486 let hours = secs / (MINS_PER_HOUR * SECS_PER_MIN);
1488 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1489 let minutes = secs / SECS_PER_MIN;
1491 secs = secs % SECS_PER_MIN;
1493
1494 wtr.write_uint(&fmtint, hours)?;
1495 wtr.write_str(":")?;
1496 wtr.write_uint(&fmtint, minutes)?;
1497 wtr.write_str(":")?;
1498 let fp = FractionalPrinter::from_duration(
1499 &core::time::Duration::new(secs, udur.subsec_nanos()),
1501 FractionalUnit::Second,
1502 fmtint,
1503 fmtfraction,
1504 );
1505 fp.print(&mut wtr)?;
1506
1507 Ok(())
1508 }
1509}
1510
1511impl Default for SpanPrinter {
1512 fn default() -> SpanPrinter {
1513 SpanPrinter::new()
1514 }
1515}
1516
1517#[derive(Debug)]
1523struct Designators {
1524 singular: &'static [&'static str],
1525 plural: &'static [&'static str],
1526}
1527
1528impl Designators {
1529 const VERBOSE_SINGULAR: &'static [&'static str] = &[
1530 "nanosecond",
1531 "microsecond",
1532 "millisecond",
1533 "second",
1534 "minute",
1535 "hour",
1536 "day",
1537 "week",
1538 "month",
1539 "year",
1540 ];
1541 const VERBOSE_PLURAL: &'static [&'static str] = &[
1542 "nanoseconds",
1543 "microseconds",
1544 "milliseconds",
1545 "seconds",
1546 "minutes",
1547 "hours",
1548 "days",
1549 "weeks",
1550 "months",
1551 "years",
1552 ];
1553
1554 const SHORT_SINGULAR: &'static [&'static str] =
1555 &["nsec", "µsec", "msec", "sec", "min", "hr", "day", "wk", "mo", "yr"];
1556 const SHORT_PLURAL: &'static [&'static str] = &[
1557 "nsecs", "µsecs", "msecs", "secs", "mins", "hrs", "days", "wks",
1558 "mos", "yrs",
1559 ];
1560
1561 const COMPACT: &'static [&'static str] =
1562 &["ns", "µs", "ms", "s", "m", "h", "d", "w", "mo", "y"];
1563
1564 const HUMAN_TIME_SINGULAR: &'static [&'static str] =
1565 &["ns", "us", "ms", "s", "m", "h", "d", "w", "month", "y"];
1566 const HUMAN_TIME_PLURAL: &'static [&'static str] =
1567 &["ns", "us", "ms", "s", "m", "h", "d", "w", "months", "y"];
1568
1569 fn new(config: Designator) -> Designators {
1570 match config {
1571 Designator::Verbose => Designators {
1572 singular: Designators::VERBOSE_SINGULAR,
1573 plural: Designators::VERBOSE_PLURAL,
1574 },
1575 Designator::Short => Designators {
1576 singular: Designators::SHORT_SINGULAR,
1577 plural: Designators::SHORT_PLURAL,
1578 },
1579 Designator::Compact => Designators {
1580 singular: Designators::COMPACT,
1581 plural: Designators::COMPACT,
1582 },
1583 Designator::HumanTime => Designators {
1584 singular: Designators::HUMAN_TIME_SINGULAR,
1585 plural: Designators::HUMAN_TIME_PLURAL,
1586 },
1587 }
1588 }
1589
1590 fn designator(&self, unit: impl Into<Unit>, plural: bool) -> &'static str {
1591 let unit = unit.into();
1592 let index = unit as usize;
1593 if plural {
1594 self.plural[index]
1595 } else {
1596 self.singular[index]
1597 }
1598 }
1599}
1600
1601#[derive(Debug)]
1607struct DesignatorWriter<'p, 'w, W> {
1608 printer: &'p SpanPrinter,
1609 wtr: &'w mut W,
1610 desig: Designators,
1611 sign: Option<DirectionSign>,
1612 fmtint: DecimalFormatter,
1613 fmtfraction: FractionalFormatter,
1614 written_non_zero_unit: bool,
1615}
1616
1617impl<'p, 'w, W: Write> DesignatorWriter<'p, 'w, W> {
1618 fn new(
1619 printer: &'p SpanPrinter,
1620 wtr: &'w mut W,
1621 has_calendar: bool,
1622 signum: i8,
1623 ) -> DesignatorWriter<'p, 'w, W> {
1624 let desig = Designators::new(printer.designator);
1625 let sign = printer.direction.sign(printer, has_calendar, signum);
1626 let fmtint =
1627 DecimalFormatter::new().padding(printer.padding.unwrap_or(0));
1628 let fmtfraction =
1629 FractionalFormatter::new().precision(printer.precision);
1630 DesignatorWriter {
1631 printer,
1632 wtr,
1633 desig,
1634 sign,
1635 fmtint,
1636 fmtfraction,
1637 written_non_zero_unit: false,
1638 }
1639 }
1640
1641 fn maybe_write_prefix_sign(&mut self) -> Result<(), Error> {
1642 if let Some(DirectionSign::Prefix(sign)) = self.sign {
1643 self.wtr.write_str(sign)?;
1644 }
1645 Ok(())
1646 }
1647
1648 fn maybe_write_suffix_sign(&mut self) -> Result<(), Error> {
1649 if let Some(DirectionSign::Suffix(sign)) = self.sign {
1650 self.wtr.write_str(sign)?;
1651 }
1652 Ok(())
1653 }
1654
1655 fn maybe_write_zero(&mut self) -> Result<(), Error> {
1656 if self.written_non_zero_unit {
1657 return Ok(());
1658 }
1659 let unit = self
1662 .printer
1663 .fractional
1664 .map(Unit::from)
1665 .unwrap_or(self.printer.zero_unit);
1666 self.wtr.write_uint(&self.fmtint, 0u32)?;
1667 self.wtr
1668 .write_str(self.printer.spacing.between_units_and_designators())?;
1669 self.wtr.write_str(self.desig.designator(unit, true))?;
1670 Ok(())
1671 }
1672
1673 fn write(
1674 &mut self,
1675 unit: Unit,
1676 value: impl Into<u64>,
1677 ) -> Result<(), Error> {
1678 let value = value.into();
1679 if value == 0 {
1680 return Ok(());
1681 }
1682 self.finish_preceding()?;
1683 self.written_non_zero_unit = true;
1684 self.wtr.write_uint(&self.fmtint, value)?;
1685 self.wtr
1686 .write_str(self.printer.spacing.between_units_and_designators())?;
1687 self.wtr.write_str(self.desig.designator(unit, value != 1))?;
1688 Ok(())
1689 }
1690
1691 fn write_fractional_duration(
1692 &mut self,
1693 unit: FractionalUnit,
1694 duration: &core::time::Duration,
1695 ) -> Result<(), Error> {
1696 let fp = FractionalPrinter::from_duration(
1697 duration,
1698 unit,
1699 self.fmtint,
1700 self.fmtfraction,
1701 );
1702 if !fp.must_write_digits() {
1703 return Ok(());
1704 }
1705 self.finish_preceding()?;
1706 self.written_non_zero_unit = true;
1707 fp.print(&mut *self.wtr)?;
1708 self.wtr
1709 .write_str(self.printer.spacing.between_units_and_designators())?;
1710 self.wtr.write_str(self.desig.designator(unit, fp.is_plural()))?;
1711 Ok(())
1712 }
1713
1714 fn finish_preceding(&mut self) -> Result<(), Error> {
1715 if self.written_non_zero_unit {
1716 if self.printer.comma_after_designator {
1717 self.wtr.write_str(",")?;
1718 }
1719 self.wtr.write_str(self.printer.spacing.between_units())?;
1720 }
1721 Ok(())
1722 }
1723}
1724
1725struct FractionalPrinter {
1730 integer: u64,
1731 fraction: u32,
1732 fmtint: DecimalFormatter,
1733 fmtfraction: FractionalFormatter,
1734}
1735
1736impl FractionalPrinter {
1737 fn from_span(
1747 span: &Span,
1748 unit: FractionalUnit,
1749 fmtint: DecimalFormatter,
1750 fmtfraction: FractionalFormatter,
1751 ) -> FractionalPrinter {
1752 debug_assert!(span.largest_unit() <= Unit::from(unit));
1753 let dur = span.to_duration_invariant().unsigned_abs();
1754 FractionalPrinter::from_duration(&dur, unit, fmtint, fmtfraction)
1755 }
1756
1757 fn from_duration(
1759 dur: &core::time::Duration,
1760 unit: FractionalUnit,
1761 fmtint: DecimalFormatter,
1762 fmtfraction: FractionalFormatter,
1763 ) -> FractionalPrinter {
1764 match unit {
1765 FractionalUnit::Hour => {
1766 let integer = dur.as_secs() / SECS_PER_HOUR;
1767 let mut fraction = dur.as_nanos() % NANOS_PER_HOUR;
1768 fraction /= u128::from(SECS_PER_HOUR);
1770 let fraction = u32::try_from(fraction).unwrap();
1772 FractionalPrinter { integer, fraction, fmtint, fmtfraction }
1773 }
1774 FractionalUnit::Minute => {
1775 let integer = dur.as_secs() / SECS_PER_MIN;
1776 let mut fraction = dur.as_nanos() % NANOS_PER_MIN;
1777 fraction /= u128::from(SECS_PER_MIN);
1779 let fraction = u32::try_from(fraction).unwrap();
1781 FractionalPrinter { integer, fraction, fmtint, fmtfraction }
1782 }
1783 FractionalUnit::Second => {
1784 let integer = dur.as_secs();
1785 let fraction = u32::from(dur.subsec_nanos());
1786 FractionalPrinter { integer, fraction, fmtint, fmtfraction }
1787 }
1788 FractionalUnit::Millisecond => {
1789 let integer = u64::try_from(dur.as_millis()).unwrap();
1798 let fraction =
1799 u32::from((dur.subsec_nanos() % NANOS_PER_MILLI) * 1_000);
1800 FractionalPrinter { integer, fraction, fmtint, fmtfraction }
1801 }
1802 FractionalUnit::Microsecond => {
1803 let integer = u64::try_from(dur.as_micros()).unwrap();
1812 let fraction = u32::from(
1813 (dur.subsec_nanos() % NANOS_PER_MICRO) * 1_000_000,
1814 );
1815 FractionalPrinter { integer, fraction, fmtint, fmtfraction }
1816 }
1817 }
1818 }
1819
1820 fn is_zero(&self) -> bool {
1822 self.integer == 0 && self.fraction == 0
1823 }
1824
1825 fn is_plural(&self) -> bool {
1828 self.integer != 1
1829 || (self.fraction != 0
1830 && !self.fmtfraction.has_zero_fixed_precision())
1831 }
1832
1833 fn must_write_digits(&self) -> bool {
1840 !self.is_zero() || self.fmtfraction.has_non_zero_fixed_precision()
1841 }
1842
1843 fn print<W: Write>(&self, mut wtr: W) -> Result<(), Error> {
1849 wtr.write_uint(&self.fmtint, self.integer)?;
1850 if self.fmtfraction.will_write_digits(self.fraction) {
1851 wtr.write_str(".")?;
1852 wtr.write_fraction(&self.fmtfraction, self.fraction)?;
1853 }
1854 Ok(())
1855 }
1856}
1857
1858#[cfg(feature = "alloc")]
1859#[cfg(test)]
1860mod tests {
1861 use crate::ToSpan;
1862
1863 use super::*;
1864
1865 #[test]
1866 fn print_span_designator_default() {
1867 let printer = || SpanPrinter::new();
1868 let p = |span| printer().span_to_string(&span);
1869
1870 insta::assert_snapshot!(p(1.second()), @"1s");
1871 insta::assert_snapshot!(p(2.seconds()), @"2s");
1872 insta::assert_snapshot!(p(10.seconds()), @"10s");
1873 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m 40s");
1874
1875 insta::assert_snapshot!(p(1.minute()), @"1m");
1876 insta::assert_snapshot!(p(2.minutes()), @"2m");
1877 insta::assert_snapshot!(p(10.minutes()), @"10m");
1878 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h 40m");
1879
1880 insta::assert_snapshot!(p(1.hour()), @"1h");
1881 insta::assert_snapshot!(p(2.hours()), @"2h");
1882 insta::assert_snapshot!(p(10.hours()), @"10h");
1883 insta::assert_snapshot!(p(100.hours()), @"100h");
1884
1885 insta::assert_snapshot!(
1886 p(1.hour().minutes(1).seconds(1)),
1887 @"1h 1m 1s",
1888 );
1889 insta::assert_snapshot!(
1890 p(2.hours().minutes(2).seconds(2)),
1891 @"2h 2m 2s",
1892 );
1893 insta::assert_snapshot!(
1894 p(10.hours().minutes(10).seconds(10)),
1895 @"10h 10m 10s",
1896 );
1897 insta::assert_snapshot!(
1898 p(100.hours().minutes(100).seconds(100)),
1899 @"100h 100m 100s",
1900 );
1901
1902 insta::assert_snapshot!(p(-1.hour()), @"1h ago");
1903 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1h 30s ago");
1904
1905 insta::assert_snapshot!(
1906 p(1.second().milliseconds(2000)),
1907 @"1s 2000ms",
1908 );
1909 }
1910
1911 #[test]
1912 fn print_span_designator_verbose() {
1913 let printer = || SpanPrinter::new().designator(Designator::Verbose);
1914 let p = |span| printer().span_to_string(&span);
1915
1916 insta::assert_snapshot!(p(1.second()), @"1second");
1917 insta::assert_snapshot!(p(2.seconds()), @"2seconds");
1918 insta::assert_snapshot!(p(10.seconds()), @"10seconds");
1919 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1minute 40seconds");
1920
1921 insta::assert_snapshot!(p(1.minute()), @"1minute");
1922 insta::assert_snapshot!(p(2.minutes()), @"2minutes");
1923 insta::assert_snapshot!(p(10.minutes()), @"10minutes");
1924 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1hour 40minutes");
1925
1926 insta::assert_snapshot!(p(1.hour()), @"1hour");
1927 insta::assert_snapshot!(p(2.hours()), @"2hours");
1928 insta::assert_snapshot!(p(10.hours()), @"10hours");
1929 insta::assert_snapshot!(p(100.hours()), @"100hours");
1930
1931 insta::assert_snapshot!(
1932 p(1.hour().minutes(1).seconds(1)),
1933 @"1hour 1minute 1second",
1934 );
1935 insta::assert_snapshot!(
1936 p(2.hours().minutes(2).seconds(2)),
1937 @"2hours 2minutes 2seconds",
1938 );
1939 insta::assert_snapshot!(
1940 p(10.hours().minutes(10).seconds(10)),
1941 @"10hours 10minutes 10seconds",
1942 );
1943 insta::assert_snapshot!(
1944 p(100.hours().minutes(100).seconds(100)),
1945 @"100hours 100minutes 100seconds",
1946 );
1947
1948 insta::assert_snapshot!(p(-1.hour()), @"1hour ago");
1949 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1hour 30seconds ago");
1950 }
1951
1952 #[test]
1953 fn print_span_designator_short() {
1954 let printer = || SpanPrinter::new().designator(Designator::Short);
1955 let p = |span| printer().span_to_string(&span);
1956
1957 insta::assert_snapshot!(p(1.second()), @"1sec");
1958 insta::assert_snapshot!(p(2.seconds()), @"2secs");
1959 insta::assert_snapshot!(p(10.seconds()), @"10secs");
1960 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1min 40secs");
1961
1962 insta::assert_snapshot!(p(1.minute()), @"1min");
1963 insta::assert_snapshot!(p(2.minutes()), @"2mins");
1964 insta::assert_snapshot!(p(10.minutes()), @"10mins");
1965 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1hr 40mins");
1966
1967 insta::assert_snapshot!(p(1.hour()), @"1hr");
1968 insta::assert_snapshot!(p(2.hours()), @"2hrs");
1969 insta::assert_snapshot!(p(10.hours()), @"10hrs");
1970 insta::assert_snapshot!(p(100.hours()), @"100hrs");
1971
1972 insta::assert_snapshot!(
1973 p(1.hour().minutes(1).seconds(1)),
1974 @"1hr 1min 1sec",
1975 );
1976 insta::assert_snapshot!(
1977 p(2.hours().minutes(2).seconds(2)),
1978 @"2hrs 2mins 2secs",
1979 );
1980 insta::assert_snapshot!(
1981 p(10.hours().minutes(10).seconds(10)),
1982 @"10hrs 10mins 10secs",
1983 );
1984 insta::assert_snapshot!(
1985 p(100.hours().minutes(100).seconds(100)),
1986 @"100hrs 100mins 100secs",
1987 );
1988
1989 insta::assert_snapshot!(p(-1.hour()), @"1hr ago");
1990 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1hr 30secs ago");
1991 }
1992
1993 #[test]
1994 fn print_span_designator_compact() {
1995 let printer = || SpanPrinter::new().designator(Designator::Compact);
1996 let p = |span| printer().span_to_string(&span);
1997
1998 insta::assert_snapshot!(p(1.second()), @"1s");
1999 insta::assert_snapshot!(p(2.seconds()), @"2s");
2000 insta::assert_snapshot!(p(10.seconds()), @"10s");
2001 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m 40s");
2002
2003 insta::assert_snapshot!(p(1.minute()), @"1m");
2004 insta::assert_snapshot!(p(2.minutes()), @"2m");
2005 insta::assert_snapshot!(p(10.minutes()), @"10m");
2006 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h 40m");
2007
2008 insta::assert_snapshot!(p(1.hour()), @"1h");
2009 insta::assert_snapshot!(p(2.hours()), @"2h");
2010 insta::assert_snapshot!(p(10.hours()), @"10h");
2011 insta::assert_snapshot!(p(100.hours()), @"100h");
2012
2013 insta::assert_snapshot!(
2014 p(1.hour().minutes(1).seconds(1)),
2015 @"1h 1m 1s",
2016 );
2017 insta::assert_snapshot!(
2018 p(2.hours().minutes(2).seconds(2)),
2019 @"2h 2m 2s",
2020 );
2021 insta::assert_snapshot!(
2022 p(10.hours().minutes(10).seconds(10)),
2023 @"10h 10m 10s",
2024 );
2025 insta::assert_snapshot!(
2026 p(100.hours().minutes(100).seconds(100)),
2027 @"100h 100m 100s",
2028 );
2029
2030 insta::assert_snapshot!(p(-1.hour()), @"1h ago");
2031 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1h 30s ago");
2032 }
2033
2034 #[test]
2035 fn print_span_designator_direction_force() {
2036 let printer = || SpanPrinter::new().direction(Direction::ForceSign);
2037 let p = |span| printer().span_to_string(&span);
2038
2039 insta::assert_snapshot!(p(1.second()), @"+1s");
2040 insta::assert_snapshot!(p(2.seconds()), @"+2s");
2041 insta::assert_snapshot!(p(10.seconds()), @"+10s");
2042 insta::assert_snapshot!(p(1.minute().seconds(40)), @"+1m 40s");
2043
2044 insta::assert_snapshot!(p(1.minute()), @"+1m");
2045 insta::assert_snapshot!(p(2.minutes()), @"+2m");
2046 insta::assert_snapshot!(p(10.minutes()), @"+10m");
2047 insta::assert_snapshot!(p(1.hour().minutes(40)), @"+1h 40m");
2048
2049 insta::assert_snapshot!(p(1.hour()), @"+1h");
2050 insta::assert_snapshot!(p(2.hours()), @"+2h");
2051 insta::assert_snapshot!(p(10.hours()), @"+10h");
2052 insta::assert_snapshot!(p(100.hours()), @"+100h");
2053
2054 insta::assert_snapshot!(
2055 p(1.hour().minutes(1).seconds(1)),
2056 @"+1h 1m 1s",
2057 );
2058 insta::assert_snapshot!(
2059 p(2.hours().minutes(2).seconds(2)),
2060 @"+2h 2m 2s",
2061 );
2062 insta::assert_snapshot!(
2063 p(10.hours().minutes(10).seconds(10)),
2064 @"+10h 10m 10s",
2065 );
2066 insta::assert_snapshot!(
2067 p(100.hours().minutes(100).seconds(100)),
2068 @"+100h 100m 100s",
2069 );
2070
2071 insta::assert_snapshot!(p(-1.hour()), @"-1h");
2072 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"-1h 30s");
2073 }
2074
2075 #[test]
2076 fn print_span_designator_padding() {
2077 let printer = || SpanPrinter::new().padding(2);
2078 let p = |span| printer().span_to_string(&span);
2079
2080 insta::assert_snapshot!(p(1.second()), @"01s");
2081 insta::assert_snapshot!(p(2.seconds()), @"02s");
2082 insta::assert_snapshot!(p(10.seconds()), @"10s");
2083 insta::assert_snapshot!(p(1.minute().seconds(40)), @"01m 40s");
2084
2085 insta::assert_snapshot!(p(1.minute()), @"01m");
2086 insta::assert_snapshot!(p(2.minutes()), @"02m");
2087 insta::assert_snapshot!(p(10.minutes()), @"10m");
2088 insta::assert_snapshot!(p(1.hour().minutes(40)), @"01h 40m");
2089
2090 insta::assert_snapshot!(p(1.hour()), @"01h");
2091 insta::assert_snapshot!(p(2.hours()), @"02h");
2092 insta::assert_snapshot!(p(10.hours()), @"10h");
2093 insta::assert_snapshot!(p(100.hours()), @"100h");
2094
2095 insta::assert_snapshot!(
2096 p(1.hour().minutes(1).seconds(1)),
2097 @"01h 01m 01s",
2098 );
2099 insta::assert_snapshot!(
2100 p(2.hours().minutes(2).seconds(2)),
2101 @"02h 02m 02s",
2102 );
2103 insta::assert_snapshot!(
2104 p(10.hours().minutes(10).seconds(10)),
2105 @"10h 10m 10s",
2106 );
2107 insta::assert_snapshot!(
2108 p(100.hours().minutes(100).seconds(100)),
2109 @"100h 100m 100s",
2110 );
2111
2112 insta::assert_snapshot!(p(-1.hour()), @"01h ago");
2113 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"01h 30s ago");
2114 }
2115
2116 #[test]
2117 fn print_span_designator_spacing_none() {
2118 let printer = || SpanPrinter::new().spacing(Spacing::None);
2119 let p = |span| printer().span_to_string(&span);
2120
2121 insta::assert_snapshot!(p(1.second()), @"1s");
2122 insta::assert_snapshot!(p(2.seconds()), @"2s");
2123 insta::assert_snapshot!(p(10.seconds()), @"10s");
2124 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m40s");
2125
2126 insta::assert_snapshot!(p(1.minute()), @"1m");
2127 insta::assert_snapshot!(p(2.minutes()), @"2m");
2128 insta::assert_snapshot!(p(10.minutes()), @"10m");
2129 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h40m");
2130
2131 insta::assert_snapshot!(p(1.hour()), @"1h");
2132 insta::assert_snapshot!(p(2.hours()), @"2h");
2133 insta::assert_snapshot!(p(10.hours()), @"10h");
2134 insta::assert_snapshot!(p(100.hours()), @"100h");
2135
2136 insta::assert_snapshot!(
2137 p(1.hour().minutes(1).seconds(1)),
2138 @"1h1m1s",
2139 );
2140 insta::assert_snapshot!(
2141 p(2.hours().minutes(2).seconds(2)),
2142 @"2h2m2s",
2143 );
2144 insta::assert_snapshot!(
2145 p(10.hours().minutes(10).seconds(10)),
2146 @"10h10m10s",
2147 );
2148 insta::assert_snapshot!(
2149 p(100.hours().minutes(100).seconds(100)),
2150 @"100h100m100s",
2151 );
2152
2153 insta::assert_snapshot!(p(-1.hour()), @"-1h");
2154 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"-1h30s");
2155 }
2156
2157 #[test]
2158 fn print_span_designator_spacing_more() {
2159 let printer =
2160 || SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
2161 let p = |span| printer().span_to_string(&span);
2162
2163 insta::assert_snapshot!(p(1.second()), @"1 s");
2164 insta::assert_snapshot!(p(2.seconds()), @"2 s");
2165 insta::assert_snapshot!(p(10.seconds()), @"10 s");
2166 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1 m 40 s");
2167
2168 insta::assert_snapshot!(p(1.minute()), @"1 m");
2169 insta::assert_snapshot!(p(2.minutes()), @"2 m");
2170 insta::assert_snapshot!(p(10.minutes()), @"10 m");
2171 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1 h 40 m");
2172
2173 insta::assert_snapshot!(p(1.hour()), @"1 h");
2174 insta::assert_snapshot!(p(2.hours()), @"2 h");
2175 insta::assert_snapshot!(p(10.hours()), @"10 h");
2176 insta::assert_snapshot!(p(100.hours()), @"100 h");
2177
2178 insta::assert_snapshot!(
2179 p(1.hour().minutes(1).seconds(1)),
2180 @"1 h 1 m 1 s",
2181 );
2182 insta::assert_snapshot!(
2183 p(2.hours().minutes(2).seconds(2)),
2184 @"2 h 2 m 2 s",
2185 );
2186 insta::assert_snapshot!(
2187 p(10.hours().minutes(10).seconds(10)),
2188 @"10 h 10 m 10 s",
2189 );
2190 insta::assert_snapshot!(
2191 p(100.hours().minutes(100).seconds(100)),
2192 @"100 h 100 m 100 s",
2193 );
2194
2195 insta::assert_snapshot!(p(-1.hour()), @"1 h ago");
2196 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1 h 30 s ago");
2197 }
2198
2199 #[test]
2200 fn print_span_designator_spacing_comma() {
2201 let printer = || {
2202 SpanPrinter::new()
2203 .comma_after_designator(true)
2204 .spacing(Spacing::BetweenUnitsAndDesignators)
2205 };
2206 let p = |span| printer().span_to_string(&span);
2207
2208 insta::assert_snapshot!(p(1.second()), @"1 s");
2209 insta::assert_snapshot!(p(2.seconds()), @"2 s");
2210 insta::assert_snapshot!(p(10.seconds()), @"10 s");
2211 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1 m, 40 s");
2212
2213 insta::assert_snapshot!(p(1.minute()), @"1 m");
2214 insta::assert_snapshot!(p(2.minutes()), @"2 m");
2215 insta::assert_snapshot!(p(10.minutes()), @"10 m");
2216 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1 h, 40 m");
2217
2218 insta::assert_snapshot!(p(1.hour()), @"1 h");
2219 insta::assert_snapshot!(p(2.hours()), @"2 h");
2220 insta::assert_snapshot!(p(10.hours()), @"10 h");
2221 insta::assert_snapshot!(p(100.hours()), @"100 h");
2222
2223 insta::assert_snapshot!(
2224 p(1.hour().minutes(1).seconds(1)),
2225 @"1 h, 1 m, 1 s",
2226 );
2227 insta::assert_snapshot!(
2228 p(2.hours().minutes(2).seconds(2)),
2229 @"2 h, 2 m, 2 s",
2230 );
2231 insta::assert_snapshot!(
2232 p(10.hours().minutes(10).seconds(10)),
2233 @"10 h, 10 m, 10 s",
2234 );
2235 insta::assert_snapshot!(
2236 p(100.hours().minutes(100).seconds(100)),
2237 @"100 h, 100 m, 100 s",
2238 );
2239
2240 insta::assert_snapshot!(p(-1.hour()), @"1 h ago");
2241 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1 h, 30 s ago");
2242 }
2243
2244 #[test]
2245 fn print_span_designator_fractional_hour() {
2246 let printer =
2247 || SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
2248 let p = |span| printer().span_to_string(&span);
2249 let pp = |precision, span| {
2250 printer().precision(Some(precision)).span_to_string(&span)
2251 };
2252
2253 insta::assert_snapshot!(p(1.hour()), @"1h");
2254 insta::assert_snapshot!(pp(0, 1.hour()), @"1h");
2255 insta::assert_snapshot!(pp(1, 1.hour()), @"1.0h");
2256 insta::assert_snapshot!(pp(2, 1.hour()), @"1.00h");
2257
2258 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1.5h");
2259 insta::assert_snapshot!(pp(0, 1.hour().minutes(30)), @"1h");
2260 insta::assert_snapshot!(pp(1, 1.hour().minutes(30)), @"1.5h");
2261 insta::assert_snapshot!(pp(2, 1.hour().minutes(30)), @"1.50h");
2262
2263 insta::assert_snapshot!(p(1.hour().minutes(3)), @"1.05h");
2264 insta::assert_snapshot!(p(1.hour().minutes(3).nanoseconds(1)), @"1.05h");
2265 insta::assert_snapshot!(p(1.second()), @"0.000277777h");
2266 insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"0.000277777h");
2268 insta::assert_snapshot!(p(0.seconds()), @"0h");
2269 insta::assert_snapshot!(p(1.nanosecond()), @"0h");
2271 }
2272
2273 #[test]
2274 fn print_span_designator_fractional_minute() {
2275 let printer =
2276 || SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
2277 let p = |span| printer().span_to_string(&span);
2278 let pp = |precision, span| {
2279 printer().precision(Some(precision)).span_to_string(&span)
2280 };
2281
2282 insta::assert_snapshot!(p(1.hour()), @"1h");
2283 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2284
2285 insta::assert_snapshot!(p(1.minute()), @"1m");
2286 insta::assert_snapshot!(pp(0, 1.minute()), @"1m");
2287 insta::assert_snapshot!(pp(1, 1.minute()), @"1.0m");
2288 insta::assert_snapshot!(pp(2, 1.minute()), @"1.00m");
2289
2290 insta::assert_snapshot!(p(1.minute().seconds(30)), @"1.5m");
2291 insta::assert_snapshot!(pp(0, 1.minute().seconds(30)), @"1m");
2292 insta::assert_snapshot!(pp(1, 1.minute().seconds(30)), @"1.5m");
2293 insta::assert_snapshot!(pp(2, 1.minute().seconds(30)), @"1.50m");
2294
2295 insta::assert_snapshot!(p(1.hour().nanoseconds(1)), @"1h");
2296 insta::assert_snapshot!(p(1.minute().seconds(3)), @"1.05m");
2297 insta::assert_snapshot!(p(1.minute().seconds(3).nanoseconds(1)), @"1.05m");
2298 insta::assert_snapshot!(p(1.second()), @"0.016666666m");
2299 insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"0.016666666m");
2301 insta::assert_snapshot!(p(0.seconds()), @"0m");
2302 insta::assert_snapshot!(p(1.nanosecond()), @"0m");
2304 }
2305
2306 #[test]
2307 fn print_span_designator_fractional_second() {
2308 let printer =
2309 || SpanPrinter::new().fractional(Some(FractionalUnit::Second));
2310 let p = |span| printer().span_to_string(&span);
2311 let pp = |precision, span| {
2312 printer().precision(Some(precision)).span_to_string(&span)
2313 };
2314
2315 insta::assert_snapshot!(p(1.hour()), @"1h");
2316 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2317
2318 insta::assert_snapshot!(p(1.second()), @"1s");
2319 insta::assert_snapshot!(pp(0, 1.second()), @"1s");
2320 insta::assert_snapshot!(pp(1, 1.second()), @"1.0s");
2321 insta::assert_snapshot!(pp(2, 1.second()), @"1.00s");
2322
2323 insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1.5s");
2324 insta::assert_snapshot!(pp(0, 1.second().milliseconds(500)), @"1s");
2325 insta::assert_snapshot!(pp(1, 1.second().milliseconds(500)), @"1.5s");
2326 insta::assert_snapshot!(pp(2, 1.second().milliseconds(500)), @"1.50s");
2327
2328 insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"1.000000001s");
2329 insta::assert_snapshot!(p(1.nanosecond()), @"0.000000001s");
2330 insta::assert_snapshot!(p(0.seconds()), @"0s");
2331
2332 insta::assert_snapshot!(p(1.second().milliseconds(2000)), @"3s");
2333 }
2334
2335 #[test]
2336 fn print_span_designator_fractional_millisecond() {
2337 let printer = || {
2338 SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
2339 };
2340 let p = |span| printer().span_to_string(&span);
2341 let pp = |precision, span| {
2342 printer().precision(Some(precision)).span_to_string(&span)
2343 };
2344
2345 insta::assert_snapshot!(p(1.hour()), @"1h");
2346 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2347 insta::assert_snapshot!(
2348 p(1.hour().minutes(30).seconds(10)),
2349 @"1h 30m 10s",
2350 );
2351
2352 insta::assert_snapshot!(p(1.second()), @"1s");
2353 insta::assert_snapshot!(pp(0, 1.second()), @"1s");
2354 insta::assert_snapshot!(pp(1, 1.second()), @"1s 0.0ms");
2355 insta::assert_snapshot!(pp(2, 1.second()), @"1s 0.00ms");
2356
2357 insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1s 500ms");
2358 insta::assert_snapshot!(
2359 pp(0, 1.second().milliseconds(1).microseconds(500)),
2360 @"1s 1ms",
2361 );
2362 insta::assert_snapshot!(
2363 pp(1, 1.second().milliseconds(1).microseconds(500)),
2364 @"1s 1.5ms",
2365 );
2366 insta::assert_snapshot!(
2367 pp(2, 1.second().milliseconds(1).microseconds(500)),
2368 @"1s 1.50ms",
2369 );
2370
2371 insta::assert_snapshot!(p(1.millisecond().nanoseconds(1)), @"1.000001ms");
2372 insta::assert_snapshot!(p(1.nanosecond()), @"0.000001ms");
2373 insta::assert_snapshot!(p(0.seconds()), @"0ms");
2374 }
2375
2376 #[test]
2377 fn print_span_designator_fractional_microsecond() {
2378 let printer = || {
2379 SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
2380 };
2381 let p = |span| printer().span_to_string(&span);
2382 let pp = |precision, span| {
2383 printer().precision(Some(precision)).span_to_string(&span)
2384 };
2385
2386 insta::assert_snapshot!(p(1.hour()), @"1h");
2387 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2388 insta::assert_snapshot!(
2389 p(1.hour().minutes(30).seconds(10)),
2390 @"1h 30m 10s",
2391 );
2392
2393 insta::assert_snapshot!(p(1.second()), @"1s");
2394 insta::assert_snapshot!(pp(0, 1.second()), @"1s");
2395 insta::assert_snapshot!(pp(1, 1.second()), @"1s 0.0µs");
2396 insta::assert_snapshot!(pp(2, 1.second()), @"1s 0.00µs");
2397
2398 insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1s 500ms");
2399 insta::assert_snapshot!(
2400 pp(0, 1.second().milliseconds(1).microseconds(500)),
2401 @"1s 1ms 500µs",
2402 );
2403 insta::assert_snapshot!(
2404 pp(1, 1.second().milliseconds(1).microseconds(500)),
2405 @"1s 1ms 500.0µs",
2406 );
2407 insta::assert_snapshot!(
2408 pp(2, 1.second().milliseconds(1).microseconds(500)),
2409 @"1s 1ms 500.00µs",
2410 );
2411
2412 insta::assert_snapshot!(
2413 p(1.millisecond().nanoseconds(1)),
2414 @"1ms 0.001µs",
2415 );
2416 insta::assert_snapshot!(p(1.nanosecond()), @"0.001µs");
2417 insta::assert_snapshot!(p(0.second()), @"0µs");
2418 }
2419
2420 #[test]
2421 fn print_signed_duration_designator_default() {
2422 let printer = || SpanPrinter::new();
2423 let p = |secs| {
2424 printer().duration_to_string(&SignedDuration::from_secs(secs))
2425 };
2426
2427 insta::assert_snapshot!(p(1), @"1s");
2428 insta::assert_snapshot!(p(2), @"2s");
2429 insta::assert_snapshot!(p(10), @"10s");
2430 insta::assert_snapshot!(p(100), @"1m 40s");
2431
2432 insta::assert_snapshot!(p(1 * 60), @"1m");
2433 insta::assert_snapshot!(p(2 * 60), @"2m");
2434 insta::assert_snapshot!(p(10 * 60), @"10m");
2435 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
2436
2437 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
2438 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
2439 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2440 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2441
2442 insta::assert_snapshot!(
2443 p(60 * 60 + 60 + 1),
2444 @"1h 1m 1s",
2445 );
2446 insta::assert_snapshot!(
2447 p(2 * 60 * 60 + 2 * 60 + 2),
2448 @"2h 2m 2s",
2449 );
2450 insta::assert_snapshot!(
2451 p(10 * 60 * 60 + 10 * 60 + 10),
2452 @"10h 10m 10s",
2453 );
2454 insta::assert_snapshot!(
2455 p(100 * 60 * 60 + 100 * 60 + 100),
2456 @"101h 41m 40s",
2457 );
2458
2459 insta::assert_snapshot!(p(-1 * 60 * 60), @"1h ago");
2460 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1h 30s ago");
2461 }
2462
2463 #[test]
2464 fn print_signed_duration_designator_verbose() {
2465 let printer = || SpanPrinter::new().designator(Designator::Verbose);
2466 let p = |secs| {
2467 printer().duration_to_string(&SignedDuration::from_secs(secs))
2468 };
2469
2470 insta::assert_snapshot!(p(1), @"1second");
2471 insta::assert_snapshot!(p(2), @"2seconds");
2472 insta::assert_snapshot!(p(10), @"10seconds");
2473 insta::assert_snapshot!(p(100), @"1minute 40seconds");
2474
2475 insta::assert_snapshot!(p(1 * 60), @"1minute");
2476 insta::assert_snapshot!(p(2 * 60), @"2minutes");
2477 insta::assert_snapshot!(p(10 * 60), @"10minutes");
2478 insta::assert_snapshot!(p(100 * 60), @"1hour 40minutes");
2479
2480 insta::assert_snapshot!(p(1 * 60 * 60), @"1hour");
2481 insta::assert_snapshot!(p(2 * 60 * 60), @"2hours");
2482 insta::assert_snapshot!(p(10 * 60 * 60), @"10hours");
2483 insta::assert_snapshot!(p(100 * 60 * 60), @"100hours");
2484
2485 insta::assert_snapshot!(
2486 p(60 * 60 + 60 + 1),
2487 @"1hour 1minute 1second",
2488 );
2489 insta::assert_snapshot!(
2490 p(2 * 60 * 60 + 2 * 60 + 2),
2491 @"2hours 2minutes 2seconds",
2492 );
2493 insta::assert_snapshot!(
2494 p(10 * 60 * 60 + 10 * 60 + 10),
2495 @"10hours 10minutes 10seconds",
2496 );
2497 insta::assert_snapshot!(
2498 p(100 * 60 * 60 + 100 * 60 + 100),
2499 @"101hours 41minutes 40seconds",
2500 );
2501
2502 insta::assert_snapshot!(p(-1 * 60 * 60), @"1hour ago");
2503 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1hour 30seconds ago");
2504 }
2505
2506 #[test]
2507 fn print_signed_duration_designator_short() {
2508 let printer = || SpanPrinter::new().designator(Designator::Short);
2509 let p = |secs| {
2510 printer().duration_to_string(&SignedDuration::from_secs(secs))
2511 };
2512
2513 insta::assert_snapshot!(p(1), @"1sec");
2514 insta::assert_snapshot!(p(2), @"2secs");
2515 insta::assert_snapshot!(p(10), @"10secs");
2516 insta::assert_snapshot!(p(100), @"1min 40secs");
2517
2518 insta::assert_snapshot!(p(1 * 60), @"1min");
2519 insta::assert_snapshot!(p(2 * 60), @"2mins");
2520 insta::assert_snapshot!(p(10 * 60), @"10mins");
2521 insta::assert_snapshot!(p(100 * 60), @"1hr 40mins");
2522
2523 insta::assert_snapshot!(p(1 * 60 * 60), @"1hr");
2524 insta::assert_snapshot!(p(2 * 60 * 60), @"2hrs");
2525 insta::assert_snapshot!(p(10 * 60 * 60), @"10hrs");
2526 insta::assert_snapshot!(p(100 * 60 * 60), @"100hrs");
2527
2528 insta::assert_snapshot!(
2529 p(60 * 60 + 60 + 1),
2530 @"1hr 1min 1sec",
2531 );
2532 insta::assert_snapshot!(
2533 p(2 * 60 * 60 + 2 * 60 + 2),
2534 @"2hrs 2mins 2secs",
2535 );
2536 insta::assert_snapshot!(
2537 p(10 * 60 * 60 + 10 * 60 + 10),
2538 @"10hrs 10mins 10secs",
2539 );
2540 insta::assert_snapshot!(
2541 p(100 * 60 * 60 + 100 * 60 + 100),
2542 @"101hrs 41mins 40secs",
2543 );
2544
2545 insta::assert_snapshot!(p(-1 * 60 * 60), @"1hr ago");
2546 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1hr 30secs ago");
2547 }
2548
2549 #[test]
2550 fn print_signed_duration_designator_compact() {
2551 let printer = || SpanPrinter::new().designator(Designator::Compact);
2552 let p = |secs| {
2553 printer().duration_to_string(&SignedDuration::from_secs(secs))
2554 };
2555
2556 insta::assert_snapshot!(p(1), @"1s");
2557 insta::assert_snapshot!(p(2), @"2s");
2558 insta::assert_snapshot!(p(10), @"10s");
2559 insta::assert_snapshot!(p(100), @"1m 40s");
2560
2561 insta::assert_snapshot!(p(1 * 60), @"1m");
2562 insta::assert_snapshot!(p(2 * 60), @"2m");
2563 insta::assert_snapshot!(p(10 * 60), @"10m");
2564 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
2565
2566 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
2567 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
2568 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2569 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2570
2571 insta::assert_snapshot!(
2572 p(60 * 60 + 60 + 1),
2573 @"1h 1m 1s",
2574 );
2575 insta::assert_snapshot!(
2576 p(2 * 60 * 60 + 2 * 60 + 2),
2577 @"2h 2m 2s",
2578 );
2579 insta::assert_snapshot!(
2580 p(10 * 60 * 60 + 10 * 60 + 10),
2581 @"10h 10m 10s",
2582 );
2583 insta::assert_snapshot!(
2584 p(100 * 60 * 60 + 100 * 60 + 100),
2585 @"101h 41m 40s",
2586 );
2587
2588 insta::assert_snapshot!(p(-1 * 60 * 60), @"1h ago");
2589 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1h 30s ago");
2590 }
2591
2592 #[test]
2593 fn print_signed_duration_designator_direction_force() {
2594 let printer = || SpanPrinter::new().direction(Direction::ForceSign);
2595 let p = |secs| {
2596 printer().duration_to_string(&SignedDuration::from_secs(secs))
2597 };
2598
2599 insta::assert_snapshot!(p(1), @"+1s");
2600 insta::assert_snapshot!(p(2), @"+2s");
2601 insta::assert_snapshot!(p(10), @"+10s");
2602 insta::assert_snapshot!(p(100), @"+1m 40s");
2603
2604 insta::assert_snapshot!(p(1 * 60), @"+1m");
2605 insta::assert_snapshot!(p(2 * 60), @"+2m");
2606 insta::assert_snapshot!(p(10 * 60), @"+10m");
2607 insta::assert_snapshot!(p(100 * 60), @"+1h 40m");
2608
2609 insta::assert_snapshot!(p(1 * 60 * 60), @"+1h");
2610 insta::assert_snapshot!(p(2 * 60 * 60), @"+2h");
2611 insta::assert_snapshot!(p(10 * 60 * 60), @"+10h");
2612 insta::assert_snapshot!(p(100 * 60 * 60), @"+100h");
2613
2614 insta::assert_snapshot!(
2615 p(60 * 60 + 60 + 1),
2616 @"+1h 1m 1s",
2617 );
2618 insta::assert_snapshot!(
2619 p(2 * 60 * 60 + 2 * 60 + 2),
2620 @"+2h 2m 2s",
2621 );
2622 insta::assert_snapshot!(
2623 p(10 * 60 * 60 + 10 * 60 + 10),
2624 @"+10h 10m 10s",
2625 );
2626 insta::assert_snapshot!(
2627 p(100 * 60 * 60 + 100 * 60 + 100),
2628 @"+101h 41m 40s",
2629 );
2630
2631 insta::assert_snapshot!(p(-1 * 60 * 60), @"-1h");
2632 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"-1h 30s");
2633 }
2634
2635 #[test]
2636 fn print_signed_duration_designator_padding() {
2637 let printer = || SpanPrinter::new().padding(2);
2638 let p = |secs| {
2639 printer().duration_to_string(&SignedDuration::from_secs(secs))
2640 };
2641
2642 insta::assert_snapshot!(p(1), @"01s");
2643 insta::assert_snapshot!(p(2), @"02s");
2644 insta::assert_snapshot!(p(10), @"10s");
2645 insta::assert_snapshot!(p(100), @"01m 40s");
2646
2647 insta::assert_snapshot!(p(1 * 60), @"01m");
2648 insta::assert_snapshot!(p(2 * 60), @"02m");
2649 insta::assert_snapshot!(p(10 * 60), @"10m");
2650 insta::assert_snapshot!(p(100 * 60), @"01h 40m");
2651
2652 insta::assert_snapshot!(p(1 * 60 * 60), @"01h");
2653 insta::assert_snapshot!(p(2 * 60 * 60), @"02h");
2654 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2655 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2656
2657 insta::assert_snapshot!(
2658 p(60 * 60 + 60 + 1),
2659 @"01h 01m 01s",
2660 );
2661 insta::assert_snapshot!(
2662 p(2 * 60 * 60 + 2 * 60 + 2),
2663 @"02h 02m 02s",
2664 );
2665 insta::assert_snapshot!(
2666 p(10 * 60 * 60 + 10 * 60 + 10),
2667 @"10h 10m 10s",
2668 );
2669 insta::assert_snapshot!(
2670 p(100 * 60 * 60 + 100 * 60 + 100),
2671 @"101h 41m 40s",
2672 );
2673
2674 insta::assert_snapshot!(p(-1 * 60 * 60), @"01h ago");
2675 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"01h 30s ago");
2676 }
2677
2678 #[test]
2679 fn print_signed_duration_designator_spacing_none() {
2680 let printer = || SpanPrinter::new().spacing(Spacing::None);
2681 let p = |secs| {
2682 printer().duration_to_string(&SignedDuration::from_secs(secs))
2683 };
2684
2685 insta::assert_snapshot!(p(1), @"1s");
2686 insta::assert_snapshot!(p(2), @"2s");
2687 insta::assert_snapshot!(p(10), @"10s");
2688 insta::assert_snapshot!(p(100), @"1m40s");
2689
2690 insta::assert_snapshot!(p(1 * 60), @"1m");
2691 insta::assert_snapshot!(p(2 * 60), @"2m");
2692 insta::assert_snapshot!(p(10 * 60), @"10m");
2693 insta::assert_snapshot!(p(100 * 60), @"1h40m");
2694
2695 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
2696 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
2697 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2698 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2699
2700 insta::assert_snapshot!(
2701 p(60 * 60 + 60 + 1),
2702 @"1h1m1s",
2703 );
2704 insta::assert_snapshot!(
2705 p(2 * 60 * 60 + 2 * 60 + 2),
2706 @"2h2m2s",
2707 );
2708 insta::assert_snapshot!(
2709 p(10 * 60 * 60 + 10 * 60 + 10),
2710 @"10h10m10s",
2711 );
2712 insta::assert_snapshot!(
2713 p(100 * 60 * 60 + 100 * 60 + 100),
2714 @"101h41m40s",
2715 );
2716
2717 insta::assert_snapshot!(p(-1 * 60 * 60), @"-1h");
2718 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"-1h30s");
2719 }
2720
2721 #[test]
2722 fn print_signed_duration_designator_spacing_more() {
2723 let printer =
2724 || SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
2725 let p = |secs| {
2726 printer().duration_to_string(&SignedDuration::from_secs(secs))
2727 };
2728
2729 insta::assert_snapshot!(p(1), @"1 s");
2730 insta::assert_snapshot!(p(2), @"2 s");
2731 insta::assert_snapshot!(p(10), @"10 s");
2732 insta::assert_snapshot!(p(100), @"1 m 40 s");
2733
2734 insta::assert_snapshot!(p(1 * 60), @"1 m");
2735 insta::assert_snapshot!(p(2 * 60), @"2 m");
2736 insta::assert_snapshot!(p(10 * 60), @"10 m");
2737 insta::assert_snapshot!(p(100 * 60), @"1 h 40 m");
2738
2739 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
2740 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
2741 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
2742 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
2743
2744 insta::assert_snapshot!(
2745 p(60 * 60 + 60 + 1),
2746 @"1 h 1 m 1 s",
2747 );
2748 insta::assert_snapshot!(
2749 p(2 * 60 * 60 + 2 * 60 + 2),
2750 @"2 h 2 m 2 s",
2751 );
2752 insta::assert_snapshot!(
2753 p(10 * 60 * 60 + 10 * 60 + 10),
2754 @"10 h 10 m 10 s",
2755 );
2756 insta::assert_snapshot!(
2757 p(100 * 60 * 60 + 100 * 60 + 100),
2758 @"101 h 41 m 40 s",
2759 );
2760
2761 insta::assert_snapshot!(p(-1 * 60 * 60), @"1 h ago");
2762 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1 h 30 s ago");
2763 }
2764
2765 #[test]
2766 fn print_signed_duration_designator_spacing_comma() {
2767 let printer = || {
2768 SpanPrinter::new()
2769 .comma_after_designator(true)
2770 .spacing(Spacing::BetweenUnitsAndDesignators)
2771 };
2772 let p = |secs| {
2773 printer().duration_to_string(&SignedDuration::from_secs(secs))
2774 };
2775
2776 insta::assert_snapshot!(p(1), @"1 s");
2777 insta::assert_snapshot!(p(2), @"2 s");
2778 insta::assert_snapshot!(p(10), @"10 s");
2779 insta::assert_snapshot!(p(100), @"1 m, 40 s");
2780
2781 insta::assert_snapshot!(p(1 * 60), @"1 m");
2782 insta::assert_snapshot!(p(2 * 60), @"2 m");
2783 insta::assert_snapshot!(p(10 * 60), @"10 m");
2784 insta::assert_snapshot!(p(100 * 60), @"1 h, 40 m");
2785
2786 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
2787 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
2788 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
2789 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
2790
2791 insta::assert_snapshot!(
2792 p(60 * 60 + 60 + 1),
2793 @"1 h, 1 m, 1 s",
2794 );
2795 insta::assert_snapshot!(
2796 p(2 * 60 * 60 + 2 * 60 + 2),
2797 @"2 h, 2 m, 2 s",
2798 );
2799 insta::assert_snapshot!(
2800 p(10 * 60 * 60 + 10 * 60 + 10),
2801 @"10 h, 10 m, 10 s",
2802 );
2803 insta::assert_snapshot!(
2804 p(100 * 60 * 60 + 100 * 60 + 100),
2805 @"101 h, 41 m, 40 s",
2806 );
2807
2808 insta::assert_snapshot!(p(-1 * 60 * 60), @"1 h ago");
2809 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1 h, 30 s ago");
2810 }
2811
2812 #[test]
2813 fn print_signed_duration_designator_fractional_hour() {
2814 let printer =
2815 || SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
2816 let p = |secs, nanos| {
2817 printer().duration_to_string(&SignedDuration::new(secs, nanos))
2818 };
2819 let pp = |precision, secs, nanos| {
2820 printer()
2821 .precision(Some(precision))
2822 .duration_to_string(&SignedDuration::new(secs, nanos))
2823 };
2824
2825 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
2826 insta::assert_snapshot!(pp(0, 1 * 60 * 60, 0), @"1h");
2827 insta::assert_snapshot!(pp(1, 1 * 60 * 60, 0), @"1.0h");
2828 insta::assert_snapshot!(pp(2, 1 * 60 * 60, 0), @"1.00h");
2829
2830 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1.5h");
2831 insta::assert_snapshot!(pp(0, 1 * 60 * 60 + 30 * 60, 0), @"1h");
2832 insta::assert_snapshot!(pp(1, 1 * 60 * 60 + 30 * 60, 0), @"1.5h");
2833 insta::assert_snapshot!(pp(2, 1 * 60 * 60 + 30 * 60, 0), @"1.50h");
2834
2835 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 0), @"1.05h");
2836 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 1), @"1.05h");
2837 insta::assert_snapshot!(p(1, 0), @"0.000277777h");
2838 insta::assert_snapshot!(p(1, 1), @"0.000277777h");
2840 insta::assert_snapshot!(p(0, 0), @"0h");
2841 insta::assert_snapshot!(p(0, 1), @"0h");
2843
2844 insta::assert_snapshot!(
2845 printer().duration_to_string(&SignedDuration::MIN),
2846 @"2562047788015215.502499999h ago",
2847 );
2848 }
2849
2850 #[test]
2851 fn print_signed_duration_designator_fractional_minute() {
2852 let printer =
2853 || SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
2854 let p = |secs, nanos| {
2855 printer().duration_to_string(&SignedDuration::new(secs, nanos))
2856 };
2857 let pp = |precision, secs, nanos| {
2858 printer()
2859 .precision(Some(precision))
2860 .duration_to_string(&SignedDuration::new(secs, nanos))
2861 };
2862
2863 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
2864 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
2865
2866 insta::assert_snapshot!(p(60, 0), @"1m");
2867 insta::assert_snapshot!(pp(0, 60, 0), @"1m");
2868 insta::assert_snapshot!(pp(1, 60, 0), @"1.0m");
2869 insta::assert_snapshot!(pp(2, 60, 0), @"1.00m");
2870
2871 insta::assert_snapshot!(p(90, 0), @"1.5m");
2872 insta::assert_snapshot!(pp(0, 90, 0), @"1m");
2873 insta::assert_snapshot!(pp(1, 90, 0), @"1.5m");
2874 insta::assert_snapshot!(pp(2, 90, 0), @"1.50m");
2875
2876 insta::assert_snapshot!(p(1 * 60 * 60, 1), @"1h");
2877 insta::assert_snapshot!(p(63, 0), @"1.05m");
2878 insta::assert_snapshot!(p(63, 1), @"1.05m");
2879 insta::assert_snapshot!(p(1, 0), @"0.016666666m");
2880 insta::assert_snapshot!(p(1, 1), @"0.016666666m");
2882 insta::assert_snapshot!(p(0, 0), @"0m");
2883 insta::assert_snapshot!(p(0, 1), @"0m");
2885
2886 insta::assert_snapshot!(
2887 printer().duration_to_string(&SignedDuration::MIN),
2888 @"2562047788015215h 30.149999999m ago",
2889 );
2890 }
2891
2892 #[test]
2893 fn print_signed_duration_designator_fractional_second() {
2894 let printer =
2895 || SpanPrinter::new().fractional(Some(FractionalUnit::Second));
2896 let p = |secs, nanos| {
2897 printer().duration_to_string(&SignedDuration::new(secs, nanos))
2898 };
2899 let pp = |precision, secs, nanos| {
2900 printer()
2901 .precision(Some(precision))
2902 .duration_to_string(&SignedDuration::new(secs, nanos))
2903 };
2904
2905 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
2906 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
2907
2908 insta::assert_snapshot!(p(1, 0), @"1s");
2909 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
2910 insta::assert_snapshot!(pp(1, 1, 0), @"1.0s");
2911 insta::assert_snapshot!(pp(2, 1, 0), @"1.00s");
2912
2913 insta::assert_snapshot!(p(1, 500_000_000), @"1.5s");
2914 insta::assert_snapshot!(pp(0, 1, 500_000_000), @"1s");
2915 insta::assert_snapshot!(pp(1, 1, 500_000_000), @"1.5s");
2916 insta::assert_snapshot!(pp(2, 1, 500_000_000), @"1.50s");
2917
2918 insta::assert_snapshot!(p(1, 1), @"1.000000001s");
2919 insta::assert_snapshot!(p(0, 1), @"0.000000001s");
2920 insta::assert_snapshot!(p(0, 0), @"0s");
2921
2922 insta::assert_snapshot!(
2923 printer().duration_to_string(&SignedDuration::MIN),
2924 @"2562047788015215h 30m 8.999999999s ago",
2925 );
2926 }
2927
2928 #[test]
2929 fn print_signed_duration_designator_fractional_millisecond() {
2930 let printer = || {
2931 SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
2932 };
2933 let p = |secs, nanos| {
2934 printer().duration_to_string(&SignedDuration::new(secs, nanos))
2935 };
2936 let pp = |precision, secs, nanos| {
2937 printer()
2938 .precision(Some(precision))
2939 .duration_to_string(&SignedDuration::new(secs, nanos))
2940 };
2941
2942 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
2943 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
2944 insta::assert_snapshot!(
2945 p(1 * 60 * 60 + 30 * 60 + 10, 0),
2946 @"1h 30m 10s",
2947 );
2948
2949 insta::assert_snapshot!(p(1, 0), @"1s");
2950 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
2951 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0ms");
2952 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00ms");
2953
2954 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
2955 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms");
2956 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1.5ms");
2957 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1.50ms");
2958
2959 insta::assert_snapshot!(p(0, 1_000_001), @"1.000001ms");
2960 insta::assert_snapshot!(p(0, 0_000_001), @"0.000001ms");
2961 insta::assert_snapshot!(p(0, 0), @"0ms");
2962
2963 insta::assert_snapshot!(
2964 printer().duration_to_string(&SignedDuration::MIN),
2965 @"2562047788015215h 30m 8s 999.999999ms ago",
2966 );
2967 }
2968
2969 #[test]
2970 fn print_signed_duration_designator_fractional_microsecond() {
2971 let printer = || {
2972 SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
2973 };
2974 let p = |secs, nanos| {
2975 printer().duration_to_string(&SignedDuration::new(secs, nanos))
2976 };
2977 let pp = |precision, secs, nanos| {
2978 printer()
2979 .precision(Some(precision))
2980 .duration_to_string(&SignedDuration::new(secs, nanos))
2981 };
2982
2983 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
2984 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
2985 insta::assert_snapshot!(
2986 p(1 * 60 * 60 + 30 * 60 + 10, 0),
2987 @"1h 30m 10s",
2988 );
2989
2990 insta::assert_snapshot!(p(1, 0), @"1s");
2991 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
2992 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0µs");
2993 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00µs");
2994
2995 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
2996 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms 500µs");
2997 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1ms 500.0µs");
2998 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1ms 500.00µs");
2999
3000 insta::assert_snapshot!(p(0, 1_000_001), @"1ms 0.001µs");
3001 insta::assert_snapshot!(p(0, 0_000_001), @"0.001µs");
3002 insta::assert_snapshot!(p(0, 0), @"0µs");
3003
3004 insta::assert_snapshot!(
3005 printer().duration_to_string(&SignedDuration::MIN),
3006 @"2562047788015215h 30m 8s 999ms 999.999µs ago",
3007 );
3008 }
3009
3010 #[test]
3011 fn print_unsigned_duration_designator_default() {
3012 let printer = || SpanPrinter::new();
3013 let p = |secs| {
3014 printer().unsigned_duration_to_string(
3015 &core::time::Duration::from_secs(secs),
3016 )
3017 };
3018
3019 insta::assert_snapshot!(p(1), @"1s");
3020 insta::assert_snapshot!(p(2), @"2s");
3021 insta::assert_snapshot!(p(10), @"10s");
3022 insta::assert_snapshot!(p(100), @"1m 40s");
3023
3024 insta::assert_snapshot!(p(1 * 60), @"1m");
3025 insta::assert_snapshot!(p(2 * 60), @"2m");
3026 insta::assert_snapshot!(p(10 * 60), @"10m");
3027 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
3028
3029 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
3030 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
3031 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3032 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3033
3034 insta::assert_snapshot!(
3035 p(60 * 60 + 60 + 1),
3036 @"1h 1m 1s",
3037 );
3038 insta::assert_snapshot!(
3039 p(2 * 60 * 60 + 2 * 60 + 2),
3040 @"2h 2m 2s",
3041 );
3042 insta::assert_snapshot!(
3043 p(10 * 60 * 60 + 10 * 60 + 10),
3044 @"10h 10m 10s",
3045 );
3046 insta::assert_snapshot!(
3047 p(100 * 60 * 60 + 100 * 60 + 100),
3048 @"101h 41m 40s",
3049 );
3050 }
3051
3052 #[test]
3053 fn print_unsigned_duration_designator_verbose() {
3054 let printer = || SpanPrinter::new().designator(Designator::Verbose);
3055 let p = |secs| {
3056 printer().unsigned_duration_to_string(
3057 &core::time::Duration::from_secs(secs),
3058 )
3059 };
3060
3061 insta::assert_snapshot!(p(1), @"1second");
3062 insta::assert_snapshot!(p(2), @"2seconds");
3063 insta::assert_snapshot!(p(10), @"10seconds");
3064 insta::assert_snapshot!(p(100), @"1minute 40seconds");
3065
3066 insta::assert_snapshot!(p(1 * 60), @"1minute");
3067 insta::assert_snapshot!(p(2 * 60), @"2minutes");
3068 insta::assert_snapshot!(p(10 * 60), @"10minutes");
3069 insta::assert_snapshot!(p(100 * 60), @"1hour 40minutes");
3070
3071 insta::assert_snapshot!(p(1 * 60 * 60), @"1hour");
3072 insta::assert_snapshot!(p(2 * 60 * 60), @"2hours");
3073 insta::assert_snapshot!(p(10 * 60 * 60), @"10hours");
3074 insta::assert_snapshot!(p(100 * 60 * 60), @"100hours");
3075
3076 insta::assert_snapshot!(
3077 p(60 * 60 + 60 + 1),
3078 @"1hour 1minute 1second",
3079 );
3080 insta::assert_snapshot!(
3081 p(2 * 60 * 60 + 2 * 60 + 2),
3082 @"2hours 2minutes 2seconds",
3083 );
3084 insta::assert_snapshot!(
3085 p(10 * 60 * 60 + 10 * 60 + 10),
3086 @"10hours 10minutes 10seconds",
3087 );
3088 insta::assert_snapshot!(
3089 p(100 * 60 * 60 + 100 * 60 + 100),
3090 @"101hours 41minutes 40seconds",
3091 );
3092 }
3093
3094 #[test]
3095 fn print_unsigned_duration_designator_short() {
3096 let printer = || SpanPrinter::new().designator(Designator::Short);
3097 let p = |secs| {
3098 printer().unsigned_duration_to_string(
3099 &core::time::Duration::from_secs(secs),
3100 )
3101 };
3102
3103 insta::assert_snapshot!(p(1), @"1sec");
3104 insta::assert_snapshot!(p(2), @"2secs");
3105 insta::assert_snapshot!(p(10), @"10secs");
3106 insta::assert_snapshot!(p(100), @"1min 40secs");
3107
3108 insta::assert_snapshot!(p(1 * 60), @"1min");
3109 insta::assert_snapshot!(p(2 * 60), @"2mins");
3110 insta::assert_snapshot!(p(10 * 60), @"10mins");
3111 insta::assert_snapshot!(p(100 * 60), @"1hr 40mins");
3112
3113 insta::assert_snapshot!(p(1 * 60 * 60), @"1hr");
3114 insta::assert_snapshot!(p(2 * 60 * 60), @"2hrs");
3115 insta::assert_snapshot!(p(10 * 60 * 60), @"10hrs");
3116 insta::assert_snapshot!(p(100 * 60 * 60), @"100hrs");
3117
3118 insta::assert_snapshot!(
3119 p(60 * 60 + 60 + 1),
3120 @"1hr 1min 1sec",
3121 );
3122 insta::assert_snapshot!(
3123 p(2 * 60 * 60 + 2 * 60 + 2),
3124 @"2hrs 2mins 2secs",
3125 );
3126 insta::assert_snapshot!(
3127 p(10 * 60 * 60 + 10 * 60 + 10),
3128 @"10hrs 10mins 10secs",
3129 );
3130 insta::assert_snapshot!(
3131 p(100 * 60 * 60 + 100 * 60 + 100),
3132 @"101hrs 41mins 40secs",
3133 );
3134 }
3135
3136 #[test]
3137 fn print_unsigned_duration_designator_compact() {
3138 let printer = || SpanPrinter::new().designator(Designator::Compact);
3139 let p = |secs| {
3140 printer().unsigned_duration_to_string(
3141 &core::time::Duration::from_secs(secs),
3142 )
3143 };
3144
3145 insta::assert_snapshot!(p(1), @"1s");
3146 insta::assert_snapshot!(p(2), @"2s");
3147 insta::assert_snapshot!(p(10), @"10s");
3148 insta::assert_snapshot!(p(100), @"1m 40s");
3149
3150 insta::assert_snapshot!(p(1 * 60), @"1m");
3151 insta::assert_snapshot!(p(2 * 60), @"2m");
3152 insta::assert_snapshot!(p(10 * 60), @"10m");
3153 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
3154
3155 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
3156 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
3157 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3158 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3159
3160 insta::assert_snapshot!(
3161 p(60 * 60 + 60 + 1),
3162 @"1h 1m 1s",
3163 );
3164 insta::assert_snapshot!(
3165 p(2 * 60 * 60 + 2 * 60 + 2),
3166 @"2h 2m 2s",
3167 );
3168 insta::assert_snapshot!(
3169 p(10 * 60 * 60 + 10 * 60 + 10),
3170 @"10h 10m 10s",
3171 );
3172 insta::assert_snapshot!(
3173 p(100 * 60 * 60 + 100 * 60 + 100),
3174 @"101h 41m 40s",
3175 );
3176 }
3177
3178 #[test]
3179 fn print_unsigned_duration_designator_direction_force() {
3180 let printer = || SpanPrinter::new().direction(Direction::ForceSign);
3181 let p = |secs| {
3182 printer().unsigned_duration_to_string(
3183 &core::time::Duration::from_secs(secs),
3184 )
3185 };
3186
3187 insta::assert_snapshot!(p(1), @"+1s");
3188 insta::assert_snapshot!(p(2), @"+2s");
3189 insta::assert_snapshot!(p(10), @"+10s");
3190 insta::assert_snapshot!(p(100), @"+1m 40s");
3191
3192 insta::assert_snapshot!(p(1 * 60), @"+1m");
3193 insta::assert_snapshot!(p(2 * 60), @"+2m");
3194 insta::assert_snapshot!(p(10 * 60), @"+10m");
3195 insta::assert_snapshot!(p(100 * 60), @"+1h 40m");
3196
3197 insta::assert_snapshot!(p(1 * 60 * 60), @"+1h");
3198 insta::assert_snapshot!(p(2 * 60 * 60), @"+2h");
3199 insta::assert_snapshot!(p(10 * 60 * 60), @"+10h");
3200 insta::assert_snapshot!(p(100 * 60 * 60), @"+100h");
3201
3202 insta::assert_snapshot!(
3203 p(60 * 60 + 60 + 1),
3204 @"+1h 1m 1s",
3205 );
3206 insta::assert_snapshot!(
3207 p(2 * 60 * 60 + 2 * 60 + 2),
3208 @"+2h 2m 2s",
3209 );
3210 insta::assert_snapshot!(
3211 p(10 * 60 * 60 + 10 * 60 + 10),
3212 @"+10h 10m 10s",
3213 );
3214 insta::assert_snapshot!(
3215 p(100 * 60 * 60 + 100 * 60 + 100),
3216 @"+101h 41m 40s",
3217 );
3218 }
3219
3220 #[test]
3221 fn print_unsigned_duration_designator_padding() {
3222 let printer = || SpanPrinter::new().padding(2);
3223 let p = |secs| {
3224 printer().unsigned_duration_to_string(
3225 &core::time::Duration::from_secs(secs),
3226 )
3227 };
3228
3229 insta::assert_snapshot!(p(1), @"01s");
3230 insta::assert_snapshot!(p(2), @"02s");
3231 insta::assert_snapshot!(p(10), @"10s");
3232 insta::assert_snapshot!(p(100), @"01m 40s");
3233
3234 insta::assert_snapshot!(p(1 * 60), @"01m");
3235 insta::assert_snapshot!(p(2 * 60), @"02m");
3236 insta::assert_snapshot!(p(10 * 60), @"10m");
3237 insta::assert_snapshot!(p(100 * 60), @"01h 40m");
3238
3239 insta::assert_snapshot!(p(1 * 60 * 60), @"01h");
3240 insta::assert_snapshot!(p(2 * 60 * 60), @"02h");
3241 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3242 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3243
3244 insta::assert_snapshot!(
3245 p(60 * 60 + 60 + 1),
3246 @"01h 01m 01s",
3247 );
3248 insta::assert_snapshot!(
3249 p(2 * 60 * 60 + 2 * 60 + 2),
3250 @"02h 02m 02s",
3251 );
3252 insta::assert_snapshot!(
3253 p(10 * 60 * 60 + 10 * 60 + 10),
3254 @"10h 10m 10s",
3255 );
3256 insta::assert_snapshot!(
3257 p(100 * 60 * 60 + 100 * 60 + 100),
3258 @"101h 41m 40s",
3259 );
3260 }
3261
3262 #[test]
3263 fn print_unsigned_duration_designator_spacing_none() {
3264 let printer = || SpanPrinter::new().spacing(Spacing::None);
3265 let p = |secs| {
3266 printer().unsigned_duration_to_string(
3267 &core::time::Duration::from_secs(secs),
3268 )
3269 };
3270
3271 insta::assert_snapshot!(p(1), @"1s");
3272 insta::assert_snapshot!(p(2), @"2s");
3273 insta::assert_snapshot!(p(10), @"10s");
3274 insta::assert_snapshot!(p(100), @"1m40s");
3275
3276 insta::assert_snapshot!(p(1 * 60), @"1m");
3277 insta::assert_snapshot!(p(2 * 60), @"2m");
3278 insta::assert_snapshot!(p(10 * 60), @"10m");
3279 insta::assert_snapshot!(p(100 * 60), @"1h40m");
3280
3281 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
3282 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
3283 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3284 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3285
3286 insta::assert_snapshot!(
3287 p(60 * 60 + 60 + 1),
3288 @"1h1m1s",
3289 );
3290 insta::assert_snapshot!(
3291 p(2 * 60 * 60 + 2 * 60 + 2),
3292 @"2h2m2s",
3293 );
3294 insta::assert_snapshot!(
3295 p(10 * 60 * 60 + 10 * 60 + 10),
3296 @"10h10m10s",
3297 );
3298 insta::assert_snapshot!(
3299 p(100 * 60 * 60 + 100 * 60 + 100),
3300 @"101h41m40s",
3301 );
3302 }
3303
3304 #[test]
3305 fn print_unsigned_duration_designator_spacing_more() {
3306 let printer =
3307 || SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
3308 let p = |secs| {
3309 printer().unsigned_duration_to_string(
3310 &core::time::Duration::from_secs(secs),
3311 )
3312 };
3313
3314 insta::assert_snapshot!(p(1), @"1 s");
3315 insta::assert_snapshot!(p(2), @"2 s");
3316 insta::assert_snapshot!(p(10), @"10 s");
3317 insta::assert_snapshot!(p(100), @"1 m 40 s");
3318
3319 insta::assert_snapshot!(p(1 * 60), @"1 m");
3320 insta::assert_snapshot!(p(2 * 60), @"2 m");
3321 insta::assert_snapshot!(p(10 * 60), @"10 m");
3322 insta::assert_snapshot!(p(100 * 60), @"1 h 40 m");
3323
3324 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
3325 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
3326 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
3327 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
3328
3329 insta::assert_snapshot!(
3330 p(60 * 60 + 60 + 1),
3331 @"1 h 1 m 1 s",
3332 );
3333 insta::assert_snapshot!(
3334 p(2 * 60 * 60 + 2 * 60 + 2),
3335 @"2 h 2 m 2 s",
3336 );
3337 insta::assert_snapshot!(
3338 p(10 * 60 * 60 + 10 * 60 + 10),
3339 @"10 h 10 m 10 s",
3340 );
3341 insta::assert_snapshot!(
3342 p(100 * 60 * 60 + 100 * 60 + 100),
3343 @"101 h 41 m 40 s",
3344 );
3345 }
3346
3347 #[test]
3348 fn print_unsigned_duration_designator_spacing_comma() {
3349 let printer = || {
3350 SpanPrinter::new()
3351 .comma_after_designator(true)
3352 .spacing(Spacing::BetweenUnitsAndDesignators)
3353 };
3354 let p = |secs| {
3355 printer().unsigned_duration_to_string(
3356 &core::time::Duration::from_secs(secs),
3357 )
3358 };
3359
3360 insta::assert_snapshot!(p(1), @"1 s");
3361 insta::assert_snapshot!(p(2), @"2 s");
3362 insta::assert_snapshot!(p(10), @"10 s");
3363 insta::assert_snapshot!(p(100), @"1 m, 40 s");
3364
3365 insta::assert_snapshot!(p(1 * 60), @"1 m");
3366 insta::assert_snapshot!(p(2 * 60), @"2 m");
3367 insta::assert_snapshot!(p(10 * 60), @"10 m");
3368 insta::assert_snapshot!(p(100 * 60), @"1 h, 40 m");
3369
3370 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
3371 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
3372 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
3373 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
3374
3375 insta::assert_snapshot!(
3376 p(60 * 60 + 60 + 1),
3377 @"1 h, 1 m, 1 s",
3378 );
3379 insta::assert_snapshot!(
3380 p(2 * 60 * 60 + 2 * 60 + 2),
3381 @"2 h, 2 m, 2 s",
3382 );
3383 insta::assert_snapshot!(
3384 p(10 * 60 * 60 + 10 * 60 + 10),
3385 @"10 h, 10 m, 10 s",
3386 );
3387 insta::assert_snapshot!(
3388 p(100 * 60 * 60 + 100 * 60 + 100),
3389 @"101 h, 41 m, 40 s",
3390 );
3391 }
3392
3393 #[test]
3394 fn print_unsigned_duration_designator_fractional_hour() {
3395 let printer =
3396 || SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
3397 let p = |secs, nanos| {
3398 printer().unsigned_duration_to_string(&core::time::Duration::new(
3399 secs, nanos,
3400 ))
3401 };
3402 let pp = |precision, secs, nanos| {
3403 printer()
3404 .precision(Some(precision))
3405 .duration_to_string(&SignedDuration::new(secs, nanos))
3406 };
3407
3408 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3409 insta::assert_snapshot!(pp(0, 1 * 60 * 60, 0), @"1h");
3410 insta::assert_snapshot!(pp(1, 1 * 60 * 60, 0), @"1.0h");
3411 insta::assert_snapshot!(pp(2, 1 * 60 * 60, 0), @"1.00h");
3412
3413 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1.5h");
3414 insta::assert_snapshot!(pp(0, 1 * 60 * 60 + 30 * 60, 0), @"1h");
3415 insta::assert_snapshot!(pp(1, 1 * 60 * 60 + 30 * 60, 0), @"1.5h");
3416 insta::assert_snapshot!(pp(2, 1 * 60 * 60 + 30 * 60, 0), @"1.50h");
3417
3418 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 0), @"1.05h");
3419 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 1), @"1.05h");
3420 insta::assert_snapshot!(p(1, 0), @"0.000277777h");
3421 insta::assert_snapshot!(p(1, 1), @"0.000277777h");
3423 insta::assert_snapshot!(p(0, 0), @"0h");
3424 insta::assert_snapshot!(p(0, 1), @"0h");
3426 }
3427
3428 #[test]
3429 fn print_unsigned_duration_designator_fractional_minute() {
3430 let printer =
3431 || SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
3432 let p = |secs, nanos| {
3433 printer().unsigned_duration_to_string(&core::time::Duration::new(
3434 secs, nanos,
3435 ))
3436 };
3437 let pp = |precision, secs, nanos| {
3438 printer()
3439 .precision(Some(precision))
3440 .duration_to_string(&SignedDuration::new(secs, nanos))
3441 };
3442
3443 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3444 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3445
3446 insta::assert_snapshot!(p(60, 0), @"1m");
3447 insta::assert_snapshot!(pp(0, 60, 0), @"1m");
3448 insta::assert_snapshot!(pp(1, 60, 0), @"1.0m");
3449 insta::assert_snapshot!(pp(2, 60, 0), @"1.00m");
3450
3451 insta::assert_snapshot!(p(90, 0), @"1.5m");
3452 insta::assert_snapshot!(pp(0, 90, 0), @"1m");
3453 insta::assert_snapshot!(pp(1, 90, 0), @"1.5m");
3454 insta::assert_snapshot!(pp(2, 90, 0), @"1.50m");
3455
3456 insta::assert_snapshot!(p(1 * 60 * 60, 1), @"1h");
3457 insta::assert_snapshot!(p(63, 0), @"1.05m");
3458 insta::assert_snapshot!(p(63, 1), @"1.05m");
3459 insta::assert_snapshot!(p(1, 0), @"0.016666666m");
3460 insta::assert_snapshot!(p(1, 1), @"0.016666666m");
3462 insta::assert_snapshot!(p(0, 0), @"0m");
3463 insta::assert_snapshot!(p(0, 1), @"0m");
3465 }
3466
3467 #[test]
3468 fn print_unsigned_duration_designator_fractional_second() {
3469 let printer =
3470 || SpanPrinter::new().fractional(Some(FractionalUnit::Second));
3471 let p = |secs, nanos| {
3472 printer().unsigned_duration_to_string(&core::time::Duration::new(
3473 secs, nanos,
3474 ))
3475 };
3476 let pp = |precision, secs, nanos| {
3477 printer()
3478 .precision(Some(precision))
3479 .duration_to_string(&SignedDuration::new(secs, nanos))
3480 };
3481
3482 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3483 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3484
3485 insta::assert_snapshot!(p(1, 0), @"1s");
3486 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3487 insta::assert_snapshot!(pp(1, 1, 0), @"1.0s");
3488 insta::assert_snapshot!(pp(2, 1, 0), @"1.00s");
3489
3490 insta::assert_snapshot!(p(1, 500_000_000), @"1.5s");
3491 insta::assert_snapshot!(pp(0, 1, 500_000_000), @"1s");
3492 insta::assert_snapshot!(pp(1, 1, 500_000_000), @"1.5s");
3493 insta::assert_snapshot!(pp(2, 1, 500_000_000), @"1.50s");
3494
3495 insta::assert_snapshot!(p(1, 1), @"1.000000001s");
3496 insta::assert_snapshot!(p(0, 1), @"0.000000001s");
3497 insta::assert_snapshot!(p(0, 0), @"0s");
3498 }
3499
3500 #[test]
3501 fn print_unsigned_duration_designator_fractional_millisecond() {
3502 let printer = || {
3503 SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
3504 };
3505 let p = |secs, nanos| {
3506 printer().unsigned_duration_to_string(&core::time::Duration::new(
3507 secs, nanos,
3508 ))
3509 };
3510 let pp = |precision, secs, nanos| {
3511 printer()
3512 .precision(Some(precision))
3513 .duration_to_string(&SignedDuration::new(secs, nanos))
3514 };
3515
3516 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3517 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3518 insta::assert_snapshot!(
3519 p(1 * 60 * 60 + 30 * 60 + 10, 0),
3520 @"1h 30m 10s",
3521 );
3522
3523 insta::assert_snapshot!(p(1, 0), @"1s");
3524 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3525 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0ms");
3526 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00ms");
3527
3528 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
3529 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms");
3530 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1.5ms");
3531 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1.50ms");
3532
3533 insta::assert_snapshot!(p(0, 1_000_001), @"1.000001ms");
3534 insta::assert_snapshot!(p(0, 0_000_001), @"0.000001ms");
3535 insta::assert_snapshot!(p(0, 0), @"0ms");
3536 }
3537
3538 #[test]
3539 fn print_unsigned_duration_designator_fractional_microsecond() {
3540 let printer = || {
3541 SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
3542 };
3543 let p = |secs, nanos| {
3544 printer().unsigned_duration_to_string(&core::time::Duration::new(
3545 secs, nanos,
3546 ))
3547 };
3548 let pp = |precision, secs, nanos| {
3549 printer().precision(Some(precision)).unsigned_duration_to_string(
3550 &core::time::Duration::new(secs, nanos),
3551 )
3552 };
3553
3554 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3555 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3556 insta::assert_snapshot!(
3557 p(1 * 60 * 60 + 30 * 60 + 10, 0),
3558 @"1h 30m 10s",
3559 );
3560
3561 insta::assert_snapshot!(p(1, 0), @"1s");
3562 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3563 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0µs");
3564 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00µs");
3565
3566 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
3567 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms 500µs");
3568 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1ms 500.0µs");
3569 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1ms 500.00µs");
3570
3571 insta::assert_snapshot!(p(0, 1_000_001), @"1ms 0.001µs");
3572 insta::assert_snapshot!(p(0, 0_000_001), @"0.001µs");
3573 insta::assert_snapshot!(p(0, 0), @"0µs");
3574 }
3575
3576 #[test]
3577 fn print_span_hms() {
3578 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3579 let p = |span| printer().span_to_string(&span);
3580
3581 insta::assert_snapshot!(p(1.second()), @"00:00:01");
3582 insta::assert_snapshot!(p(2.seconds()), @"00:00:02");
3583 insta::assert_snapshot!(p(10.seconds()), @"00:00:10");
3584 insta::assert_snapshot!(p(100.seconds()), @"00:00:100");
3585
3586 insta::assert_snapshot!(p(1.minute()), @"00:01:00");
3587 insta::assert_snapshot!(p(2.minutes()), @"00:02:00");
3588 insta::assert_snapshot!(p(10.minutes()), @"00:10:00");
3589 insta::assert_snapshot!(p(100.minutes()), @"00:100:00");
3590
3591 insta::assert_snapshot!(p(1.hour()), @"01:00:00");
3592 insta::assert_snapshot!(p(2.hours()), @"02:00:00");
3593 insta::assert_snapshot!(p(10.hours()), @"10:00:00");
3594 insta::assert_snapshot!(p(100.hours()), @"100:00:00");
3595
3596 insta::assert_snapshot!(
3597 p(1.hour().minutes(1).seconds(1)),
3598 @"01:01:01",
3599 );
3600 insta::assert_snapshot!(
3601 p(2.hours().minutes(2).seconds(2)),
3602 @"02:02:02",
3603 );
3604 insta::assert_snapshot!(
3605 p(10.hours().minutes(10).seconds(10)),
3606 @"10:10:10",
3607 );
3608 insta::assert_snapshot!(
3609 p(100.hours().minutes(100).seconds(100)),
3610 @"100:100:100",
3611 );
3612
3613 insta::assert_snapshot!(
3614 p(1.day().hours(1).minutes(1).seconds(1)),
3615 @"1d 01:01:01",
3616 );
3617 insta::assert_snapshot!(
3618 p(1.day()),
3619 @"1d 00:00:00",
3620 );
3621 insta::assert_snapshot!(
3622 p(1.day().seconds(2)),
3623 @"1d 00:00:02",
3624 );
3625 }
3626
3627 #[test]
3628 fn print_span_hms_fmt() {
3629 let printer = || {
3630 SpanPrinter::new()
3631 .hours_minutes_seconds(true)
3632 .comma_after_designator(true)
3633 .spacing(Spacing::BetweenUnitsAndDesignators)
3634 };
3635 let p = |span| printer().span_to_string(&span);
3636
3637 insta::assert_snapshot!(
3638 p(1.day().hours(1).minutes(1).seconds(1)),
3639 @"1 d, 01:01:01",
3640 );
3641 insta::assert_snapshot!(
3642 p(1.year().months(1).weeks(1).days(1).hours(1).minutes(1).seconds(1)),
3643 @"1 y, 1 mo, 1 w, 1 d, 01:01:01",
3644 );
3645 insta::assert_snapshot!(
3646 p(1.day().hours(1).minutes(1).seconds(1).nanoseconds(1)),
3647 @"1 d, 01:01:01.000000001",
3648 );
3649 }
3650
3651 #[test]
3652 fn print_span_hms_sign() {
3653 let printer = |direction| {
3654 SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
3655 };
3656 let p = |direction, span| printer(direction).span_to_string(&span);
3657
3658 insta::assert_snapshot!(
3659 p(Direction::Auto, 1.hour()),
3660 @"01:00:00",
3661 );
3662 insta::assert_snapshot!(
3663 p(Direction::Sign, 1.hour()),
3664 @"01:00:00",
3665 );
3666 insta::assert_snapshot!(
3667 p(Direction::ForceSign, 1.hour()),
3668 @"+01:00:00",
3669 );
3670 insta::assert_snapshot!(
3671 p(Direction::Suffix, 1.hour()),
3672 @"01:00:00",
3673 );
3674 insta::assert_snapshot!(
3675 p(Direction::Auto, -1.hour()),
3676 @"-01:00:00",
3677 );
3678 insta::assert_snapshot!(
3679 p(Direction::Sign, -1.hour()),
3680 @"-01:00:00",
3681 );
3682 insta::assert_snapshot!(
3683 p(Direction::ForceSign, -1.hour()),
3684 @"-01:00:00",
3685 );
3686 insta::assert_snapshot!(
3687 p(Direction::Suffix, -1.hour()),
3688 @"01:00:00 ago",
3689 );
3690
3691 insta::assert_snapshot!(
3692 p(Direction::Auto, 1.day().hours(1)),
3693 @"1d 01:00:00",
3694 );
3695 insta::assert_snapshot!(
3696 p(Direction::Sign, 1.day().hours(1)),
3697 @"1d 01:00:00",
3698 );
3699 insta::assert_snapshot!(
3700 p(Direction::ForceSign, 1.day().hours(1)),
3701 @"+1d 01:00:00",
3702 );
3703 insta::assert_snapshot!(
3704 p(Direction::Suffix, 1.day().hours(1)),
3705 @"1d 01:00:00",
3706 );
3707 insta::assert_snapshot!(
3711 p(Direction::Auto, -1.day().hours(1)),
3712 @"1d 01:00:00 ago",
3713 );
3714 insta::assert_snapshot!(
3715 p(Direction::Sign, -1.day().hours(1)),
3716 @"-1d 01:00:00",
3717 );
3718 insta::assert_snapshot!(
3719 p(Direction::ForceSign, -1.day().hours(1)),
3720 @"-1d 01:00:00",
3721 );
3722 insta::assert_snapshot!(
3723 p(Direction::Suffix, -1.day().hours(1)),
3724 @"1d 01:00:00 ago",
3725 );
3726 }
3727
3728 #[test]
3729 fn print_span_hms_fraction_auto() {
3730 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3731 let p = |span| printer().span_to_string(&span);
3732
3733 insta::assert_snapshot!(p(1.nanosecond()), @"00:00:00.000000001");
3734 insta::assert_snapshot!(p(-1.nanosecond()), @"-00:00:00.000000001");
3735 insta::assert_snapshot!(
3736 printer().direction(Direction::ForceSign).span_to_string(&1.nanosecond()),
3737 @"+00:00:00.000000001",
3738 );
3739
3740 insta::assert_snapshot!(
3741 p(1.second().nanoseconds(123)),
3742 @"00:00:01.000000123",
3743 );
3744 insta::assert_snapshot!(
3745 p(1.second().milliseconds(123)),
3746 @"00:00:01.123",
3747 );
3748 insta::assert_snapshot!(
3749 p(1.second().milliseconds(1_123)),
3750 @"00:00:02.123",
3751 );
3752 insta::assert_snapshot!(
3753 p(1.second().milliseconds(61_123)),
3754 @"00:00:62.123",
3755 );
3756 }
3757
3758 #[test]
3759 fn print_span_hms_fraction_fixed_precision() {
3760 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3761 let p = |precision, span| {
3762 printer().precision(Some(precision)).span_to_string(&span)
3763 };
3764
3765 insta::assert_snapshot!(p(3, 1.second()), @"00:00:01.000");
3766 insta::assert_snapshot!(
3767 p(3, 1.second().milliseconds(1)),
3768 @"00:00:01.001",
3769 );
3770 insta::assert_snapshot!(
3771 p(3, 1.second().milliseconds(123)),
3772 @"00:00:01.123",
3773 );
3774 insta::assert_snapshot!(
3775 p(3, 1.second().milliseconds(100)),
3776 @"00:00:01.100",
3777 );
3778
3779 insta::assert_snapshot!(p(0, 1.second()), @"00:00:01");
3780 insta::assert_snapshot!(p(0, 1.second().milliseconds(1)), @"00:00:01");
3781 insta::assert_snapshot!(
3782 p(1, 1.second().milliseconds(999)),
3783 @"00:00:01.9",
3784 );
3785 }
3786
3787 #[test]
3788 fn print_signed_duration_hms() {
3789 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3790 let p = |secs| {
3791 printer().duration_to_string(&SignedDuration::from_secs(secs))
3792 };
3793
3794 insta::assert_snapshot!(p(1), @"00:00:01");
3798 insta::assert_snapshot!(p(2), @"00:00:02");
3799 insta::assert_snapshot!(p(10), @"00:00:10");
3800 insta::assert_snapshot!(p(100), @"00:01:40");
3801
3802 insta::assert_snapshot!(p(1 * 60), @"00:01:00");
3803 insta::assert_snapshot!(p(2 * 60), @"00:02:00");
3804 insta::assert_snapshot!(p(10 * 60), @"00:10:00");
3805 insta::assert_snapshot!(p(100 * 60), @"01:40:00");
3806
3807 insta::assert_snapshot!(p(1 * 60 * 60), @"01:00:00");
3808 insta::assert_snapshot!(p(2 * 60 * 60), @"02:00:00");
3809 insta::assert_snapshot!(p(10 * 60 * 60), @"10:00:00");
3810 insta::assert_snapshot!(p(100 * 60 * 60), @"100:00:00");
3811
3812 insta::assert_snapshot!(
3813 p(60 * 60 + 60 + 1),
3814 @"01:01:01",
3815 );
3816 insta::assert_snapshot!(
3817 p(2 * 60 * 60 + 2 * 60 + 2),
3818 @"02:02:02",
3819 );
3820 insta::assert_snapshot!(
3821 p(10 * 60 * 60 + 10 * 60 + 10),
3822 @"10:10:10",
3823 );
3824 insta::assert_snapshot!(
3825 p(100 * 60 * 60 + 100 * 60 + 100),
3826 @"101:41:40",
3827 );
3828 }
3829
3830 #[test]
3831 fn print_signed_duration_hms_sign() {
3832 let printer = |direction| {
3833 SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
3834 };
3835 let p = |direction, secs| {
3836 printer(direction)
3837 .duration_to_string(&SignedDuration::from_secs(secs))
3838 };
3839
3840 insta::assert_snapshot!(p(Direction::Auto, 1), @"00:00:01");
3841 insta::assert_snapshot!(p(Direction::Sign, 1), @"00:00:01");
3842 insta::assert_snapshot!(p(Direction::ForceSign, 1), @"+00:00:01");
3843 insta::assert_snapshot!(p(Direction::Suffix, 1), @"00:00:01");
3844
3845 insta::assert_snapshot!(p(Direction::Auto, -1), @"-00:00:01");
3846 insta::assert_snapshot!(p(Direction::Sign, -1), @"-00:00:01");
3847 insta::assert_snapshot!(p(Direction::ForceSign, -1), @"-00:00:01");
3848 insta::assert_snapshot!(p(Direction::Suffix, -1), @"00:00:01 ago");
3849 }
3850
3851 #[test]
3852 fn print_signed_duration_hms_fraction_auto() {
3853 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3854 let p = |secs, nanos| {
3855 printer().duration_to_string(&SignedDuration::new(secs, nanos))
3856 };
3857
3858 insta::assert_snapshot!(p(0, 1), @"00:00:00.000000001");
3859 insta::assert_snapshot!(p(0, -1), @"-00:00:00.000000001");
3860 insta::assert_snapshot!(
3861 printer().direction(Direction::ForceSign).duration_to_string(
3862 &SignedDuration::new(0, 1),
3863 ),
3864 @"+00:00:00.000000001",
3865 );
3866
3867 insta::assert_snapshot!(
3868 p(1, 123),
3869 @"00:00:01.000000123",
3870 );
3871 insta::assert_snapshot!(
3872 p(1, 123_000_000),
3873 @"00:00:01.123",
3874 );
3875 insta::assert_snapshot!(
3876 p(1, 1_123_000_000),
3877 @"00:00:02.123",
3878 );
3879 insta::assert_snapshot!(
3880 p(61, 1_123_000_000),
3881 @"00:01:02.123",
3882 );
3883 }
3884
3885 #[test]
3886 fn print_signed_duration_hms_fraction_fixed_precision() {
3887 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3888 let p = |precision, secs, nanos| {
3889 printer()
3890 .precision(Some(precision))
3891 .duration_to_string(&SignedDuration::new(secs, nanos))
3892 };
3893
3894 insta::assert_snapshot!(p(3, 1, 0), @"00:00:01.000");
3895 insta::assert_snapshot!(
3896 p(3, 1, 1_000_000),
3897 @"00:00:01.001",
3898 );
3899 insta::assert_snapshot!(
3900 p(3, 1, 123_000_000),
3901 @"00:00:01.123",
3902 );
3903 insta::assert_snapshot!(
3904 p(3, 1, 100_000_000),
3905 @"00:00:01.100",
3906 );
3907
3908 insta::assert_snapshot!(p(0, 1, 0), @"00:00:01");
3909 insta::assert_snapshot!(p(0, 1, 1_000_000), @"00:00:01");
3910 insta::assert_snapshot!(
3911 p(1, 1, 999_000_000),
3912 @"00:00:01.9",
3913 );
3914 }
3915
3916 #[test]
3917 fn print_unsigned_duration_hms() {
3918 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3919 let p = |secs| {
3920 printer().unsigned_duration_to_string(
3921 &core::time::Duration::from_secs(secs),
3922 )
3923 };
3924
3925 insta::assert_snapshot!(p(1), @"00:00:01");
3929 insta::assert_snapshot!(p(2), @"00:00:02");
3930 insta::assert_snapshot!(p(10), @"00:00:10");
3931 insta::assert_snapshot!(p(100), @"00:01:40");
3932
3933 insta::assert_snapshot!(p(1 * 60), @"00:01:00");
3934 insta::assert_snapshot!(p(2 * 60), @"00:02:00");
3935 insta::assert_snapshot!(p(10 * 60), @"00:10:00");
3936 insta::assert_snapshot!(p(100 * 60), @"01:40:00");
3937
3938 insta::assert_snapshot!(p(1 * 60 * 60), @"01:00:00");
3939 insta::assert_snapshot!(p(2 * 60 * 60), @"02:00:00");
3940 insta::assert_snapshot!(p(10 * 60 * 60), @"10:00:00");
3941 insta::assert_snapshot!(p(100 * 60 * 60), @"100:00:00");
3942
3943 insta::assert_snapshot!(
3944 p(60 * 60 + 60 + 1),
3945 @"01:01:01",
3946 );
3947 insta::assert_snapshot!(
3948 p(2 * 60 * 60 + 2 * 60 + 2),
3949 @"02:02:02",
3950 );
3951 insta::assert_snapshot!(
3952 p(10 * 60 * 60 + 10 * 60 + 10),
3953 @"10:10:10",
3954 );
3955 insta::assert_snapshot!(
3956 p(100 * 60 * 60 + 100 * 60 + 100),
3957 @"101:41:40",
3958 );
3959 }
3960
3961 #[test]
3962 fn print_unsigned_duration_hms_sign() {
3963 let printer = |direction| {
3964 SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
3965 };
3966 let p = |direction, secs| {
3967 printer(direction).unsigned_duration_to_string(
3968 &core::time::Duration::from_secs(secs),
3969 )
3970 };
3971
3972 insta::assert_snapshot!(p(Direction::Auto, 1), @"00:00:01");
3973 insta::assert_snapshot!(p(Direction::Sign, 1), @"00:00:01");
3974 insta::assert_snapshot!(p(Direction::ForceSign, 1), @"+00:00:01");
3975 insta::assert_snapshot!(p(Direction::Suffix, 1), @"00:00:01");
3976 }
3977
3978 #[test]
3979 fn print_unsigned_duration_hms_fraction_auto() {
3980 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3981 let p = |secs, nanos| {
3982 printer().unsigned_duration_to_string(&core::time::Duration::new(
3983 secs, nanos,
3984 ))
3985 };
3986
3987 insta::assert_snapshot!(p(0, 1), @"00:00:00.000000001");
3988 insta::assert_snapshot!(
3989 printer().direction(Direction::ForceSign).duration_to_string(
3990 &SignedDuration::new(0, 1),
3991 ),
3992 @"+00:00:00.000000001",
3993 );
3994
3995 insta::assert_snapshot!(
3996 p(1, 123),
3997 @"00:00:01.000000123",
3998 );
3999 insta::assert_snapshot!(
4000 p(1, 123_000_000),
4001 @"00:00:01.123",
4002 );
4003 insta::assert_snapshot!(
4004 p(1, 1_123_000_000),
4005 @"00:00:02.123",
4006 );
4007 insta::assert_snapshot!(
4008 p(61, 1_123_000_000),
4009 @"00:01:02.123",
4010 );
4011 }
4012
4013 #[test]
4014 fn print_unsigned_duration_hms_fraction_fixed_precision() {
4015 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
4016 let p = |precision, secs, nanos| {
4017 printer().precision(Some(precision)).unsigned_duration_to_string(
4018 &core::time::Duration::new(secs, nanos),
4019 )
4020 };
4021
4022 insta::assert_snapshot!(p(3, 1, 0), @"00:00:01.000");
4023 insta::assert_snapshot!(
4024 p(3, 1, 1_000_000),
4025 @"00:00:01.001",
4026 );
4027 insta::assert_snapshot!(
4028 p(3, 1, 123_000_000),
4029 @"00:00:01.123",
4030 );
4031 insta::assert_snapshot!(
4032 p(3, 1, 100_000_000),
4033 @"00:00:01.100",
4034 );
4035
4036 insta::assert_snapshot!(p(0, 1, 0), @"00:00:01");
4037 insta::assert_snapshot!(p(0, 1, 1_000_000), @"00:00:01");
4038 insta::assert_snapshot!(
4039 p(1, 1, 999_000_000),
4040 @"00:00:01.9",
4041 );
4042 }
4043}