1use crate::{
2 fmt::{
3 buffer::{ArrayBuffer, BorrowedBuffer},
4 Write,
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
19const MAX_SPAN_LEN: usize = 306;
34
35const MAX_SIGNED_DURATION_LEN: usize = 194;
41
42const MAX_UNSIGNED_DURATION_LEN: usize = 190;
55
56#[derive(Clone, Copy, Debug)]
82#[non_exhaustive]
83pub enum Designator {
84 Verbose,
87 Short,
90 Compact,
95 HumanTime,
122}
123
124#[derive(Clone, Copy, Debug)]
167#[non_exhaustive]
168pub enum Spacing {
169 None,
176 BetweenUnits,
181 BetweenUnitsAndDesignators,
187}
188
189impl Spacing {
190 fn between_units(self) -> Option<u8> {
191 match self {
192 Spacing::None => None,
193 Spacing::BetweenUnits => Some(b' '),
194 Spacing::BetweenUnitsAndDesignators => Some(b' '),
195 }
196 }
197
198 fn between_units_and_designators(self) -> Option<u8> {
199 match self {
200 Spacing::None => None,
201 Spacing::BetweenUnits => None,
202 Spacing::BetweenUnitsAndDesignators => Some(b' '),
203 }
204 }
205}
206
207#[derive(Clone, Copy, Debug)]
230#[non_exhaustive]
231pub enum Direction {
232 Auto,
244 Sign,
248 ForceSign,
252 Suffix,
256}
257
258impl Direction {
259 fn sign(
265 self,
266 printer: &SpanPrinter,
267 has_calendar: bool,
268 signum: i8,
269 ) -> Option<DirectionSign> {
270 match self {
271 Direction::Auto => match printer.spacing {
272 Spacing::None => {
273 if signum < 0 {
274 Some(DirectionSign::Prefix(b'-'))
275 } else {
276 None
277 }
278 }
279 Spacing::BetweenUnits
280 | Spacing::BetweenUnitsAndDesignators => {
281 if signum < 0 {
282 if printer.hms && !has_calendar {
283 Some(DirectionSign::Prefix(b'-'))
284 } else {
285 Some(DirectionSign::Suffix)
286 }
287 } else {
288 None
289 }
290 }
291 },
292 Direction::Sign => {
293 if signum < 0 {
294 Some(DirectionSign::Prefix(b'-'))
295 } else {
296 None
297 }
298 }
299 Direction::ForceSign => {
300 Some(DirectionSign::Prefix(if signum < 0 {
301 b'-'
302 } else {
303 b'+'
304 }))
305 }
306 Direction::Suffix => {
307 if signum < 0 {
308 Some(DirectionSign::Suffix)
309 } else {
310 None
311 }
312 }
313 }
314 }
315}
316
317#[derive(Clone, Copy, Debug)]
319enum DirectionSign {
320 Prefix(u8),
321 Suffix,
322}
323
324#[derive(Clone, Copy, Debug)]
358#[non_exhaustive]
359pub enum FractionalUnit {
360 Hour,
365 Minute,
370 Second,
372 Millisecond,
374 Microsecond,
376}
377
378impl From<FractionalUnit> for Unit {
379 fn from(u: FractionalUnit) -> Unit {
380 match u {
381 FractionalUnit::Hour => Unit::Hour,
382 FractionalUnit::Minute => Unit::Minute,
383 FractionalUnit::Second => Unit::Second,
384 FractionalUnit::Millisecond => Unit::Millisecond,
385 FractionalUnit::Microsecond => Unit::Microsecond,
386 }
387 }
388}
389
390#[derive(Clone, Debug)]
497pub struct SpanPrinter {
498 designators: &'static Designators,
499 spacing: Spacing,
500 direction: Direction,
501 fractional: Option<FractionalUnit>,
502 comma_after_designator: bool,
503 hms: bool,
504 padding: Option<u8>,
505 precision: Option<u8>,
506 zero_unit: Unit,
507}
508
509impl SpanPrinter {
510 #[inline]
532 pub const fn new() -> SpanPrinter {
533 SpanPrinter {
534 designators: Designators::new(Designator::Compact),
535 spacing: Spacing::BetweenUnits,
536 direction: Direction::Auto,
537 fractional: None,
538 comma_after_designator: false,
539 hms: false,
540 padding: None,
541 precision: None,
542 zero_unit: Unit::Second,
543 }
544 }
545
546 #[inline]
575 pub const fn designator(self, designator: Designator) -> SpanPrinter {
576 SpanPrinter { designators: Designators::new(designator), ..self }
577 }
578
579 #[inline]
639 pub const fn spacing(self, spacing: Spacing) -> SpanPrinter {
640 SpanPrinter { spacing, ..self }
641 }
642
643 #[inline]
666 pub const fn direction(self, direction: Direction) -> SpanPrinter {
667 SpanPrinter { direction, ..self }
668 }
669
670 #[inline]
720 pub const fn fractional(
721 self,
722 unit: Option<FractionalUnit>,
723 ) -> SpanPrinter {
724 SpanPrinter { fractional: unit, ..self }
725 }
726
727 #[inline]
748 pub const fn comma_after_designator(self, yes: bool) -> SpanPrinter {
749 SpanPrinter { comma_after_designator: yes, ..self }
750 }
751
752 #[inline]
851 pub const fn hours_minutes_seconds(self, yes: bool) -> SpanPrinter {
852 SpanPrinter { hms: yes, ..self }
853 }
854
855 #[inline]
899 pub const fn padding(self, digits: u8) -> SpanPrinter {
900 SpanPrinter { padding: Some(digits), ..self }
901 }
902
903 #[inline]
955 pub const fn precision(self, precision: Option<u8>) -> SpanPrinter {
956 SpanPrinter { precision, ..self }
957 }
958
959 #[inline]
1014 pub const fn zero_unit(self, unit: Unit) -> SpanPrinter {
1015 SpanPrinter { zero_unit: unit, ..self }
1016 }
1017
1018 #[cfg(any(test, feature = "alloc"))]
1034 pub fn span_to_string(&self, span: &Span) -> alloc::string::String {
1035 let mut buf = alloc::string::String::with_capacity(4);
1036 self.print_span(span, &mut buf).unwrap();
1038 buf
1039 }
1040
1041 #[cfg(any(test, feature = "alloc"))]
1075 pub fn duration_to_string(
1076 &self,
1077 duration: &SignedDuration,
1078 ) -> alloc::string::String {
1079 let mut buf = alloc::string::String::with_capacity(4);
1080 self.print_duration(duration, &mut buf).unwrap();
1082 buf
1083 }
1084
1085 #[cfg(any(test, feature = "alloc"))]
1118 pub fn unsigned_duration_to_string(
1119 &self,
1120 duration: &core::time::Duration,
1121 ) -> alloc::string::String {
1122 let mut buf = alloc::string::String::with_capacity(4);
1123 self.print_unsigned_duration(duration, &mut buf).unwrap();
1125 buf
1126 }
1127
1128 pub fn print_span<W: Write>(
1152 &self,
1153 span: &Span,
1154 mut wtr: W,
1155 ) -> Result<(), Error> {
1156 let mut buf = ArrayBuffer::<MAX_SPAN_LEN>::default();
1157 let mut bbuf = buf.as_borrowed();
1158 if self.hms {
1159 self.print_span_hms(span, &mut bbuf);
1160 } else {
1161 self.print_span_designators(span, &mut bbuf);
1162 }
1163 wtr.write_str(bbuf.filled())
1164 }
1165
1166 pub fn print_duration<W: Write>(
1199 &self,
1200 duration: &SignedDuration,
1201 mut wtr: W,
1202 ) -> Result<(), Error> {
1203 let mut buf = ArrayBuffer::<MAX_SIGNED_DURATION_LEN>::default();
1204 let mut bbuf = buf.as_borrowed();
1205 if self.hms {
1206 self.print_signed_duration_hms(duration, &mut bbuf);
1207 } else {
1208 self.print_signed_duration_designators(duration, &mut bbuf);
1209 }
1210 wtr.write_str(bbuf.filled())
1211 }
1212
1213 pub fn print_unsigned_duration<W: Write>(
1243 &self,
1244 duration: &core::time::Duration,
1245 mut wtr: W,
1246 ) -> Result<(), Error> {
1247 let mut buf = ArrayBuffer::<MAX_UNSIGNED_DURATION_LEN>::default();
1248 let mut bbuf = buf.as_borrowed();
1249 if self.hms {
1250 self.print_unsigned_duration_hms(duration, &mut bbuf);
1251 } else {
1252 self.print_unsigned_duration_designators(duration, &mut bbuf);
1253 }
1254 wtr.write_str(bbuf.filled())
1255 }
1256
1257 fn print_span_designators(
1258 &self,
1259 span: &Span,
1260 bbuf: &mut BorrowedBuffer<'_>,
1261 ) {
1262 let mut wtr = DesignatorWriter::new(self, bbuf, false, span.signum());
1263 wtr.maybe_write_prefix_sign();
1264 match self.fractional {
1265 None => {
1266 self.print_span_designators_non_fraction(span, &mut wtr);
1267 }
1268 Some(unit) => {
1269 self.print_span_designators_fractional(span, unit, &mut wtr);
1270 }
1271 }
1272 wtr.maybe_write_zero();
1273 wtr.maybe_write_suffix_sign();
1274 }
1275
1276 fn print_span_designators_non_fraction<'p, 'w, 'd>(
1277 &self,
1278 span: &Span,
1279 wtr: &mut DesignatorWriter<'p, 'w, 'd>,
1280 ) {
1281 let units = span.units();
1282
1283 if units.contains(Unit::Year) {
1284 wtr.write(
1285 Unit::Year,
1286 span.get_years_unsigned().get().unsigned_abs().into(),
1287 );
1288 }
1289 if units.contains(Unit::Month) {
1290 wtr.write(
1291 Unit::Month,
1292 span.get_months_unsigned().get().unsigned_abs().into(),
1293 );
1294 }
1295 if units.contains(Unit::Week) {
1296 wtr.write(
1297 Unit::Week,
1298 span.get_weeks_unsigned().get().unsigned_abs().into(),
1299 );
1300 }
1301 if units.contains(Unit::Day) {
1302 wtr.write(
1303 Unit::Day,
1304 span.get_days_unsigned().get().unsigned_abs().into(),
1305 );
1306 }
1307 if units.contains(Unit::Hour) {
1308 wtr.write(
1309 Unit::Hour,
1310 span.get_hours_unsigned().get().unsigned_abs().into(),
1311 );
1312 }
1313 if units.contains(Unit::Minute) {
1314 wtr.write(
1315 Unit::Minute,
1316 span.get_minutes_unsigned().get().unsigned_abs(),
1317 );
1318 }
1319 if units.contains(Unit::Second) {
1320 wtr.write(
1321 Unit::Second,
1322 span.get_seconds_unsigned().get().unsigned_abs(),
1323 );
1324 }
1325 if units.contains(Unit::Millisecond) {
1326 wtr.write(
1327 Unit::Millisecond,
1328 span.get_milliseconds_unsigned().get().unsigned_abs(),
1329 );
1330 }
1331 if units.contains(Unit::Microsecond) {
1332 wtr.write(
1333 Unit::Microsecond,
1334 span.get_microseconds_unsigned().get().unsigned_abs(),
1335 );
1336 }
1337 if units.contains(Unit::Nanosecond) {
1338 wtr.write(
1339 Unit::Nanosecond,
1340 span.get_nanoseconds_unsigned().get().unsigned_abs(),
1341 );
1342 }
1343 }
1344
1345 fn print_span_calendar_designators_non_fraction<'p, 'w, 'd>(
1346 &self,
1347 span: &Span,
1348 wtr: &mut DesignatorWriter<'p, 'w, 'd>,
1349 ) {
1350 let units = span.units();
1351
1352 if units.contains(Unit::Year) {
1353 wtr.write(
1354 Unit::Year,
1355 span.get_years_unsigned().get().unsigned_abs().into(),
1356 );
1357 }
1358 if units.contains(Unit::Month) {
1359 wtr.write(
1360 Unit::Month,
1361 span.get_months_unsigned().get().unsigned_abs().into(),
1362 );
1363 }
1364 if units.contains(Unit::Week) {
1365 wtr.write(
1366 Unit::Week,
1367 span.get_weeks_unsigned().get().unsigned_abs().into(),
1368 );
1369 }
1370 if units.contains(Unit::Day) {
1371 wtr.write(
1372 Unit::Day,
1373 span.get_days_unsigned().get().unsigned_abs().into(),
1374 );
1375 }
1376 }
1377
1378 #[inline(never)]
1379 fn print_span_designators_fractional<'p, 'w, 'd>(
1380 &self,
1381 span: &Span,
1382 unit: FractionalUnit,
1383 wtr: &mut DesignatorWriter<'p, 'w, 'd>,
1384 ) {
1385 let split_at = Unit::from(unit).next().unwrap();
1388 let non_fractional = span.without_lower(split_at);
1389 let fractional = span.only_lower(split_at);
1390 self.print_span_designators_non_fraction(&non_fractional, wtr);
1391 wtr.write_fractional_duration(
1392 unit,
1393 &fractional.to_duration_invariant().unsigned_abs(),
1394 );
1395 }
1396
1397 fn print_span_hms(&self, span: &Span, bbuf: &mut BorrowedBuffer<'_>) {
1398 let has_cal = !span.units().only_calendar().is_empty();
1399 let mut wtr =
1400 DesignatorWriter::new(self, bbuf, has_cal, span.signum());
1401 let span = span.abs();
1402
1403 wtr.maybe_write_prefix_sign();
1404 if has_cal {
1405 self.print_span_calendar_designators_non_fraction(&span, &mut wtr);
1406 wtr.finish_preceding();
1407 if matches!(self.spacing, Spacing::None) {
1412 wtr.bbuf.write_ascii_char(b' ');
1413 }
1414 }
1415
1416 let padding = self.padding.unwrap_or(2);
1417 wtr.bbuf.write_int_pad(
1418 span.get_hours_ranged().get().unsigned_abs(),
1419 b'0',
1420 padding,
1421 );
1422 wtr.bbuf.write_ascii_char(b':');
1423 wtr.bbuf.write_int_pad(
1424 span.get_minutes_ranged().get().unsigned_abs(),
1425 b'0',
1426 padding,
1427 );
1428 wtr.bbuf.write_ascii_char(b':');
1429 let fp = FractionalPrinter::from_span_seconds(
1434 &span.only_lower(Unit::Minute),
1435 padding,
1436 self.precision,
1437 );
1438 fp.print(wtr.bbuf);
1439 wtr.maybe_write_suffix_sign();
1440 }
1441
1442 fn print_signed_duration_designators(
1443 &self,
1444 dur: &SignedDuration,
1445 bbuf: &mut BorrowedBuffer<'_>,
1446 ) {
1447 let mut wtr = DesignatorWriter::new(self, bbuf, false, dur.signum());
1448 wtr.maybe_write_prefix_sign();
1449 self.print_duration_designators(&dur.unsigned_abs(), &mut wtr);
1450 wtr.maybe_write_zero();
1451 wtr.maybe_write_suffix_sign();
1452 }
1453
1454 fn print_unsigned_duration_designators(
1455 &self,
1456 dur: &core::time::Duration,
1457 bbuf: &mut BorrowedBuffer<'_>,
1458 ) {
1459 let mut wtr = DesignatorWriter::new(self, bbuf, false, 1);
1460 wtr.maybe_write_prefix_sign();
1461 self.print_duration_designators(dur, &mut wtr);
1462 wtr.maybe_write_zero();
1463 }
1464
1465 fn print_duration_designators(
1466 &self,
1467 dur: &core::time::Duration,
1468 wtr: &mut DesignatorWriter<'_, '_, '_>,
1469 ) {
1470 match self.fractional {
1471 None => {
1472 let mut secs = dur.as_secs();
1473 wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
1474 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1475 wtr.write(Unit::Minute, secs / SECS_PER_MIN);
1476 wtr.write(Unit::Second, secs % SECS_PER_MIN);
1477 let mut nanos = dur.subsec_nanos();
1478 wtr.write(Unit::Millisecond, (nanos / NANOS_PER_MILLI).into());
1479 nanos %= NANOS_PER_MILLI;
1480 wtr.write(Unit::Microsecond, (nanos / NANOS_PER_MICRO).into());
1481 wtr.write(Unit::Nanosecond, (nanos % NANOS_PER_MICRO).into());
1482 }
1483 Some(FractionalUnit::Hour) => {
1484 wtr.write_fractional_duration(FractionalUnit::Hour, &dur);
1485 }
1486 Some(FractionalUnit::Minute) => {
1487 let mut secs = dur.as_secs();
1488 wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
1489 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1490
1491 let leftovers =
1492 core::time::Duration::new(secs, dur.subsec_nanos());
1493 wtr.write_fractional_duration(
1494 FractionalUnit::Minute,
1495 &leftovers,
1496 );
1497 }
1498 Some(FractionalUnit::Second) => {
1499 let mut secs = dur.as_secs();
1500 wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
1501 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1502 wtr.write(Unit::Minute, secs / SECS_PER_MIN);
1503 secs %= SECS_PER_MIN;
1504
1505 let leftovers =
1506 core::time::Duration::new(secs, dur.subsec_nanos());
1507 wtr.write_fractional_duration(
1508 FractionalUnit::Second,
1509 &leftovers,
1510 );
1511 }
1512 Some(FractionalUnit::Millisecond) => {
1513 let mut secs = dur.as_secs();
1514 wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
1515 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1516 wtr.write(Unit::Minute, secs / SECS_PER_MIN);
1517 wtr.write(Unit::Second, secs % SECS_PER_MIN);
1518
1519 let leftovers =
1520 core::time::Duration::new(0, dur.subsec_nanos());
1521 wtr.write_fractional_duration(
1522 FractionalUnit::Millisecond,
1523 &leftovers,
1524 );
1525 }
1526 Some(FractionalUnit::Microsecond) => {
1527 let mut secs = dur.as_secs();
1528 wtr.write(Unit::Hour, secs / SECS_PER_HOUR);
1529 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1530 wtr.write(Unit::Minute, secs / SECS_PER_MIN);
1531 wtr.write(Unit::Second, secs % SECS_PER_MIN);
1532 let mut nanos = dur.subsec_nanos();
1533 wtr.write(Unit::Millisecond, (nanos / NANOS_PER_MILLI).into());
1534 nanos %= NANOS_PER_MILLI;
1535
1536 let leftovers = core::time::Duration::new(0, nanos);
1537 wtr.write_fractional_duration(
1538 FractionalUnit::Microsecond,
1539 &leftovers,
1540 );
1541 }
1542 }
1543 }
1544
1545 fn print_signed_duration_hms(
1546 &self,
1547 dur: &SignedDuration,
1548 bbuf: &mut BorrowedBuffer<'_>,
1549 ) {
1550 if dur.is_negative() {
1551 if !matches!(self.direction, Direction::Suffix) {
1552 bbuf.write_ascii_char(b'-');
1553 }
1554 } else if let Direction::ForceSign = self.direction {
1555 bbuf.write_ascii_char(b'+');
1556 }
1557 self.print_duration_hms(&dur.unsigned_abs(), bbuf);
1558 if dur.is_negative() {
1559 if matches!(self.direction, Direction::Suffix) {
1560 bbuf.write_str(" ago");
1561 }
1562 }
1563 }
1564
1565 fn print_unsigned_duration_hms(
1566 &self,
1567 dur: &core::time::Duration,
1568 bbuf: &mut BorrowedBuffer<'_>,
1569 ) {
1570 if let Direction::ForceSign = self.direction {
1571 bbuf.write_ascii_char(b'+');
1572 }
1573 self.print_duration_hms(dur, bbuf);
1574 }
1575
1576 fn print_duration_hms(
1577 &self,
1578 udur: &core::time::Duration,
1579 bbuf: &mut BorrowedBuffer<'_>,
1580 ) {
1581 let padding = self.padding.unwrap_or(2);
1588
1589 let mut secs = udur.as_secs();
1590 let hours = secs / (MINS_PER_HOUR * SECS_PER_MIN);
1592 secs %= MINS_PER_HOUR * SECS_PER_MIN;
1593 let minutes = secs / SECS_PER_MIN;
1595 secs = secs % SECS_PER_MIN;
1597
1598 bbuf.write_int_pad(hours, b'0', padding);
1599 bbuf.write_ascii_char(b':');
1600 bbuf.write_int_pad(minutes, b'0', padding);
1601 bbuf.write_ascii_char(b':');
1602 let fp = FractionalPrinter::from_duration_seconds(
1603 &core::time::Duration::new(secs, udur.subsec_nanos()),
1605 padding,
1606 self.precision,
1607 );
1608 fp.print(bbuf);
1609 }
1610}
1611
1612impl Default for SpanPrinter {
1613 fn default() -> SpanPrinter {
1614 SpanPrinter::new()
1615 }
1616}
1617
1618#[derive(Clone, Debug)]
1624struct Designators {
1625 singular: [&'static str; 10],
1626 plural: [&'static str; 10],
1627}
1628
1629impl Designators {
1630 const VERBOSE_SINGULAR: [&'static str; 10] = [
1631 "nanosecond",
1632 "microsecond",
1633 "millisecond",
1634 "second",
1635 "minute",
1636 "hour",
1637 "day",
1638 "week",
1639 "month",
1640 "year",
1641 ];
1642 const VERBOSE_PLURAL: [&'static str; 10] = [
1643 "nanoseconds",
1644 "microseconds",
1645 "milliseconds",
1646 "seconds",
1647 "minutes",
1648 "hours",
1649 "days",
1650 "weeks",
1651 "months",
1652 "years",
1653 ];
1654
1655 const SHORT_SINGULAR: [&'static str; 10] =
1656 ["nsec", "µsec", "msec", "sec", "min", "hr", "day", "wk", "mo", "yr"];
1657 const SHORT_PLURAL: [&'static str; 10] = [
1658 "nsecs", "µsecs", "msecs", "secs", "mins", "hrs", "days", "wks",
1659 "mos", "yrs",
1660 ];
1661
1662 const COMPACT: [&'static str; 10] =
1663 ["ns", "µs", "ms", "s", "m", "h", "d", "w", "mo", "y"];
1664
1665 const HUMAN_TIME_SINGULAR: [&'static str; 10] =
1666 ["ns", "us", "ms", "s", "m", "h", "d", "w", "month", "y"];
1667 const HUMAN_TIME_PLURAL: [&'static str; 10] =
1668 ["ns", "us", "ms", "s", "m", "h", "d", "w", "months", "y"];
1669
1670 const fn new(config: Designator) -> &'static Designators {
1671 match config {
1672 Designator::Verbose => &Designators {
1673 singular: Designators::VERBOSE_SINGULAR,
1674 plural: Designators::VERBOSE_PLURAL,
1675 },
1676 Designator::Short => &Designators {
1677 singular: Designators::SHORT_SINGULAR,
1678 plural: Designators::SHORT_PLURAL,
1679 },
1680 Designator::Compact => &Designators {
1681 singular: Designators::COMPACT,
1682 plural: Designators::COMPACT,
1683 },
1684 Designator::HumanTime => &Designators {
1685 singular: Designators::HUMAN_TIME_SINGULAR,
1686 plural: Designators::HUMAN_TIME_PLURAL,
1687 },
1688 }
1689 }
1690
1691 fn designator(&self, unit: impl Into<Unit>, plural: bool) -> &'static str {
1692 let unit = unit.into();
1693 let index = unit as usize;
1694 if plural {
1695 self.plural[index]
1696 } else {
1697 self.singular[index]
1698 }
1699 }
1700}
1701
1702#[derive(Debug)]
1708struct DesignatorWriter<'p, 'w, 'd> {
1709 printer: &'p SpanPrinter,
1710 bbuf: &'w mut BorrowedBuffer<'d>,
1711 sign: Option<DirectionSign>,
1712 padding: u8,
1713 precision: Option<u8>,
1714 written_non_zero_unit: bool,
1715}
1716
1717impl<'p, 'w, 'd> DesignatorWriter<'p, 'w, 'd> {
1718 fn new(
1719 printer: &'p SpanPrinter,
1720 bbuf: &'w mut BorrowedBuffer<'d>,
1721 has_calendar: bool,
1722 signum: i8,
1723 ) -> DesignatorWriter<'p, 'w, 'd> {
1724 let sign = printer.direction.sign(printer, has_calendar, signum);
1725 DesignatorWriter {
1726 printer,
1727 bbuf,
1728 sign,
1729 padding: printer.padding.unwrap_or(0),
1730 precision: printer.precision,
1731 written_non_zero_unit: false,
1732 }
1733 }
1734
1735 fn maybe_write_prefix_sign(&mut self) {
1736 if let Some(DirectionSign::Prefix(sign)) = self.sign {
1737 self.bbuf.write_ascii_char(sign);
1738 }
1739 }
1740
1741 fn maybe_write_suffix_sign(&mut self) {
1742 if let Some(DirectionSign::Suffix) = self.sign {
1743 self.bbuf.write_str(" ago");
1744 }
1745 }
1746
1747 fn maybe_write_zero(&mut self) {
1748 #[cold]
1749 #[inline(never)]
1750 fn imp(wtr: &mut DesignatorWriter<'_, '_, '_>) {
1751 wtr.bbuf.write_int_pad(0u64, b'0', wtr.padding);
1752 if let Some(byte) =
1753 wtr.printer.spacing.between_units_and_designators()
1754 {
1755 wtr.bbuf.write_ascii_char(byte);
1756 }
1757 let unit = wtr
1760 .printer
1761 .fractional
1762 .map(Unit::from)
1763 .unwrap_or(wtr.printer.zero_unit);
1764 wtr.bbuf.write_str(wtr.printer.designators.designator(unit, true));
1765 }
1766
1767 if !self.written_non_zero_unit {
1768 imp(self);
1769 }
1770 }
1771
1772 #[inline(never)]
1773 fn write(&mut self, unit: Unit, value: u64) {
1774 if value == 0 {
1775 return;
1776 }
1777 self.finish_preceding();
1778 self.written_non_zero_unit = true;
1779 self.bbuf.write_int_pad0(value, self.padding);
1780 if let Some(byte) =
1781 self.printer.spacing.between_units_and_designators()
1782 {
1783 self.bbuf.write_ascii_char(byte);
1784 }
1785 self.bbuf
1786 .write_str(self.printer.designators.designator(unit, value != 1));
1787 }
1788
1789 fn write_fractional_duration(
1790 &mut self,
1791 unit: FractionalUnit,
1792 duration: &core::time::Duration,
1793 ) {
1794 let fp = FractionalPrinter::from_duration(
1795 duration,
1796 unit,
1797 self.padding,
1798 self.precision,
1799 );
1800 if !fp.must_write_digits() {
1801 return;
1802 }
1803 self.finish_preceding();
1804 self.written_non_zero_unit = true;
1805 fp.print(&mut *self.bbuf);
1806 if let Some(byte) =
1807 self.printer.spacing.between_units_and_designators()
1808 {
1809 self.bbuf.write_ascii_char(byte);
1810 }
1811 self.bbuf.write_str(
1812 self.printer.designators.designator(unit, fp.is_plural()),
1813 );
1814 }
1815
1816 fn finish_preceding(&mut self) {
1817 if self.written_non_zero_unit {
1818 if self.printer.comma_after_designator {
1819 self.bbuf.write_ascii_char(b',');
1820 }
1821 if let Some(byte) = self.printer.spacing.between_units() {
1822 self.bbuf.write_ascii_char(byte);
1823 }
1824 }
1825 }
1826}
1827
1828struct FractionalPrinter {
1833 integer: u64,
1834 fraction: u32,
1835 padding: u8,
1836 precision: Option<u8>,
1837}
1838
1839impl FractionalPrinter {
1840 fn from_span_seconds(
1850 span: &Span,
1851 padding: u8,
1852 precision: Option<u8>,
1853 ) -> FractionalPrinter {
1854 FractionalPrinter::from_duration_seconds(
1855 &span.to_duration_invariant().unsigned_abs(),
1856 padding,
1857 precision,
1858 )
1859 }
1860
1861 fn from_duration_seconds(
1863 dur: &core::time::Duration,
1864 padding: u8,
1865 precision: Option<u8>,
1866 ) -> FractionalPrinter {
1867 let integer = dur.as_secs();
1868 let fraction = u32::from(dur.subsec_nanos());
1869 FractionalPrinter { integer, fraction, padding, precision }
1870 }
1871
1872 fn from_duration(
1874 dur: &core::time::Duration,
1875 unit: FractionalUnit,
1876 padding: u8,
1877 precision: Option<u8>,
1878 ) -> FractionalPrinter {
1879 match unit {
1880 FractionalUnit::Hour => {
1881 let integer = dur.as_secs() / SECS_PER_HOUR;
1882 let mut fraction = dur.as_nanos() % NANOS_PER_HOUR;
1883 fraction /= u128::from(SECS_PER_HOUR);
1885 let fraction = u32::try_from(fraction).unwrap();
1887 FractionalPrinter { integer, fraction, padding, precision }
1888 }
1889 FractionalUnit::Minute => {
1890 let integer = dur.as_secs() / SECS_PER_MIN;
1891 let mut fraction = dur.as_nanos() % NANOS_PER_MIN;
1892 fraction /= u128::from(SECS_PER_MIN);
1894 let fraction = u32::try_from(fraction).unwrap();
1896 FractionalPrinter { integer, fraction, padding, precision }
1897 }
1898 FractionalUnit::Second => {
1899 let integer = dur.as_secs();
1900 let fraction = u32::from(dur.subsec_nanos());
1901 FractionalPrinter { integer, fraction, padding, precision }
1902 }
1903 FractionalUnit::Millisecond => {
1904 let integer = u64::try_from(dur.as_millis()).unwrap();
1913 let fraction =
1914 u32::from((dur.subsec_nanos() % NANOS_PER_MILLI) * 1_000);
1915 FractionalPrinter { integer, fraction, padding, precision }
1916 }
1917 FractionalUnit::Microsecond => {
1918 let integer = u64::try_from(dur.as_micros()).unwrap();
1927 let fraction = u32::from(
1928 (dur.subsec_nanos() % NANOS_PER_MICRO) * 1_000_000,
1929 );
1930 FractionalPrinter { integer, fraction, padding, precision }
1931 }
1932 }
1933 }
1934
1935 fn is_zero(&self) -> bool {
1937 self.integer == 0 && self.fraction == 0
1938 }
1939
1940 fn is_plural(&self) -> bool {
1943 self.integer != 1
1944 || (self.fraction != 0 && !self.has_zero_fixed_precision())
1945 }
1946
1947 fn must_write_digits(&self) -> bool {
1954 !self.is_zero() || self.has_non_zero_fixed_precision()
1955 }
1956
1957 fn will_write_digits(&self) -> bool {
1963 self.precision.map_or_else(|| self.fraction != 0, |p| p > 0)
1964 }
1965
1966 fn has_non_zero_fixed_precision(&self) -> bool {
1973 self.precision.map_or(false, |p| p > 0)
1974 }
1975
1976 fn has_zero_fixed_precision(&self) -> bool {
1979 self.precision.map_or(false, |p| p == 0)
1980 }
1981
1982 fn print(&self, bbuf: &mut BorrowedBuffer<'_>) {
1988 bbuf.write_int_pad(self.integer, b'0', self.padding);
1989 if self.will_write_digits() {
1990 bbuf.write_ascii_char(b'.');
1991 bbuf.write_fraction(self.precision, self.fraction);
1992 }
1993 }
1994}
1995
1996#[cfg(feature = "alloc")]
1997#[cfg(test)]
1998mod tests {
1999 use crate::ToSpan;
2000
2001 use super::*;
2002
2003 #[test]
2004 fn print_span_designator_default() {
2005 let printer = || SpanPrinter::new();
2006 let p = |span| printer().span_to_string(&span);
2007
2008 insta::assert_snapshot!(p(1.second()), @"1s");
2009 insta::assert_snapshot!(p(2.seconds()), @"2s");
2010 insta::assert_snapshot!(p(10.seconds()), @"10s");
2011 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m 40s");
2012
2013 insta::assert_snapshot!(p(1.minute()), @"1m");
2014 insta::assert_snapshot!(p(2.minutes()), @"2m");
2015 insta::assert_snapshot!(p(10.minutes()), @"10m");
2016 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h 40m");
2017
2018 insta::assert_snapshot!(p(1.hour()), @"1h");
2019 insta::assert_snapshot!(p(2.hours()), @"2h");
2020 insta::assert_snapshot!(p(10.hours()), @"10h");
2021 insta::assert_snapshot!(p(100.hours()), @"100h");
2022
2023 insta::assert_snapshot!(
2024 p(1.hour().minutes(1).seconds(1)),
2025 @"1h 1m 1s",
2026 );
2027 insta::assert_snapshot!(
2028 p(2.hours().minutes(2).seconds(2)),
2029 @"2h 2m 2s",
2030 );
2031 insta::assert_snapshot!(
2032 p(10.hours().minutes(10).seconds(10)),
2033 @"10h 10m 10s",
2034 );
2035 insta::assert_snapshot!(
2036 p(100.hours().minutes(100).seconds(100)),
2037 @"100h 100m 100s",
2038 );
2039
2040 insta::assert_snapshot!(p(-1.hour()), @"1h ago");
2041 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1h 30s ago");
2042
2043 insta::assert_snapshot!(
2044 p(1.second().milliseconds(2000)),
2045 @"1s 2000ms",
2046 );
2047 }
2048
2049 #[test]
2050 fn print_span_designator_verbose() {
2051 let printer = || SpanPrinter::new().designator(Designator::Verbose);
2052 let p = |span| printer().span_to_string(&span);
2053
2054 insta::assert_snapshot!(p(1.second()), @"1second");
2055 insta::assert_snapshot!(p(2.seconds()), @"2seconds");
2056 insta::assert_snapshot!(p(10.seconds()), @"10seconds");
2057 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1minute 40seconds");
2058
2059 insta::assert_snapshot!(p(1.minute()), @"1minute");
2060 insta::assert_snapshot!(p(2.minutes()), @"2minutes");
2061 insta::assert_snapshot!(p(10.minutes()), @"10minutes");
2062 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1hour 40minutes");
2063
2064 insta::assert_snapshot!(p(1.hour()), @"1hour");
2065 insta::assert_snapshot!(p(2.hours()), @"2hours");
2066 insta::assert_snapshot!(p(10.hours()), @"10hours");
2067 insta::assert_snapshot!(p(100.hours()), @"100hours");
2068
2069 insta::assert_snapshot!(
2070 p(1.hour().minutes(1).seconds(1)),
2071 @"1hour 1minute 1second",
2072 );
2073 insta::assert_snapshot!(
2074 p(2.hours().minutes(2).seconds(2)),
2075 @"2hours 2minutes 2seconds",
2076 );
2077 insta::assert_snapshot!(
2078 p(10.hours().minutes(10).seconds(10)),
2079 @"10hours 10minutes 10seconds",
2080 );
2081 insta::assert_snapshot!(
2082 p(100.hours().minutes(100).seconds(100)),
2083 @"100hours 100minutes 100seconds",
2084 );
2085
2086 insta::assert_snapshot!(p(-1.hour()), @"1hour ago");
2087 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1hour 30seconds ago");
2088 }
2089
2090 #[test]
2091 fn print_span_designator_short() {
2092 let printer = || SpanPrinter::new().designator(Designator::Short);
2093 let p = |span| printer().span_to_string(&span);
2094
2095 insta::assert_snapshot!(p(1.second()), @"1sec");
2096 insta::assert_snapshot!(p(2.seconds()), @"2secs");
2097 insta::assert_snapshot!(p(10.seconds()), @"10secs");
2098 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1min 40secs");
2099
2100 insta::assert_snapshot!(p(1.minute()), @"1min");
2101 insta::assert_snapshot!(p(2.minutes()), @"2mins");
2102 insta::assert_snapshot!(p(10.minutes()), @"10mins");
2103 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1hr 40mins");
2104
2105 insta::assert_snapshot!(p(1.hour()), @"1hr");
2106 insta::assert_snapshot!(p(2.hours()), @"2hrs");
2107 insta::assert_snapshot!(p(10.hours()), @"10hrs");
2108 insta::assert_snapshot!(p(100.hours()), @"100hrs");
2109
2110 insta::assert_snapshot!(
2111 p(1.hour().minutes(1).seconds(1)),
2112 @"1hr 1min 1sec",
2113 );
2114 insta::assert_snapshot!(
2115 p(2.hours().minutes(2).seconds(2)),
2116 @"2hrs 2mins 2secs",
2117 );
2118 insta::assert_snapshot!(
2119 p(10.hours().minutes(10).seconds(10)),
2120 @"10hrs 10mins 10secs",
2121 );
2122 insta::assert_snapshot!(
2123 p(100.hours().minutes(100).seconds(100)),
2124 @"100hrs 100mins 100secs",
2125 );
2126
2127 insta::assert_snapshot!(p(-1.hour()), @"1hr ago");
2128 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1hr 30secs ago");
2129 }
2130
2131 #[test]
2132 fn print_span_designator_compact() {
2133 let printer = || SpanPrinter::new().designator(Designator::Compact);
2134 let p = |span| printer().span_to_string(&span);
2135
2136 insta::assert_snapshot!(p(1.second()), @"1s");
2137 insta::assert_snapshot!(p(2.seconds()), @"2s");
2138 insta::assert_snapshot!(p(10.seconds()), @"10s");
2139 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m 40s");
2140
2141 insta::assert_snapshot!(p(1.minute()), @"1m");
2142 insta::assert_snapshot!(p(2.minutes()), @"2m");
2143 insta::assert_snapshot!(p(10.minutes()), @"10m");
2144 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h 40m");
2145
2146 insta::assert_snapshot!(p(1.hour()), @"1h");
2147 insta::assert_snapshot!(p(2.hours()), @"2h");
2148 insta::assert_snapshot!(p(10.hours()), @"10h");
2149 insta::assert_snapshot!(p(100.hours()), @"100h");
2150
2151 insta::assert_snapshot!(
2152 p(1.hour().minutes(1).seconds(1)),
2153 @"1h 1m 1s",
2154 );
2155 insta::assert_snapshot!(
2156 p(2.hours().minutes(2).seconds(2)),
2157 @"2h 2m 2s",
2158 );
2159 insta::assert_snapshot!(
2160 p(10.hours().minutes(10).seconds(10)),
2161 @"10h 10m 10s",
2162 );
2163 insta::assert_snapshot!(
2164 p(100.hours().minutes(100).seconds(100)),
2165 @"100h 100m 100s",
2166 );
2167
2168 insta::assert_snapshot!(p(-1.hour()), @"1h ago");
2169 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1h 30s ago");
2170 }
2171
2172 #[test]
2173 fn print_span_designator_direction_force() {
2174 let printer = || SpanPrinter::new().direction(Direction::ForceSign);
2175 let p = |span| printer().span_to_string(&span);
2176
2177 insta::assert_snapshot!(p(1.second()), @"+1s");
2178 insta::assert_snapshot!(p(2.seconds()), @"+2s");
2179 insta::assert_snapshot!(p(10.seconds()), @"+10s");
2180 insta::assert_snapshot!(p(1.minute().seconds(40)), @"+1m 40s");
2181
2182 insta::assert_snapshot!(p(1.minute()), @"+1m");
2183 insta::assert_snapshot!(p(2.minutes()), @"+2m");
2184 insta::assert_snapshot!(p(10.minutes()), @"+10m");
2185 insta::assert_snapshot!(p(1.hour().minutes(40)), @"+1h 40m");
2186
2187 insta::assert_snapshot!(p(1.hour()), @"+1h");
2188 insta::assert_snapshot!(p(2.hours()), @"+2h");
2189 insta::assert_snapshot!(p(10.hours()), @"+10h");
2190 insta::assert_snapshot!(p(100.hours()), @"+100h");
2191
2192 insta::assert_snapshot!(
2193 p(1.hour().minutes(1).seconds(1)),
2194 @"+1h 1m 1s",
2195 );
2196 insta::assert_snapshot!(
2197 p(2.hours().minutes(2).seconds(2)),
2198 @"+2h 2m 2s",
2199 );
2200 insta::assert_snapshot!(
2201 p(10.hours().minutes(10).seconds(10)),
2202 @"+10h 10m 10s",
2203 );
2204 insta::assert_snapshot!(
2205 p(100.hours().minutes(100).seconds(100)),
2206 @"+100h 100m 100s",
2207 );
2208
2209 insta::assert_snapshot!(p(-1.hour()), @"-1h");
2210 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"-1h 30s");
2211 }
2212
2213 #[test]
2214 fn print_span_designator_padding() {
2215 let printer = || SpanPrinter::new().padding(2);
2216 let p = |span| printer().span_to_string(&span);
2217
2218 insta::assert_snapshot!(p(1.second()), @"01s");
2219 insta::assert_snapshot!(p(2.seconds()), @"02s");
2220 insta::assert_snapshot!(p(10.seconds()), @"10s");
2221 insta::assert_snapshot!(p(1.minute().seconds(40)), @"01m 40s");
2222
2223 insta::assert_snapshot!(p(1.minute()), @"01m");
2224 insta::assert_snapshot!(p(2.minutes()), @"02m");
2225 insta::assert_snapshot!(p(10.minutes()), @"10m");
2226 insta::assert_snapshot!(p(1.hour().minutes(40)), @"01h 40m");
2227
2228 insta::assert_snapshot!(p(1.hour()), @"01h");
2229 insta::assert_snapshot!(p(2.hours()), @"02h");
2230 insta::assert_snapshot!(p(10.hours()), @"10h");
2231 insta::assert_snapshot!(p(100.hours()), @"100h");
2232
2233 insta::assert_snapshot!(
2234 p(1.hour().minutes(1).seconds(1)),
2235 @"01h 01m 01s",
2236 );
2237 insta::assert_snapshot!(
2238 p(2.hours().minutes(2).seconds(2)),
2239 @"02h 02m 02s",
2240 );
2241 insta::assert_snapshot!(
2242 p(10.hours().minutes(10).seconds(10)),
2243 @"10h 10m 10s",
2244 );
2245 insta::assert_snapshot!(
2246 p(100.hours().minutes(100).seconds(100)),
2247 @"100h 100m 100s",
2248 );
2249
2250 insta::assert_snapshot!(p(-1.hour()), @"01h ago");
2251 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"01h 30s ago");
2252 }
2253
2254 #[test]
2255 fn print_span_designator_spacing_none() {
2256 let printer = || SpanPrinter::new().spacing(Spacing::None);
2257 let p = |span| printer().span_to_string(&span);
2258
2259 insta::assert_snapshot!(p(1.second()), @"1s");
2260 insta::assert_snapshot!(p(2.seconds()), @"2s");
2261 insta::assert_snapshot!(p(10.seconds()), @"10s");
2262 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1m40s");
2263
2264 insta::assert_snapshot!(p(1.minute()), @"1m");
2265 insta::assert_snapshot!(p(2.minutes()), @"2m");
2266 insta::assert_snapshot!(p(10.minutes()), @"10m");
2267 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1h40m");
2268
2269 insta::assert_snapshot!(p(1.hour()), @"1h");
2270 insta::assert_snapshot!(p(2.hours()), @"2h");
2271 insta::assert_snapshot!(p(10.hours()), @"10h");
2272 insta::assert_snapshot!(p(100.hours()), @"100h");
2273
2274 insta::assert_snapshot!(
2275 p(1.hour().minutes(1).seconds(1)),
2276 @"1h1m1s",
2277 );
2278 insta::assert_snapshot!(
2279 p(2.hours().minutes(2).seconds(2)),
2280 @"2h2m2s",
2281 );
2282 insta::assert_snapshot!(
2283 p(10.hours().minutes(10).seconds(10)),
2284 @"10h10m10s",
2285 );
2286 insta::assert_snapshot!(
2287 p(100.hours().minutes(100).seconds(100)),
2288 @"100h100m100s",
2289 );
2290
2291 insta::assert_snapshot!(p(-1.hour()), @"-1h");
2292 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"-1h30s");
2293 }
2294
2295 #[test]
2296 fn print_span_designator_spacing_more() {
2297 let printer =
2298 || SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
2299 let p = |span| printer().span_to_string(&span);
2300
2301 insta::assert_snapshot!(p(1.second()), @"1 s");
2302 insta::assert_snapshot!(p(2.seconds()), @"2 s");
2303 insta::assert_snapshot!(p(10.seconds()), @"10 s");
2304 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1 m 40 s");
2305
2306 insta::assert_snapshot!(p(1.minute()), @"1 m");
2307 insta::assert_snapshot!(p(2.minutes()), @"2 m");
2308 insta::assert_snapshot!(p(10.minutes()), @"10 m");
2309 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1 h 40 m");
2310
2311 insta::assert_snapshot!(p(1.hour()), @"1 h");
2312 insta::assert_snapshot!(p(2.hours()), @"2 h");
2313 insta::assert_snapshot!(p(10.hours()), @"10 h");
2314 insta::assert_snapshot!(p(100.hours()), @"100 h");
2315
2316 insta::assert_snapshot!(
2317 p(1.hour().minutes(1).seconds(1)),
2318 @"1 h 1 m 1 s",
2319 );
2320 insta::assert_snapshot!(
2321 p(2.hours().minutes(2).seconds(2)),
2322 @"2 h 2 m 2 s",
2323 );
2324 insta::assert_snapshot!(
2325 p(10.hours().minutes(10).seconds(10)),
2326 @"10 h 10 m 10 s",
2327 );
2328 insta::assert_snapshot!(
2329 p(100.hours().minutes(100).seconds(100)),
2330 @"100 h 100 m 100 s",
2331 );
2332
2333 insta::assert_snapshot!(p(-1.hour()), @"1 h ago");
2334 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1 h 30 s ago");
2335 }
2336
2337 #[test]
2338 fn print_span_designator_spacing_comma() {
2339 let printer = || {
2340 SpanPrinter::new()
2341 .comma_after_designator(true)
2342 .spacing(Spacing::BetweenUnitsAndDesignators)
2343 };
2344 let p = |span| printer().span_to_string(&span);
2345
2346 insta::assert_snapshot!(p(1.second()), @"1 s");
2347 insta::assert_snapshot!(p(2.seconds()), @"2 s");
2348 insta::assert_snapshot!(p(10.seconds()), @"10 s");
2349 insta::assert_snapshot!(p(1.minute().seconds(40)), @"1 m, 40 s");
2350
2351 insta::assert_snapshot!(p(1.minute()), @"1 m");
2352 insta::assert_snapshot!(p(2.minutes()), @"2 m");
2353 insta::assert_snapshot!(p(10.minutes()), @"10 m");
2354 insta::assert_snapshot!(p(1.hour().minutes(40)), @"1 h, 40 m");
2355
2356 insta::assert_snapshot!(p(1.hour()), @"1 h");
2357 insta::assert_snapshot!(p(2.hours()), @"2 h");
2358 insta::assert_snapshot!(p(10.hours()), @"10 h");
2359 insta::assert_snapshot!(p(100.hours()), @"100 h");
2360
2361 insta::assert_snapshot!(
2362 p(1.hour().minutes(1).seconds(1)),
2363 @"1 h, 1 m, 1 s",
2364 );
2365 insta::assert_snapshot!(
2366 p(2.hours().minutes(2).seconds(2)),
2367 @"2 h, 2 m, 2 s",
2368 );
2369 insta::assert_snapshot!(
2370 p(10.hours().minutes(10).seconds(10)),
2371 @"10 h, 10 m, 10 s",
2372 );
2373 insta::assert_snapshot!(
2374 p(100.hours().minutes(100).seconds(100)),
2375 @"100 h, 100 m, 100 s",
2376 );
2377
2378 insta::assert_snapshot!(p(-1.hour()), @"1 h ago");
2379 insta::assert_snapshot!(p(-1.hour().seconds(30)), @"1 h, 30 s ago");
2380 }
2381
2382 #[test]
2383 fn print_span_designator_fractional_hour() {
2384 let printer =
2385 || SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
2386 let p = |span| printer().span_to_string(&span);
2387 let pp = |precision, span| {
2388 printer().precision(Some(precision)).span_to_string(&span)
2389 };
2390
2391 insta::assert_snapshot!(p(1.hour()), @"1h");
2392 insta::assert_snapshot!(pp(0, 1.hour()), @"1h");
2393 insta::assert_snapshot!(pp(1, 1.hour()), @"1.0h");
2394 insta::assert_snapshot!(pp(2, 1.hour()), @"1.00h");
2395
2396 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1.5h");
2397 insta::assert_snapshot!(pp(0, 1.hour().minutes(30)), @"1h");
2398 insta::assert_snapshot!(pp(1, 1.hour().minutes(30)), @"1.5h");
2399 insta::assert_snapshot!(pp(2, 1.hour().minutes(30)), @"1.50h");
2400
2401 insta::assert_snapshot!(p(1.hour().minutes(3)), @"1.05h");
2402 insta::assert_snapshot!(p(1.hour().minutes(3).nanoseconds(1)), @"1.05h");
2403 insta::assert_snapshot!(p(1.second()), @"0.000277777h");
2404 insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"0.000277777h");
2406 insta::assert_snapshot!(p(0.seconds()), @"0h");
2407 insta::assert_snapshot!(p(1.nanosecond()), @"0h");
2409 }
2410
2411 #[test]
2412 fn print_span_designator_fractional_minute() {
2413 let printer =
2414 || SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
2415 let p = |span| printer().span_to_string(&span);
2416 let pp = |precision, span| {
2417 printer().precision(Some(precision)).span_to_string(&span)
2418 };
2419
2420 insta::assert_snapshot!(p(1.hour()), @"1h");
2421 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2422
2423 insta::assert_snapshot!(p(1.minute()), @"1m");
2424 insta::assert_snapshot!(pp(0, 1.minute()), @"1m");
2425 insta::assert_snapshot!(pp(1, 1.minute()), @"1.0m");
2426 insta::assert_snapshot!(pp(2, 1.minute()), @"1.00m");
2427
2428 insta::assert_snapshot!(p(1.minute().seconds(30)), @"1.5m");
2429 insta::assert_snapshot!(pp(0, 1.minute().seconds(30)), @"1m");
2430 insta::assert_snapshot!(pp(1, 1.minute().seconds(30)), @"1.5m");
2431 insta::assert_snapshot!(pp(2, 1.minute().seconds(30)), @"1.50m");
2432
2433 insta::assert_snapshot!(p(1.hour().nanoseconds(1)), @"1h");
2434 insta::assert_snapshot!(p(1.minute().seconds(3)), @"1.05m");
2435 insta::assert_snapshot!(p(1.minute().seconds(3).nanoseconds(1)), @"1.05m");
2436 insta::assert_snapshot!(p(1.second()), @"0.016666666m");
2437 insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"0.016666666m");
2439 insta::assert_snapshot!(p(0.seconds()), @"0m");
2440 insta::assert_snapshot!(p(1.nanosecond()), @"0m");
2442 }
2443
2444 #[test]
2445 fn print_span_designator_fractional_second() {
2446 let printer =
2447 || SpanPrinter::new().fractional(Some(FractionalUnit::Second));
2448 let p = |span| printer().span_to_string(&span);
2449 let pp = |precision, span| {
2450 printer().precision(Some(precision)).span_to_string(&span)
2451 };
2452
2453 insta::assert_snapshot!(p(1.hour()), @"1h");
2454 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2455
2456 insta::assert_snapshot!(p(1.second()), @"1s");
2457 insta::assert_snapshot!(pp(0, 1.second()), @"1s");
2458 insta::assert_snapshot!(pp(1, 1.second()), @"1.0s");
2459 insta::assert_snapshot!(pp(2, 1.second()), @"1.00s");
2460
2461 insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1.5s");
2462 insta::assert_snapshot!(pp(0, 1.second().milliseconds(500)), @"1s");
2463 insta::assert_snapshot!(pp(1, 1.second().milliseconds(500)), @"1.5s");
2464 insta::assert_snapshot!(pp(2, 1.second().milliseconds(500)), @"1.50s");
2465
2466 insta::assert_snapshot!(p(1.second().nanoseconds(1)), @"1.000000001s");
2467 insta::assert_snapshot!(p(1.nanosecond()), @"0.000000001s");
2468 insta::assert_snapshot!(p(0.seconds()), @"0s");
2469
2470 insta::assert_snapshot!(p(1.second().milliseconds(2000)), @"3s");
2471 }
2472
2473 #[test]
2474 fn print_span_designator_fractional_millisecond() {
2475 let printer = || {
2476 SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
2477 };
2478 let p = |span| printer().span_to_string(&span);
2479 let pp = |precision, span| {
2480 printer().precision(Some(precision)).span_to_string(&span)
2481 };
2482
2483 insta::assert_snapshot!(p(1.hour()), @"1h");
2484 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2485 insta::assert_snapshot!(
2486 p(1.hour().minutes(30).seconds(10)),
2487 @"1h 30m 10s",
2488 );
2489
2490 insta::assert_snapshot!(p(1.second()), @"1s");
2491 insta::assert_snapshot!(pp(0, 1.second()), @"1s");
2492 insta::assert_snapshot!(pp(1, 1.second()), @"1s 0.0ms");
2493 insta::assert_snapshot!(pp(2, 1.second()), @"1s 0.00ms");
2494
2495 insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1s 500ms");
2496 insta::assert_snapshot!(
2497 pp(0, 1.second().milliseconds(1).microseconds(500)),
2498 @"1s 1ms",
2499 );
2500 insta::assert_snapshot!(
2501 pp(1, 1.second().milliseconds(1).microseconds(500)),
2502 @"1s 1.5ms",
2503 );
2504 insta::assert_snapshot!(
2505 pp(2, 1.second().milliseconds(1).microseconds(500)),
2506 @"1s 1.50ms",
2507 );
2508
2509 insta::assert_snapshot!(p(1.millisecond().nanoseconds(1)), @"1.000001ms");
2510 insta::assert_snapshot!(p(1.nanosecond()), @"0.000001ms");
2511 insta::assert_snapshot!(p(0.seconds()), @"0ms");
2512 }
2513
2514 #[test]
2515 fn print_span_designator_fractional_microsecond() {
2516 let printer = || {
2517 SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
2518 };
2519 let p = |span| printer().span_to_string(&span);
2520 let pp = |precision, span| {
2521 printer().precision(Some(precision)).span_to_string(&span)
2522 };
2523
2524 insta::assert_snapshot!(p(1.hour()), @"1h");
2525 insta::assert_snapshot!(p(1.hour().minutes(30)), @"1h 30m");
2526 insta::assert_snapshot!(
2527 p(1.hour().minutes(30).seconds(10)),
2528 @"1h 30m 10s",
2529 );
2530
2531 insta::assert_snapshot!(p(1.second()), @"1s");
2532 insta::assert_snapshot!(pp(0, 1.second()), @"1s");
2533 insta::assert_snapshot!(pp(1, 1.second()), @"1s 0.0µs");
2534 insta::assert_snapshot!(pp(2, 1.second()), @"1s 0.00µs");
2535
2536 insta::assert_snapshot!(p(1.second().milliseconds(500)), @"1s 500ms");
2537 insta::assert_snapshot!(
2538 pp(0, 1.second().milliseconds(1).microseconds(500)),
2539 @"1s 1ms 500µs",
2540 );
2541 insta::assert_snapshot!(
2542 pp(1, 1.second().milliseconds(1).microseconds(500)),
2543 @"1s 1ms 500.0µs",
2544 );
2545 insta::assert_snapshot!(
2546 pp(2, 1.second().milliseconds(1).microseconds(500)),
2547 @"1s 1ms 500.00µs",
2548 );
2549
2550 insta::assert_snapshot!(
2551 p(1.millisecond().nanoseconds(1)),
2552 @"1ms 0.001µs",
2553 );
2554 insta::assert_snapshot!(p(1.nanosecond()), @"0.001µs");
2555 insta::assert_snapshot!(p(0.second()), @"0µs");
2556 }
2557
2558 #[test]
2559 fn print_signed_duration_designator_default() {
2560 let printer = || SpanPrinter::new();
2561 let p = |secs| {
2562 printer().duration_to_string(&SignedDuration::from_secs(secs))
2563 };
2564
2565 insta::assert_snapshot!(p(1), @"1s");
2566 insta::assert_snapshot!(p(2), @"2s");
2567 insta::assert_snapshot!(p(10), @"10s");
2568 insta::assert_snapshot!(p(100), @"1m 40s");
2569
2570 insta::assert_snapshot!(p(1 * 60), @"1m");
2571 insta::assert_snapshot!(p(2 * 60), @"2m");
2572 insta::assert_snapshot!(p(10 * 60), @"10m");
2573 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
2574
2575 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
2576 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
2577 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2578 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2579
2580 insta::assert_snapshot!(
2581 p(60 * 60 + 60 + 1),
2582 @"1h 1m 1s",
2583 );
2584 insta::assert_snapshot!(
2585 p(2 * 60 * 60 + 2 * 60 + 2),
2586 @"2h 2m 2s",
2587 );
2588 insta::assert_snapshot!(
2589 p(10 * 60 * 60 + 10 * 60 + 10),
2590 @"10h 10m 10s",
2591 );
2592 insta::assert_snapshot!(
2593 p(100 * 60 * 60 + 100 * 60 + 100),
2594 @"101h 41m 40s",
2595 );
2596
2597 insta::assert_snapshot!(p(-1 * 60 * 60), @"1h ago");
2598 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1h 30s ago");
2599 }
2600
2601 #[test]
2602 fn print_signed_duration_designator_verbose() {
2603 let printer = || SpanPrinter::new().designator(Designator::Verbose);
2604 let p = |secs| {
2605 printer().duration_to_string(&SignedDuration::from_secs(secs))
2606 };
2607
2608 insta::assert_snapshot!(p(1), @"1second");
2609 insta::assert_snapshot!(p(2), @"2seconds");
2610 insta::assert_snapshot!(p(10), @"10seconds");
2611 insta::assert_snapshot!(p(100), @"1minute 40seconds");
2612
2613 insta::assert_snapshot!(p(1 * 60), @"1minute");
2614 insta::assert_snapshot!(p(2 * 60), @"2minutes");
2615 insta::assert_snapshot!(p(10 * 60), @"10minutes");
2616 insta::assert_snapshot!(p(100 * 60), @"1hour 40minutes");
2617
2618 insta::assert_snapshot!(p(1 * 60 * 60), @"1hour");
2619 insta::assert_snapshot!(p(2 * 60 * 60), @"2hours");
2620 insta::assert_snapshot!(p(10 * 60 * 60), @"10hours");
2621 insta::assert_snapshot!(p(100 * 60 * 60), @"100hours");
2622
2623 insta::assert_snapshot!(
2624 p(60 * 60 + 60 + 1),
2625 @"1hour 1minute 1second",
2626 );
2627 insta::assert_snapshot!(
2628 p(2 * 60 * 60 + 2 * 60 + 2),
2629 @"2hours 2minutes 2seconds",
2630 );
2631 insta::assert_snapshot!(
2632 p(10 * 60 * 60 + 10 * 60 + 10),
2633 @"10hours 10minutes 10seconds",
2634 );
2635 insta::assert_snapshot!(
2636 p(100 * 60 * 60 + 100 * 60 + 100),
2637 @"101hours 41minutes 40seconds",
2638 );
2639
2640 insta::assert_snapshot!(p(-1 * 60 * 60), @"1hour ago");
2641 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1hour 30seconds ago");
2642 }
2643
2644 #[test]
2645 fn print_signed_duration_designator_short() {
2646 let printer = || SpanPrinter::new().designator(Designator::Short);
2647 let p = |secs| {
2648 printer().duration_to_string(&SignedDuration::from_secs(secs))
2649 };
2650
2651 insta::assert_snapshot!(p(1), @"1sec");
2652 insta::assert_snapshot!(p(2), @"2secs");
2653 insta::assert_snapshot!(p(10), @"10secs");
2654 insta::assert_snapshot!(p(100), @"1min 40secs");
2655
2656 insta::assert_snapshot!(p(1 * 60), @"1min");
2657 insta::assert_snapshot!(p(2 * 60), @"2mins");
2658 insta::assert_snapshot!(p(10 * 60), @"10mins");
2659 insta::assert_snapshot!(p(100 * 60), @"1hr 40mins");
2660
2661 insta::assert_snapshot!(p(1 * 60 * 60), @"1hr");
2662 insta::assert_snapshot!(p(2 * 60 * 60), @"2hrs");
2663 insta::assert_snapshot!(p(10 * 60 * 60), @"10hrs");
2664 insta::assert_snapshot!(p(100 * 60 * 60), @"100hrs");
2665
2666 insta::assert_snapshot!(
2667 p(60 * 60 + 60 + 1),
2668 @"1hr 1min 1sec",
2669 );
2670 insta::assert_snapshot!(
2671 p(2 * 60 * 60 + 2 * 60 + 2),
2672 @"2hrs 2mins 2secs",
2673 );
2674 insta::assert_snapshot!(
2675 p(10 * 60 * 60 + 10 * 60 + 10),
2676 @"10hrs 10mins 10secs",
2677 );
2678 insta::assert_snapshot!(
2679 p(100 * 60 * 60 + 100 * 60 + 100),
2680 @"101hrs 41mins 40secs",
2681 );
2682
2683 insta::assert_snapshot!(p(-1 * 60 * 60), @"1hr ago");
2684 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1hr 30secs ago");
2685 }
2686
2687 #[test]
2688 fn print_signed_duration_designator_compact() {
2689 let printer = || SpanPrinter::new().designator(Designator::Compact);
2690 let p = |secs| {
2691 printer().duration_to_string(&SignedDuration::from_secs(secs))
2692 };
2693
2694 insta::assert_snapshot!(p(1), @"1s");
2695 insta::assert_snapshot!(p(2), @"2s");
2696 insta::assert_snapshot!(p(10), @"10s");
2697 insta::assert_snapshot!(p(100), @"1m 40s");
2698
2699 insta::assert_snapshot!(p(1 * 60), @"1m");
2700 insta::assert_snapshot!(p(2 * 60), @"2m");
2701 insta::assert_snapshot!(p(10 * 60), @"10m");
2702 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
2703
2704 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
2705 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
2706 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2707 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2708
2709 insta::assert_snapshot!(
2710 p(60 * 60 + 60 + 1),
2711 @"1h 1m 1s",
2712 );
2713 insta::assert_snapshot!(
2714 p(2 * 60 * 60 + 2 * 60 + 2),
2715 @"2h 2m 2s",
2716 );
2717 insta::assert_snapshot!(
2718 p(10 * 60 * 60 + 10 * 60 + 10),
2719 @"10h 10m 10s",
2720 );
2721 insta::assert_snapshot!(
2722 p(100 * 60 * 60 + 100 * 60 + 100),
2723 @"101h 41m 40s",
2724 );
2725
2726 insta::assert_snapshot!(p(-1 * 60 * 60), @"1h ago");
2727 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1h 30s ago");
2728 }
2729
2730 #[test]
2731 fn print_signed_duration_designator_direction_force() {
2732 let printer = || SpanPrinter::new().direction(Direction::ForceSign);
2733 let p = |secs| {
2734 printer().duration_to_string(&SignedDuration::from_secs(secs))
2735 };
2736
2737 insta::assert_snapshot!(p(1), @"+1s");
2738 insta::assert_snapshot!(p(2), @"+2s");
2739 insta::assert_snapshot!(p(10), @"+10s");
2740 insta::assert_snapshot!(p(100), @"+1m 40s");
2741
2742 insta::assert_snapshot!(p(1 * 60), @"+1m");
2743 insta::assert_snapshot!(p(2 * 60), @"+2m");
2744 insta::assert_snapshot!(p(10 * 60), @"+10m");
2745 insta::assert_snapshot!(p(100 * 60), @"+1h 40m");
2746
2747 insta::assert_snapshot!(p(1 * 60 * 60), @"+1h");
2748 insta::assert_snapshot!(p(2 * 60 * 60), @"+2h");
2749 insta::assert_snapshot!(p(10 * 60 * 60), @"+10h");
2750 insta::assert_snapshot!(p(100 * 60 * 60), @"+100h");
2751
2752 insta::assert_snapshot!(
2753 p(60 * 60 + 60 + 1),
2754 @"+1h 1m 1s",
2755 );
2756 insta::assert_snapshot!(
2757 p(2 * 60 * 60 + 2 * 60 + 2),
2758 @"+2h 2m 2s",
2759 );
2760 insta::assert_snapshot!(
2761 p(10 * 60 * 60 + 10 * 60 + 10),
2762 @"+10h 10m 10s",
2763 );
2764 insta::assert_snapshot!(
2765 p(100 * 60 * 60 + 100 * 60 + 100),
2766 @"+101h 41m 40s",
2767 );
2768
2769 insta::assert_snapshot!(p(-1 * 60 * 60), @"-1h");
2770 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"-1h 30s");
2771 }
2772
2773 #[test]
2774 fn print_signed_duration_designator_padding() {
2775 let printer = || SpanPrinter::new().padding(2);
2776 let p = |secs| {
2777 printer().duration_to_string(&SignedDuration::from_secs(secs))
2778 };
2779
2780 insta::assert_snapshot!(p(1), @"01s");
2781 insta::assert_snapshot!(p(2), @"02s");
2782 insta::assert_snapshot!(p(10), @"10s");
2783 insta::assert_snapshot!(p(100), @"01m 40s");
2784
2785 insta::assert_snapshot!(p(1 * 60), @"01m");
2786 insta::assert_snapshot!(p(2 * 60), @"02m");
2787 insta::assert_snapshot!(p(10 * 60), @"10m");
2788 insta::assert_snapshot!(p(100 * 60), @"01h 40m");
2789
2790 insta::assert_snapshot!(p(1 * 60 * 60), @"01h");
2791 insta::assert_snapshot!(p(2 * 60 * 60), @"02h");
2792 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2793 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2794
2795 insta::assert_snapshot!(
2796 p(60 * 60 + 60 + 1),
2797 @"01h 01m 01s",
2798 );
2799 insta::assert_snapshot!(
2800 p(2 * 60 * 60 + 2 * 60 + 2),
2801 @"02h 02m 02s",
2802 );
2803 insta::assert_snapshot!(
2804 p(10 * 60 * 60 + 10 * 60 + 10),
2805 @"10h 10m 10s",
2806 );
2807 insta::assert_snapshot!(
2808 p(100 * 60 * 60 + 100 * 60 + 100),
2809 @"101h 41m 40s",
2810 );
2811
2812 insta::assert_snapshot!(p(-1 * 60 * 60), @"01h ago");
2813 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"01h 30s ago");
2814 }
2815
2816 #[test]
2817 fn print_signed_duration_designator_spacing_none() {
2818 let printer = || SpanPrinter::new().spacing(Spacing::None);
2819 let p = |secs| {
2820 printer().duration_to_string(&SignedDuration::from_secs(secs))
2821 };
2822
2823 insta::assert_snapshot!(p(1), @"1s");
2824 insta::assert_snapshot!(p(2), @"2s");
2825 insta::assert_snapshot!(p(10), @"10s");
2826 insta::assert_snapshot!(p(100), @"1m40s");
2827
2828 insta::assert_snapshot!(p(1 * 60), @"1m");
2829 insta::assert_snapshot!(p(2 * 60), @"2m");
2830 insta::assert_snapshot!(p(10 * 60), @"10m");
2831 insta::assert_snapshot!(p(100 * 60), @"1h40m");
2832
2833 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
2834 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
2835 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
2836 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
2837
2838 insta::assert_snapshot!(
2839 p(60 * 60 + 60 + 1),
2840 @"1h1m1s",
2841 );
2842 insta::assert_snapshot!(
2843 p(2 * 60 * 60 + 2 * 60 + 2),
2844 @"2h2m2s",
2845 );
2846 insta::assert_snapshot!(
2847 p(10 * 60 * 60 + 10 * 60 + 10),
2848 @"10h10m10s",
2849 );
2850 insta::assert_snapshot!(
2851 p(100 * 60 * 60 + 100 * 60 + 100),
2852 @"101h41m40s",
2853 );
2854
2855 insta::assert_snapshot!(p(-1 * 60 * 60), @"-1h");
2856 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"-1h30s");
2857 }
2858
2859 #[test]
2860 fn print_signed_duration_designator_spacing_more() {
2861 let printer =
2862 || SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
2863 let p = |secs| {
2864 printer().duration_to_string(&SignedDuration::from_secs(secs))
2865 };
2866
2867 insta::assert_snapshot!(p(1), @"1 s");
2868 insta::assert_snapshot!(p(2), @"2 s");
2869 insta::assert_snapshot!(p(10), @"10 s");
2870 insta::assert_snapshot!(p(100), @"1 m 40 s");
2871
2872 insta::assert_snapshot!(p(1 * 60), @"1 m");
2873 insta::assert_snapshot!(p(2 * 60), @"2 m");
2874 insta::assert_snapshot!(p(10 * 60), @"10 m");
2875 insta::assert_snapshot!(p(100 * 60), @"1 h 40 m");
2876
2877 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
2878 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
2879 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
2880 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
2881
2882 insta::assert_snapshot!(
2883 p(60 * 60 + 60 + 1),
2884 @"1 h 1 m 1 s",
2885 );
2886 insta::assert_snapshot!(
2887 p(2 * 60 * 60 + 2 * 60 + 2),
2888 @"2 h 2 m 2 s",
2889 );
2890 insta::assert_snapshot!(
2891 p(10 * 60 * 60 + 10 * 60 + 10),
2892 @"10 h 10 m 10 s",
2893 );
2894 insta::assert_snapshot!(
2895 p(100 * 60 * 60 + 100 * 60 + 100),
2896 @"101 h 41 m 40 s",
2897 );
2898
2899 insta::assert_snapshot!(p(-1 * 60 * 60), @"1 h ago");
2900 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1 h 30 s ago");
2901 }
2902
2903 #[test]
2904 fn print_signed_duration_designator_spacing_comma() {
2905 let printer = || {
2906 SpanPrinter::new()
2907 .comma_after_designator(true)
2908 .spacing(Spacing::BetweenUnitsAndDesignators)
2909 };
2910 let p = |secs| {
2911 printer().duration_to_string(&SignedDuration::from_secs(secs))
2912 };
2913
2914 insta::assert_snapshot!(p(1), @"1 s");
2915 insta::assert_snapshot!(p(2), @"2 s");
2916 insta::assert_snapshot!(p(10), @"10 s");
2917 insta::assert_snapshot!(p(100), @"1 m, 40 s");
2918
2919 insta::assert_snapshot!(p(1 * 60), @"1 m");
2920 insta::assert_snapshot!(p(2 * 60), @"2 m");
2921 insta::assert_snapshot!(p(10 * 60), @"10 m");
2922 insta::assert_snapshot!(p(100 * 60), @"1 h, 40 m");
2923
2924 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
2925 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
2926 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
2927 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
2928
2929 insta::assert_snapshot!(
2930 p(60 * 60 + 60 + 1),
2931 @"1 h, 1 m, 1 s",
2932 );
2933 insta::assert_snapshot!(
2934 p(2 * 60 * 60 + 2 * 60 + 2),
2935 @"2 h, 2 m, 2 s",
2936 );
2937 insta::assert_snapshot!(
2938 p(10 * 60 * 60 + 10 * 60 + 10),
2939 @"10 h, 10 m, 10 s",
2940 );
2941 insta::assert_snapshot!(
2942 p(100 * 60 * 60 + 100 * 60 + 100),
2943 @"101 h, 41 m, 40 s",
2944 );
2945
2946 insta::assert_snapshot!(p(-1 * 60 * 60), @"1 h ago");
2947 insta::assert_snapshot!(p(-1 * 60 * 60 - 30), @"1 h, 30 s ago");
2948 }
2949
2950 #[test]
2951 fn print_signed_duration_designator_fractional_hour() {
2952 let printer =
2953 || SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
2954 let p = |secs, nanos| {
2955 printer().duration_to_string(&SignedDuration::new(secs, nanos))
2956 };
2957 let pp = |precision, secs, nanos| {
2958 printer()
2959 .precision(Some(precision))
2960 .duration_to_string(&SignedDuration::new(secs, nanos))
2961 };
2962
2963 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
2964 insta::assert_snapshot!(pp(0, 1 * 60 * 60, 0), @"1h");
2965 insta::assert_snapshot!(pp(1, 1 * 60 * 60, 0), @"1.0h");
2966 insta::assert_snapshot!(pp(2, 1 * 60 * 60, 0), @"1.00h");
2967
2968 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1.5h");
2969 insta::assert_snapshot!(pp(0, 1 * 60 * 60 + 30 * 60, 0), @"1h");
2970 insta::assert_snapshot!(pp(1, 1 * 60 * 60 + 30 * 60, 0), @"1.5h");
2971 insta::assert_snapshot!(pp(2, 1 * 60 * 60 + 30 * 60, 0), @"1.50h");
2972
2973 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 0), @"1.05h");
2974 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 1), @"1.05h");
2975 insta::assert_snapshot!(p(1, 0), @"0.000277777h");
2976 insta::assert_snapshot!(p(1, 1), @"0.000277777h");
2978 insta::assert_snapshot!(p(0, 0), @"0h");
2979 insta::assert_snapshot!(p(0, 1), @"0h");
2981
2982 insta::assert_snapshot!(
2983 printer().duration_to_string(&SignedDuration::MIN),
2984 @"2562047788015215.502499999h ago",
2985 );
2986 }
2987
2988 #[test]
2989 fn print_signed_duration_designator_fractional_minute() {
2990 let printer =
2991 || SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
2992 let p = |secs, nanos| {
2993 printer().duration_to_string(&SignedDuration::new(secs, nanos))
2994 };
2995 let pp = |precision, secs, nanos| {
2996 printer()
2997 .precision(Some(precision))
2998 .duration_to_string(&SignedDuration::new(secs, nanos))
2999 };
3000
3001 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3002 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3003
3004 insta::assert_snapshot!(p(60, 0), @"1m");
3005 insta::assert_snapshot!(pp(0, 60, 0), @"1m");
3006 insta::assert_snapshot!(pp(1, 60, 0), @"1.0m");
3007 insta::assert_snapshot!(pp(2, 60, 0), @"1.00m");
3008
3009 insta::assert_snapshot!(p(90, 0), @"1.5m");
3010 insta::assert_snapshot!(pp(0, 90, 0), @"1m");
3011 insta::assert_snapshot!(pp(1, 90, 0), @"1.5m");
3012 insta::assert_snapshot!(pp(2, 90, 0), @"1.50m");
3013
3014 insta::assert_snapshot!(p(1 * 60 * 60, 1), @"1h");
3015 insta::assert_snapshot!(p(63, 0), @"1.05m");
3016 insta::assert_snapshot!(p(63, 1), @"1.05m");
3017 insta::assert_snapshot!(p(1, 0), @"0.016666666m");
3018 insta::assert_snapshot!(p(1, 1), @"0.016666666m");
3020 insta::assert_snapshot!(p(0, 0), @"0m");
3021 insta::assert_snapshot!(p(0, 1), @"0m");
3023
3024 insta::assert_snapshot!(
3025 printer().duration_to_string(&SignedDuration::MIN),
3026 @"2562047788015215h 30.149999999m ago",
3027 );
3028 }
3029
3030 #[test]
3031 fn print_signed_duration_designator_fractional_second() {
3032 let printer =
3033 || SpanPrinter::new().fractional(Some(FractionalUnit::Second));
3034 let p = |secs, nanos| {
3035 printer().duration_to_string(&SignedDuration::new(secs, nanos))
3036 };
3037 let pp = |precision, secs, nanos| {
3038 printer()
3039 .precision(Some(precision))
3040 .duration_to_string(&SignedDuration::new(secs, nanos))
3041 };
3042
3043 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3044 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3045
3046 insta::assert_snapshot!(p(1, 0), @"1s");
3047 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3048 insta::assert_snapshot!(pp(1, 1, 0), @"1.0s");
3049 insta::assert_snapshot!(pp(2, 1, 0), @"1.00s");
3050
3051 insta::assert_snapshot!(p(1, 500_000_000), @"1.5s");
3052 insta::assert_snapshot!(pp(0, 1, 500_000_000), @"1s");
3053 insta::assert_snapshot!(pp(1, 1, 500_000_000), @"1.5s");
3054 insta::assert_snapshot!(pp(2, 1, 500_000_000), @"1.50s");
3055
3056 insta::assert_snapshot!(p(1, 1), @"1.000000001s");
3057 insta::assert_snapshot!(p(0, 1), @"0.000000001s");
3058 insta::assert_snapshot!(p(0, 0), @"0s");
3059
3060 insta::assert_snapshot!(
3061 printer().duration_to_string(&SignedDuration::MIN),
3062 @"2562047788015215h 30m 8.999999999s ago",
3063 );
3064 }
3065
3066 #[test]
3067 fn print_signed_duration_designator_fractional_millisecond() {
3068 let printer = || {
3069 SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
3070 };
3071 let p = |secs, nanos| {
3072 printer().duration_to_string(&SignedDuration::new(secs, nanos))
3073 };
3074 let pp = |precision, secs, nanos| {
3075 printer()
3076 .precision(Some(precision))
3077 .duration_to_string(&SignedDuration::new(secs, nanos))
3078 };
3079
3080 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3081 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3082 insta::assert_snapshot!(
3083 p(1 * 60 * 60 + 30 * 60 + 10, 0),
3084 @"1h 30m 10s",
3085 );
3086
3087 insta::assert_snapshot!(p(1, 0), @"1s");
3088 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3089 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0ms");
3090 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00ms");
3091
3092 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
3093 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms");
3094 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1.5ms");
3095 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1.50ms");
3096
3097 insta::assert_snapshot!(p(0, 1_000_001), @"1.000001ms");
3098 insta::assert_snapshot!(p(0, 0_000_001), @"0.000001ms");
3099 insta::assert_snapshot!(p(0, 0), @"0ms");
3100
3101 insta::assert_snapshot!(
3102 printer().duration_to_string(&SignedDuration::MIN),
3103 @"2562047788015215h 30m 8s 999.999999ms ago",
3104 );
3105 }
3106
3107 #[test]
3108 fn print_signed_duration_designator_fractional_microsecond() {
3109 let printer = || {
3110 SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
3111 };
3112 let p = |secs, nanos| {
3113 printer().duration_to_string(&SignedDuration::new(secs, nanos))
3114 };
3115 let pp = |precision, secs, nanos| {
3116 printer()
3117 .precision(Some(precision))
3118 .duration_to_string(&SignedDuration::new(secs, nanos))
3119 };
3120
3121 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3122 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3123 insta::assert_snapshot!(
3124 p(1 * 60 * 60 + 30 * 60 + 10, 0),
3125 @"1h 30m 10s",
3126 );
3127
3128 insta::assert_snapshot!(p(1, 0), @"1s");
3129 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3130 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0µs");
3131 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00µs");
3132
3133 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
3134 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms 500µs");
3135 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1ms 500.0µs");
3136 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1ms 500.00µs");
3137
3138 insta::assert_snapshot!(p(0, 1_000_001), @"1ms 0.001µs");
3139 insta::assert_snapshot!(p(0, 0_000_001), @"0.001µs");
3140 insta::assert_snapshot!(p(0, 0), @"0µs");
3141
3142 insta::assert_snapshot!(
3143 printer().duration_to_string(&SignedDuration::MIN),
3144 @"2562047788015215h 30m 8s 999ms 999.999µs ago",
3145 );
3146 }
3147
3148 #[test]
3149 fn print_unsigned_duration_designator_default() {
3150 let printer = || SpanPrinter::new();
3151 let p = |secs| {
3152 printer().unsigned_duration_to_string(
3153 &core::time::Duration::from_secs(secs),
3154 )
3155 };
3156
3157 insta::assert_snapshot!(p(1), @"1s");
3158 insta::assert_snapshot!(p(2), @"2s");
3159 insta::assert_snapshot!(p(10), @"10s");
3160 insta::assert_snapshot!(p(100), @"1m 40s");
3161
3162 insta::assert_snapshot!(p(1 * 60), @"1m");
3163 insta::assert_snapshot!(p(2 * 60), @"2m");
3164 insta::assert_snapshot!(p(10 * 60), @"10m");
3165 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
3166
3167 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
3168 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
3169 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3170 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3171
3172 insta::assert_snapshot!(
3173 p(60 * 60 + 60 + 1),
3174 @"1h 1m 1s",
3175 );
3176 insta::assert_snapshot!(
3177 p(2 * 60 * 60 + 2 * 60 + 2),
3178 @"2h 2m 2s",
3179 );
3180 insta::assert_snapshot!(
3181 p(10 * 60 * 60 + 10 * 60 + 10),
3182 @"10h 10m 10s",
3183 );
3184 insta::assert_snapshot!(
3185 p(100 * 60 * 60 + 100 * 60 + 100),
3186 @"101h 41m 40s",
3187 );
3188 }
3189
3190 #[test]
3191 fn print_unsigned_duration_designator_verbose() {
3192 let printer = || SpanPrinter::new().designator(Designator::Verbose);
3193 let p = |secs| {
3194 printer().unsigned_duration_to_string(
3195 &core::time::Duration::from_secs(secs),
3196 )
3197 };
3198
3199 insta::assert_snapshot!(p(1), @"1second");
3200 insta::assert_snapshot!(p(2), @"2seconds");
3201 insta::assert_snapshot!(p(10), @"10seconds");
3202 insta::assert_snapshot!(p(100), @"1minute 40seconds");
3203
3204 insta::assert_snapshot!(p(1 * 60), @"1minute");
3205 insta::assert_snapshot!(p(2 * 60), @"2minutes");
3206 insta::assert_snapshot!(p(10 * 60), @"10minutes");
3207 insta::assert_snapshot!(p(100 * 60), @"1hour 40minutes");
3208
3209 insta::assert_snapshot!(p(1 * 60 * 60), @"1hour");
3210 insta::assert_snapshot!(p(2 * 60 * 60), @"2hours");
3211 insta::assert_snapshot!(p(10 * 60 * 60), @"10hours");
3212 insta::assert_snapshot!(p(100 * 60 * 60), @"100hours");
3213
3214 insta::assert_snapshot!(
3215 p(60 * 60 + 60 + 1),
3216 @"1hour 1minute 1second",
3217 );
3218 insta::assert_snapshot!(
3219 p(2 * 60 * 60 + 2 * 60 + 2),
3220 @"2hours 2minutes 2seconds",
3221 );
3222 insta::assert_snapshot!(
3223 p(10 * 60 * 60 + 10 * 60 + 10),
3224 @"10hours 10minutes 10seconds",
3225 );
3226 insta::assert_snapshot!(
3227 p(100 * 60 * 60 + 100 * 60 + 100),
3228 @"101hours 41minutes 40seconds",
3229 );
3230 }
3231
3232 #[test]
3233 fn print_unsigned_duration_designator_short() {
3234 let printer = || SpanPrinter::new().designator(Designator::Short);
3235 let p = |secs| {
3236 printer().unsigned_duration_to_string(
3237 &core::time::Duration::from_secs(secs),
3238 )
3239 };
3240
3241 insta::assert_snapshot!(p(1), @"1sec");
3242 insta::assert_snapshot!(p(2), @"2secs");
3243 insta::assert_snapshot!(p(10), @"10secs");
3244 insta::assert_snapshot!(p(100), @"1min 40secs");
3245
3246 insta::assert_snapshot!(p(1 * 60), @"1min");
3247 insta::assert_snapshot!(p(2 * 60), @"2mins");
3248 insta::assert_snapshot!(p(10 * 60), @"10mins");
3249 insta::assert_snapshot!(p(100 * 60), @"1hr 40mins");
3250
3251 insta::assert_snapshot!(p(1 * 60 * 60), @"1hr");
3252 insta::assert_snapshot!(p(2 * 60 * 60), @"2hrs");
3253 insta::assert_snapshot!(p(10 * 60 * 60), @"10hrs");
3254 insta::assert_snapshot!(p(100 * 60 * 60), @"100hrs");
3255
3256 insta::assert_snapshot!(
3257 p(60 * 60 + 60 + 1),
3258 @"1hr 1min 1sec",
3259 );
3260 insta::assert_snapshot!(
3261 p(2 * 60 * 60 + 2 * 60 + 2),
3262 @"2hrs 2mins 2secs",
3263 );
3264 insta::assert_snapshot!(
3265 p(10 * 60 * 60 + 10 * 60 + 10),
3266 @"10hrs 10mins 10secs",
3267 );
3268 insta::assert_snapshot!(
3269 p(100 * 60 * 60 + 100 * 60 + 100),
3270 @"101hrs 41mins 40secs",
3271 );
3272 }
3273
3274 #[test]
3275 fn print_unsigned_duration_designator_compact() {
3276 let printer = || SpanPrinter::new().designator(Designator::Compact);
3277 let p = |secs| {
3278 printer().unsigned_duration_to_string(
3279 &core::time::Duration::from_secs(secs),
3280 )
3281 };
3282
3283 insta::assert_snapshot!(p(1), @"1s");
3284 insta::assert_snapshot!(p(2), @"2s");
3285 insta::assert_snapshot!(p(10), @"10s");
3286 insta::assert_snapshot!(p(100), @"1m 40s");
3287
3288 insta::assert_snapshot!(p(1 * 60), @"1m");
3289 insta::assert_snapshot!(p(2 * 60), @"2m");
3290 insta::assert_snapshot!(p(10 * 60), @"10m");
3291 insta::assert_snapshot!(p(100 * 60), @"1h 40m");
3292
3293 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
3294 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
3295 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3296 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3297
3298 insta::assert_snapshot!(
3299 p(60 * 60 + 60 + 1),
3300 @"1h 1m 1s",
3301 );
3302 insta::assert_snapshot!(
3303 p(2 * 60 * 60 + 2 * 60 + 2),
3304 @"2h 2m 2s",
3305 );
3306 insta::assert_snapshot!(
3307 p(10 * 60 * 60 + 10 * 60 + 10),
3308 @"10h 10m 10s",
3309 );
3310 insta::assert_snapshot!(
3311 p(100 * 60 * 60 + 100 * 60 + 100),
3312 @"101h 41m 40s",
3313 );
3314 }
3315
3316 #[test]
3317 fn print_unsigned_duration_designator_direction_force() {
3318 let printer = || SpanPrinter::new().direction(Direction::ForceSign);
3319 let p = |secs| {
3320 printer().unsigned_duration_to_string(
3321 &core::time::Duration::from_secs(secs),
3322 )
3323 };
3324
3325 insta::assert_snapshot!(p(1), @"+1s");
3326 insta::assert_snapshot!(p(2), @"+2s");
3327 insta::assert_snapshot!(p(10), @"+10s");
3328 insta::assert_snapshot!(p(100), @"+1m 40s");
3329
3330 insta::assert_snapshot!(p(1 * 60), @"+1m");
3331 insta::assert_snapshot!(p(2 * 60), @"+2m");
3332 insta::assert_snapshot!(p(10 * 60), @"+10m");
3333 insta::assert_snapshot!(p(100 * 60), @"+1h 40m");
3334
3335 insta::assert_snapshot!(p(1 * 60 * 60), @"+1h");
3336 insta::assert_snapshot!(p(2 * 60 * 60), @"+2h");
3337 insta::assert_snapshot!(p(10 * 60 * 60), @"+10h");
3338 insta::assert_snapshot!(p(100 * 60 * 60), @"+100h");
3339
3340 insta::assert_snapshot!(
3341 p(60 * 60 + 60 + 1),
3342 @"+1h 1m 1s",
3343 );
3344 insta::assert_snapshot!(
3345 p(2 * 60 * 60 + 2 * 60 + 2),
3346 @"+2h 2m 2s",
3347 );
3348 insta::assert_snapshot!(
3349 p(10 * 60 * 60 + 10 * 60 + 10),
3350 @"+10h 10m 10s",
3351 );
3352 insta::assert_snapshot!(
3353 p(100 * 60 * 60 + 100 * 60 + 100),
3354 @"+101h 41m 40s",
3355 );
3356 }
3357
3358 #[test]
3359 fn print_unsigned_duration_designator_padding() {
3360 let printer = || SpanPrinter::new().padding(2);
3361 let p = |secs| {
3362 printer().unsigned_duration_to_string(
3363 &core::time::Duration::from_secs(secs),
3364 )
3365 };
3366
3367 insta::assert_snapshot!(p(1), @"01s");
3368 insta::assert_snapshot!(p(2), @"02s");
3369 insta::assert_snapshot!(p(10), @"10s");
3370 insta::assert_snapshot!(p(100), @"01m 40s");
3371
3372 insta::assert_snapshot!(p(1 * 60), @"01m");
3373 insta::assert_snapshot!(p(2 * 60), @"02m");
3374 insta::assert_snapshot!(p(10 * 60), @"10m");
3375 insta::assert_snapshot!(p(100 * 60), @"01h 40m");
3376
3377 insta::assert_snapshot!(p(1 * 60 * 60), @"01h");
3378 insta::assert_snapshot!(p(2 * 60 * 60), @"02h");
3379 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3380 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3381
3382 insta::assert_snapshot!(
3383 p(60 * 60 + 60 + 1),
3384 @"01h 01m 01s",
3385 );
3386 insta::assert_snapshot!(
3387 p(2 * 60 * 60 + 2 * 60 + 2),
3388 @"02h 02m 02s",
3389 );
3390 insta::assert_snapshot!(
3391 p(10 * 60 * 60 + 10 * 60 + 10),
3392 @"10h 10m 10s",
3393 );
3394 insta::assert_snapshot!(
3395 p(100 * 60 * 60 + 100 * 60 + 100),
3396 @"101h 41m 40s",
3397 );
3398 }
3399
3400 #[test]
3401 fn print_unsigned_duration_designator_spacing_none() {
3402 let printer = || SpanPrinter::new().spacing(Spacing::None);
3403 let p = |secs| {
3404 printer().unsigned_duration_to_string(
3405 &core::time::Duration::from_secs(secs),
3406 )
3407 };
3408
3409 insta::assert_snapshot!(p(1), @"1s");
3410 insta::assert_snapshot!(p(2), @"2s");
3411 insta::assert_snapshot!(p(10), @"10s");
3412 insta::assert_snapshot!(p(100), @"1m40s");
3413
3414 insta::assert_snapshot!(p(1 * 60), @"1m");
3415 insta::assert_snapshot!(p(2 * 60), @"2m");
3416 insta::assert_snapshot!(p(10 * 60), @"10m");
3417 insta::assert_snapshot!(p(100 * 60), @"1h40m");
3418
3419 insta::assert_snapshot!(p(1 * 60 * 60), @"1h");
3420 insta::assert_snapshot!(p(2 * 60 * 60), @"2h");
3421 insta::assert_snapshot!(p(10 * 60 * 60), @"10h");
3422 insta::assert_snapshot!(p(100 * 60 * 60), @"100h");
3423
3424 insta::assert_snapshot!(
3425 p(60 * 60 + 60 + 1),
3426 @"1h1m1s",
3427 );
3428 insta::assert_snapshot!(
3429 p(2 * 60 * 60 + 2 * 60 + 2),
3430 @"2h2m2s",
3431 );
3432 insta::assert_snapshot!(
3433 p(10 * 60 * 60 + 10 * 60 + 10),
3434 @"10h10m10s",
3435 );
3436 insta::assert_snapshot!(
3437 p(100 * 60 * 60 + 100 * 60 + 100),
3438 @"101h41m40s",
3439 );
3440 }
3441
3442 #[test]
3443 fn print_unsigned_duration_designator_spacing_more() {
3444 let printer =
3445 || SpanPrinter::new().spacing(Spacing::BetweenUnitsAndDesignators);
3446 let p = |secs| {
3447 printer().unsigned_duration_to_string(
3448 &core::time::Duration::from_secs(secs),
3449 )
3450 };
3451
3452 insta::assert_snapshot!(p(1), @"1 s");
3453 insta::assert_snapshot!(p(2), @"2 s");
3454 insta::assert_snapshot!(p(10), @"10 s");
3455 insta::assert_snapshot!(p(100), @"1 m 40 s");
3456
3457 insta::assert_snapshot!(p(1 * 60), @"1 m");
3458 insta::assert_snapshot!(p(2 * 60), @"2 m");
3459 insta::assert_snapshot!(p(10 * 60), @"10 m");
3460 insta::assert_snapshot!(p(100 * 60), @"1 h 40 m");
3461
3462 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
3463 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
3464 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
3465 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
3466
3467 insta::assert_snapshot!(
3468 p(60 * 60 + 60 + 1),
3469 @"1 h 1 m 1 s",
3470 );
3471 insta::assert_snapshot!(
3472 p(2 * 60 * 60 + 2 * 60 + 2),
3473 @"2 h 2 m 2 s",
3474 );
3475 insta::assert_snapshot!(
3476 p(10 * 60 * 60 + 10 * 60 + 10),
3477 @"10 h 10 m 10 s",
3478 );
3479 insta::assert_snapshot!(
3480 p(100 * 60 * 60 + 100 * 60 + 100),
3481 @"101 h 41 m 40 s",
3482 );
3483 }
3484
3485 #[test]
3486 fn print_unsigned_duration_designator_spacing_comma() {
3487 let printer = || {
3488 SpanPrinter::new()
3489 .comma_after_designator(true)
3490 .spacing(Spacing::BetweenUnitsAndDesignators)
3491 };
3492 let p = |secs| {
3493 printer().unsigned_duration_to_string(
3494 &core::time::Duration::from_secs(secs),
3495 )
3496 };
3497
3498 insta::assert_snapshot!(p(1), @"1 s");
3499 insta::assert_snapshot!(p(2), @"2 s");
3500 insta::assert_snapshot!(p(10), @"10 s");
3501 insta::assert_snapshot!(p(100), @"1 m, 40 s");
3502
3503 insta::assert_snapshot!(p(1 * 60), @"1 m");
3504 insta::assert_snapshot!(p(2 * 60), @"2 m");
3505 insta::assert_snapshot!(p(10 * 60), @"10 m");
3506 insta::assert_snapshot!(p(100 * 60), @"1 h, 40 m");
3507
3508 insta::assert_snapshot!(p(1 * 60 * 60), @"1 h");
3509 insta::assert_snapshot!(p(2 * 60 * 60), @"2 h");
3510 insta::assert_snapshot!(p(10 * 60 * 60), @"10 h");
3511 insta::assert_snapshot!(p(100 * 60 * 60), @"100 h");
3512
3513 insta::assert_snapshot!(
3514 p(60 * 60 + 60 + 1),
3515 @"1 h, 1 m, 1 s",
3516 );
3517 insta::assert_snapshot!(
3518 p(2 * 60 * 60 + 2 * 60 + 2),
3519 @"2 h, 2 m, 2 s",
3520 );
3521 insta::assert_snapshot!(
3522 p(10 * 60 * 60 + 10 * 60 + 10),
3523 @"10 h, 10 m, 10 s",
3524 );
3525 insta::assert_snapshot!(
3526 p(100 * 60 * 60 + 100 * 60 + 100),
3527 @"101 h, 41 m, 40 s",
3528 );
3529 }
3530
3531 #[test]
3532 fn print_unsigned_duration_designator_fractional_hour() {
3533 let printer =
3534 || SpanPrinter::new().fractional(Some(FractionalUnit::Hour));
3535 let p = |secs, nanos| {
3536 printer().unsigned_duration_to_string(&core::time::Duration::new(
3537 secs, nanos,
3538 ))
3539 };
3540 let pp = |precision, secs, nanos| {
3541 printer()
3542 .precision(Some(precision))
3543 .duration_to_string(&SignedDuration::new(secs, nanos))
3544 };
3545
3546 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3547 insta::assert_snapshot!(pp(0, 1 * 60 * 60, 0), @"1h");
3548 insta::assert_snapshot!(pp(1, 1 * 60 * 60, 0), @"1.0h");
3549 insta::assert_snapshot!(pp(2, 1 * 60 * 60, 0), @"1.00h");
3550
3551 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1.5h");
3552 insta::assert_snapshot!(pp(0, 1 * 60 * 60 + 30 * 60, 0), @"1h");
3553 insta::assert_snapshot!(pp(1, 1 * 60 * 60 + 30 * 60, 0), @"1.5h");
3554 insta::assert_snapshot!(pp(2, 1 * 60 * 60 + 30 * 60, 0), @"1.50h");
3555
3556 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 0), @"1.05h");
3557 insta::assert_snapshot!(p(1 * 60 * 60 + 3 * 60, 1), @"1.05h");
3558 insta::assert_snapshot!(p(1, 0), @"0.000277777h");
3559 insta::assert_snapshot!(p(1, 1), @"0.000277777h");
3561 insta::assert_snapshot!(p(0, 0), @"0h");
3562 insta::assert_snapshot!(p(0, 1), @"0h");
3564 }
3565
3566 #[test]
3567 fn print_unsigned_duration_designator_fractional_minute() {
3568 let printer =
3569 || SpanPrinter::new().fractional(Some(FractionalUnit::Minute));
3570 let p = |secs, nanos| {
3571 printer().unsigned_duration_to_string(&core::time::Duration::new(
3572 secs, nanos,
3573 ))
3574 };
3575 let pp = |precision, secs, nanos| {
3576 printer()
3577 .precision(Some(precision))
3578 .duration_to_string(&SignedDuration::new(secs, nanos))
3579 };
3580
3581 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3582 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3583
3584 insta::assert_snapshot!(p(60, 0), @"1m");
3585 insta::assert_snapshot!(pp(0, 60, 0), @"1m");
3586 insta::assert_snapshot!(pp(1, 60, 0), @"1.0m");
3587 insta::assert_snapshot!(pp(2, 60, 0), @"1.00m");
3588
3589 insta::assert_snapshot!(p(90, 0), @"1.5m");
3590 insta::assert_snapshot!(pp(0, 90, 0), @"1m");
3591 insta::assert_snapshot!(pp(1, 90, 0), @"1.5m");
3592 insta::assert_snapshot!(pp(2, 90, 0), @"1.50m");
3593
3594 insta::assert_snapshot!(p(1 * 60 * 60, 1), @"1h");
3595 insta::assert_snapshot!(p(63, 0), @"1.05m");
3596 insta::assert_snapshot!(p(63, 1), @"1.05m");
3597 insta::assert_snapshot!(p(1, 0), @"0.016666666m");
3598 insta::assert_snapshot!(p(1, 1), @"0.016666666m");
3600 insta::assert_snapshot!(p(0, 0), @"0m");
3601 insta::assert_snapshot!(p(0, 1), @"0m");
3603 }
3604
3605 #[test]
3606 fn print_unsigned_duration_designator_fractional_second() {
3607 let printer =
3608 || SpanPrinter::new().fractional(Some(FractionalUnit::Second));
3609 let p = |secs, nanos| {
3610 printer().unsigned_duration_to_string(&core::time::Duration::new(
3611 secs, nanos,
3612 ))
3613 };
3614 let pp = |precision, secs, nanos| {
3615 printer()
3616 .precision(Some(precision))
3617 .duration_to_string(&SignedDuration::new(secs, nanos))
3618 };
3619
3620 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3621 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3622
3623 insta::assert_snapshot!(p(1, 0), @"1s");
3624 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3625 insta::assert_snapshot!(pp(1, 1, 0), @"1.0s");
3626 insta::assert_snapshot!(pp(2, 1, 0), @"1.00s");
3627
3628 insta::assert_snapshot!(p(1, 500_000_000), @"1.5s");
3629 insta::assert_snapshot!(pp(0, 1, 500_000_000), @"1s");
3630 insta::assert_snapshot!(pp(1, 1, 500_000_000), @"1.5s");
3631 insta::assert_snapshot!(pp(2, 1, 500_000_000), @"1.50s");
3632
3633 insta::assert_snapshot!(p(1, 1), @"1.000000001s");
3634 insta::assert_snapshot!(p(0, 1), @"0.000000001s");
3635 insta::assert_snapshot!(p(0, 0), @"0s");
3636 }
3637
3638 #[test]
3639 fn print_unsigned_duration_designator_fractional_millisecond() {
3640 let printer = || {
3641 SpanPrinter::new().fractional(Some(FractionalUnit::Millisecond))
3642 };
3643 let p = |secs, nanos| {
3644 printer().unsigned_duration_to_string(&core::time::Duration::new(
3645 secs, nanos,
3646 ))
3647 };
3648 let pp = |precision, secs, nanos| {
3649 printer()
3650 .precision(Some(precision))
3651 .duration_to_string(&SignedDuration::new(secs, nanos))
3652 };
3653
3654 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3655 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3656 insta::assert_snapshot!(
3657 p(1 * 60 * 60 + 30 * 60 + 10, 0),
3658 @"1h 30m 10s",
3659 );
3660
3661 insta::assert_snapshot!(p(1, 0), @"1s");
3662 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3663 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0ms");
3664 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00ms");
3665
3666 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
3667 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms");
3668 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1.5ms");
3669 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1.50ms");
3670
3671 insta::assert_snapshot!(p(0, 1_000_001), @"1.000001ms");
3672 insta::assert_snapshot!(p(0, 0_000_001), @"0.000001ms");
3673 insta::assert_snapshot!(p(0, 0), @"0ms");
3674 }
3675
3676 #[test]
3677 fn print_unsigned_duration_designator_fractional_microsecond() {
3678 let printer = || {
3679 SpanPrinter::new().fractional(Some(FractionalUnit::Microsecond))
3680 };
3681 let p = |secs, nanos| {
3682 printer().unsigned_duration_to_string(&core::time::Duration::new(
3683 secs, nanos,
3684 ))
3685 };
3686 let pp = |precision, secs, nanos| {
3687 printer().precision(Some(precision)).unsigned_duration_to_string(
3688 &core::time::Duration::new(secs, nanos),
3689 )
3690 };
3691
3692 insta::assert_snapshot!(p(1 * 60 * 60, 0), @"1h");
3693 insta::assert_snapshot!(p(1 * 60 * 60 + 30 * 60, 0), @"1h 30m");
3694 insta::assert_snapshot!(
3695 p(1 * 60 * 60 + 30 * 60 + 10, 0),
3696 @"1h 30m 10s",
3697 );
3698
3699 insta::assert_snapshot!(p(1, 0), @"1s");
3700 insta::assert_snapshot!(pp(0, 1, 0), @"1s");
3701 insta::assert_snapshot!(pp(1, 1, 0), @"1s 0.0µs");
3702 insta::assert_snapshot!(pp(2, 1, 0), @"1s 0.00µs");
3703
3704 insta::assert_snapshot!(p(1, 500_000_000), @"1s 500ms");
3705 insta::assert_snapshot!(pp(0, 1, 1_500_000), @"1s 1ms 500µs");
3706 insta::assert_snapshot!(pp(1, 1, 1_500_000), @"1s 1ms 500.0µs");
3707 insta::assert_snapshot!(pp(2, 1, 1_500_000), @"1s 1ms 500.00µs");
3708
3709 insta::assert_snapshot!(p(0, 1_000_001), @"1ms 0.001µs");
3710 insta::assert_snapshot!(p(0, 0_000_001), @"0.001µs");
3711 insta::assert_snapshot!(p(0, 0), @"0µs");
3712 }
3713
3714 #[test]
3715 fn print_span_hms() {
3716 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3717 let p = |span| printer().span_to_string(&span);
3718
3719 insta::assert_snapshot!(p(1.second()), @"00:00:01");
3720 insta::assert_snapshot!(p(2.seconds()), @"00:00:02");
3721 insta::assert_snapshot!(p(10.seconds()), @"00:00:10");
3722 insta::assert_snapshot!(p(100.seconds()), @"00:00:100");
3723
3724 insta::assert_snapshot!(p(1.minute()), @"00:01:00");
3725 insta::assert_snapshot!(p(2.minutes()), @"00:02:00");
3726 insta::assert_snapshot!(p(10.minutes()), @"00:10:00");
3727 insta::assert_snapshot!(p(100.minutes()), @"00:100:00");
3728
3729 insta::assert_snapshot!(p(1.hour()), @"01:00:00");
3730 insta::assert_snapshot!(p(2.hours()), @"02:00:00");
3731 insta::assert_snapshot!(p(10.hours()), @"10:00:00");
3732 insta::assert_snapshot!(p(100.hours()), @"100:00:00");
3733
3734 insta::assert_snapshot!(
3735 p(1.hour().minutes(1).seconds(1)),
3736 @"01:01:01",
3737 );
3738 insta::assert_snapshot!(
3739 p(2.hours().minutes(2).seconds(2)),
3740 @"02:02:02",
3741 );
3742 insta::assert_snapshot!(
3743 p(10.hours().minutes(10).seconds(10)),
3744 @"10:10:10",
3745 );
3746 insta::assert_snapshot!(
3747 p(100.hours().minutes(100).seconds(100)),
3748 @"100:100:100",
3749 );
3750
3751 insta::assert_snapshot!(
3752 p(1.day().hours(1).minutes(1).seconds(1)),
3753 @"1d 01:01:01",
3754 );
3755 insta::assert_snapshot!(
3756 p(1.day()),
3757 @"1d 00:00:00",
3758 );
3759 insta::assert_snapshot!(
3760 p(1.day().seconds(2)),
3761 @"1d 00:00:02",
3762 );
3763 }
3764
3765 #[test]
3766 fn print_span_hms_fmt() {
3767 let printer = || {
3768 SpanPrinter::new()
3769 .hours_minutes_seconds(true)
3770 .comma_after_designator(true)
3771 .spacing(Spacing::BetweenUnitsAndDesignators)
3772 };
3773 let p = |span| printer().span_to_string(&span);
3774
3775 insta::assert_snapshot!(
3776 p(1.day().hours(1).minutes(1).seconds(1)),
3777 @"1 d, 01:01:01",
3778 );
3779 insta::assert_snapshot!(
3780 p(1.year().months(1).weeks(1).days(1).hours(1).minutes(1).seconds(1)),
3781 @"1 y, 1 mo, 1 w, 1 d, 01:01:01",
3782 );
3783 insta::assert_snapshot!(
3784 p(1.day().hours(1).minutes(1).seconds(1).nanoseconds(1)),
3785 @"1 d, 01:01:01.000000001",
3786 );
3787 }
3788
3789 #[test]
3790 fn print_span_hms_sign() {
3791 let printer = |direction| {
3792 SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
3793 };
3794 let p = |direction, span| printer(direction).span_to_string(&span);
3795
3796 insta::assert_snapshot!(
3797 p(Direction::Auto, 1.hour()),
3798 @"01:00:00",
3799 );
3800 insta::assert_snapshot!(
3801 p(Direction::Sign, 1.hour()),
3802 @"01:00:00",
3803 );
3804 insta::assert_snapshot!(
3805 p(Direction::ForceSign, 1.hour()),
3806 @"+01:00:00",
3807 );
3808 insta::assert_snapshot!(
3809 p(Direction::Suffix, 1.hour()),
3810 @"01:00:00",
3811 );
3812 insta::assert_snapshot!(
3813 p(Direction::Auto, -1.hour()),
3814 @"-01:00:00",
3815 );
3816 insta::assert_snapshot!(
3817 p(Direction::Sign, -1.hour()),
3818 @"-01:00:00",
3819 );
3820 insta::assert_snapshot!(
3821 p(Direction::ForceSign, -1.hour()),
3822 @"-01:00:00",
3823 );
3824 insta::assert_snapshot!(
3825 p(Direction::Suffix, -1.hour()),
3826 @"01:00:00 ago",
3827 );
3828
3829 insta::assert_snapshot!(
3830 p(Direction::Auto, 1.day().hours(1)),
3831 @"1d 01:00:00",
3832 );
3833 insta::assert_snapshot!(
3834 p(Direction::Sign, 1.day().hours(1)),
3835 @"1d 01:00:00",
3836 );
3837 insta::assert_snapshot!(
3838 p(Direction::ForceSign, 1.day().hours(1)),
3839 @"+1d 01:00:00",
3840 );
3841 insta::assert_snapshot!(
3842 p(Direction::Suffix, 1.day().hours(1)),
3843 @"1d 01:00:00",
3844 );
3845 insta::assert_snapshot!(
3849 p(Direction::Auto, -1.day().hours(1)),
3850 @"1d 01:00:00 ago",
3851 );
3852 insta::assert_snapshot!(
3853 p(Direction::Sign, -1.day().hours(1)),
3854 @"-1d 01:00:00",
3855 );
3856 insta::assert_snapshot!(
3857 p(Direction::ForceSign, -1.day().hours(1)),
3858 @"-1d 01:00:00",
3859 );
3860 insta::assert_snapshot!(
3861 p(Direction::Suffix, -1.day().hours(1)),
3862 @"1d 01:00:00 ago",
3863 );
3864 }
3865
3866 #[test]
3867 fn print_span_hms_fraction_auto() {
3868 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3869 let p = |span| printer().span_to_string(&span);
3870
3871 insta::assert_snapshot!(p(1.nanosecond()), @"00:00:00.000000001");
3872 insta::assert_snapshot!(p(-1.nanosecond()), @"-00:00:00.000000001");
3873 insta::assert_snapshot!(
3874 printer().direction(Direction::ForceSign).span_to_string(&1.nanosecond()),
3875 @"+00:00:00.000000001",
3876 );
3877
3878 insta::assert_snapshot!(
3879 p(1.second().nanoseconds(123)),
3880 @"00:00:01.000000123",
3881 );
3882 insta::assert_snapshot!(
3883 p(1.second().milliseconds(123)),
3884 @"00:00:01.123",
3885 );
3886 insta::assert_snapshot!(
3887 p(1.second().milliseconds(1_123)),
3888 @"00:00:02.123",
3889 );
3890 insta::assert_snapshot!(
3891 p(1.second().milliseconds(61_123)),
3892 @"00:00:62.123",
3893 );
3894 }
3895
3896 #[test]
3897 fn print_span_hms_fraction_fixed_precision() {
3898 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3899 let p = |precision, span| {
3900 printer().precision(Some(precision)).span_to_string(&span)
3901 };
3902
3903 insta::assert_snapshot!(p(3, 1.second()), @"00:00:01.000");
3904 insta::assert_snapshot!(
3905 p(3, 1.second().milliseconds(1)),
3906 @"00:00:01.001",
3907 );
3908 insta::assert_snapshot!(
3909 p(3, 1.second().milliseconds(123)),
3910 @"00:00:01.123",
3911 );
3912 insta::assert_snapshot!(
3913 p(3, 1.second().milliseconds(100)),
3914 @"00:00:01.100",
3915 );
3916
3917 insta::assert_snapshot!(p(0, 1.second()), @"00:00:01");
3918 insta::assert_snapshot!(p(0, 1.second().milliseconds(1)), @"00:00:01");
3919 insta::assert_snapshot!(
3920 p(1, 1.second().milliseconds(999)),
3921 @"00:00:01.9",
3922 );
3923 }
3924
3925 #[test]
3926 fn print_signed_duration_hms() {
3927 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3928 let p = |secs| {
3929 printer().duration_to_string(&SignedDuration::from_secs(secs))
3930 };
3931
3932 insta::assert_snapshot!(p(1), @"00:00:01");
3936 insta::assert_snapshot!(p(2), @"00:00:02");
3937 insta::assert_snapshot!(p(10), @"00:00:10");
3938 insta::assert_snapshot!(p(100), @"00:01:40");
3939
3940 insta::assert_snapshot!(p(1 * 60), @"00:01:00");
3941 insta::assert_snapshot!(p(2 * 60), @"00:02:00");
3942 insta::assert_snapshot!(p(10 * 60), @"00:10:00");
3943 insta::assert_snapshot!(p(100 * 60), @"01:40:00");
3944
3945 insta::assert_snapshot!(p(1 * 60 * 60), @"01:00:00");
3946 insta::assert_snapshot!(p(2 * 60 * 60), @"02:00:00");
3947 insta::assert_snapshot!(p(10 * 60 * 60), @"10:00:00");
3948 insta::assert_snapshot!(p(100 * 60 * 60), @"100:00:00");
3949
3950 insta::assert_snapshot!(
3951 p(60 * 60 + 60 + 1),
3952 @"01:01:01",
3953 );
3954 insta::assert_snapshot!(
3955 p(2 * 60 * 60 + 2 * 60 + 2),
3956 @"02:02:02",
3957 );
3958 insta::assert_snapshot!(
3959 p(10 * 60 * 60 + 10 * 60 + 10),
3960 @"10:10:10",
3961 );
3962 insta::assert_snapshot!(
3963 p(100 * 60 * 60 + 100 * 60 + 100),
3964 @"101:41:40",
3965 );
3966 }
3967
3968 #[test]
3969 fn print_signed_duration_hms_sign() {
3970 let printer = |direction| {
3971 SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
3972 };
3973 let p = |direction, secs| {
3974 printer(direction)
3975 .duration_to_string(&SignedDuration::from_secs(secs))
3976 };
3977
3978 insta::assert_snapshot!(p(Direction::Auto, 1), @"00:00:01");
3979 insta::assert_snapshot!(p(Direction::Sign, 1), @"00:00:01");
3980 insta::assert_snapshot!(p(Direction::ForceSign, 1), @"+00:00:01");
3981 insta::assert_snapshot!(p(Direction::Suffix, 1), @"00:00:01");
3982
3983 insta::assert_snapshot!(p(Direction::Auto, -1), @"-00:00:01");
3984 insta::assert_snapshot!(p(Direction::Sign, -1), @"-00:00:01");
3985 insta::assert_snapshot!(p(Direction::ForceSign, -1), @"-00:00:01");
3986 insta::assert_snapshot!(p(Direction::Suffix, -1), @"00:00:01 ago");
3987 }
3988
3989 #[test]
3990 fn print_signed_duration_hms_fraction_auto() {
3991 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
3992 let p = |secs, nanos| {
3993 printer().duration_to_string(&SignedDuration::new(secs, nanos))
3994 };
3995
3996 insta::assert_snapshot!(p(0, 1), @"00:00:00.000000001");
3997 insta::assert_snapshot!(p(0, -1), @"-00:00:00.000000001");
3998 insta::assert_snapshot!(
3999 printer().direction(Direction::ForceSign).duration_to_string(
4000 &SignedDuration::new(0, 1),
4001 ),
4002 @"+00:00:00.000000001",
4003 );
4004
4005 insta::assert_snapshot!(
4006 p(1, 123),
4007 @"00:00:01.000000123",
4008 );
4009 insta::assert_snapshot!(
4010 p(1, 123_000_000),
4011 @"00:00:01.123",
4012 );
4013 insta::assert_snapshot!(
4014 p(1, 1_123_000_000),
4015 @"00:00:02.123",
4016 );
4017 insta::assert_snapshot!(
4018 p(61, 1_123_000_000),
4019 @"00:01:02.123",
4020 );
4021 }
4022
4023 #[test]
4024 fn print_signed_duration_hms_fraction_fixed_precision() {
4025 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
4026 let p = |precision, secs, nanos| {
4027 printer()
4028 .precision(Some(precision))
4029 .duration_to_string(&SignedDuration::new(secs, nanos))
4030 };
4031
4032 insta::assert_snapshot!(p(3, 1, 0), @"00:00:01.000");
4033 insta::assert_snapshot!(
4034 p(3, 1, 1_000_000),
4035 @"00:00:01.001",
4036 );
4037 insta::assert_snapshot!(
4038 p(3, 1, 123_000_000),
4039 @"00:00:01.123",
4040 );
4041 insta::assert_snapshot!(
4042 p(3, 1, 100_000_000),
4043 @"00:00:01.100",
4044 );
4045
4046 insta::assert_snapshot!(p(0, 1, 0), @"00:00:01");
4047 insta::assert_snapshot!(p(0, 1, 1_000_000), @"00:00:01");
4048 insta::assert_snapshot!(
4049 p(1, 1, 999_000_000),
4050 @"00:00:01.9",
4051 );
4052 }
4053
4054 #[test]
4055 fn print_unsigned_duration_hms() {
4056 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
4057 let p = |secs| {
4058 printer().unsigned_duration_to_string(
4059 &core::time::Duration::from_secs(secs),
4060 )
4061 };
4062
4063 insta::assert_snapshot!(p(1), @"00:00:01");
4067 insta::assert_snapshot!(p(2), @"00:00:02");
4068 insta::assert_snapshot!(p(10), @"00:00:10");
4069 insta::assert_snapshot!(p(100), @"00:01:40");
4070
4071 insta::assert_snapshot!(p(1 * 60), @"00:01:00");
4072 insta::assert_snapshot!(p(2 * 60), @"00:02:00");
4073 insta::assert_snapshot!(p(10 * 60), @"00:10:00");
4074 insta::assert_snapshot!(p(100 * 60), @"01:40:00");
4075
4076 insta::assert_snapshot!(p(1 * 60 * 60), @"01:00:00");
4077 insta::assert_snapshot!(p(2 * 60 * 60), @"02:00:00");
4078 insta::assert_snapshot!(p(10 * 60 * 60), @"10:00:00");
4079 insta::assert_snapshot!(p(100 * 60 * 60), @"100:00:00");
4080
4081 insta::assert_snapshot!(
4082 p(60 * 60 + 60 + 1),
4083 @"01:01:01",
4084 );
4085 insta::assert_snapshot!(
4086 p(2 * 60 * 60 + 2 * 60 + 2),
4087 @"02:02:02",
4088 );
4089 insta::assert_snapshot!(
4090 p(10 * 60 * 60 + 10 * 60 + 10),
4091 @"10:10:10",
4092 );
4093 insta::assert_snapshot!(
4094 p(100 * 60 * 60 + 100 * 60 + 100),
4095 @"101:41:40",
4096 );
4097 }
4098
4099 #[test]
4100 fn print_unsigned_duration_hms_sign() {
4101 let printer = |direction| {
4102 SpanPrinter::new().hours_minutes_seconds(true).direction(direction)
4103 };
4104 let p = |direction, secs| {
4105 printer(direction).unsigned_duration_to_string(
4106 &core::time::Duration::from_secs(secs),
4107 )
4108 };
4109
4110 insta::assert_snapshot!(p(Direction::Auto, 1), @"00:00:01");
4111 insta::assert_snapshot!(p(Direction::Sign, 1), @"00:00:01");
4112 insta::assert_snapshot!(p(Direction::ForceSign, 1), @"+00:00:01");
4113 insta::assert_snapshot!(p(Direction::Suffix, 1), @"00:00:01");
4114 }
4115
4116 #[test]
4117 fn print_unsigned_duration_hms_fraction_auto() {
4118 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
4119 let p = |secs, nanos| {
4120 printer().unsigned_duration_to_string(&core::time::Duration::new(
4121 secs, nanos,
4122 ))
4123 };
4124
4125 insta::assert_snapshot!(p(0, 1), @"00:00:00.000000001");
4126 insta::assert_snapshot!(
4127 printer().direction(Direction::ForceSign).duration_to_string(
4128 &SignedDuration::new(0, 1),
4129 ),
4130 @"+00:00:00.000000001",
4131 );
4132
4133 insta::assert_snapshot!(
4134 p(1, 123),
4135 @"00:00:01.000000123",
4136 );
4137 insta::assert_snapshot!(
4138 p(1, 123_000_000),
4139 @"00:00:01.123",
4140 );
4141 insta::assert_snapshot!(
4142 p(1, 1_123_000_000),
4143 @"00:00:02.123",
4144 );
4145 insta::assert_snapshot!(
4146 p(61, 1_123_000_000),
4147 @"00:01:02.123",
4148 );
4149 }
4150
4151 #[test]
4152 fn print_unsigned_duration_hms_fraction_fixed_precision() {
4153 let printer = || SpanPrinter::new().hours_minutes_seconds(true);
4154 let p = |precision, secs, nanos| {
4155 printer().precision(Some(precision)).unsigned_duration_to_string(
4156 &core::time::Duration::new(secs, nanos),
4157 )
4158 };
4159
4160 insta::assert_snapshot!(p(3, 1, 0), @"00:00:01.000");
4161 insta::assert_snapshot!(
4162 p(3, 1, 1_000_000),
4163 @"00:00:01.001",
4164 );
4165 insta::assert_snapshot!(
4166 p(3, 1, 123_000_000),
4167 @"00:00:01.123",
4168 );
4169 insta::assert_snapshot!(
4170 p(3, 1, 100_000_000),
4171 @"00:00:01.100",
4172 );
4173
4174 insta::assert_snapshot!(p(0, 1, 0), @"00:00:01");
4175 insta::assert_snapshot!(p(0, 1, 1_000_000), @"00:00:01");
4176 insta::assert_snapshot!(
4177 p(1, 1, 999_000_000),
4178 @"00:00:01.9",
4179 );
4180 }
4181
4182 #[test]
4187 fn maximums() {
4188 let p = SpanPrinter::new()
4189 .padding(u8::MAX)
4190 .designator(Designator::Verbose)
4191 .spacing(Spacing::BetweenUnitsAndDesignators)
4192 .comma_after_designator(true);
4193
4194 let span = -19_998
4195 .year()
4196 .months(239_976)
4197 .weeks(1_043_497)
4198 .days(7_304_484)
4199 .hours(175_307_616)
4200 .minutes(10_518_456_960i64)
4201 .seconds(631_107_417_600i64)
4202 .milliseconds(631_107_417_600_000i64)
4203 .microseconds(631_107_416_600_000_000i64)
4204 .nanoseconds(9_223_372_036_854_775_807i64);
4205 insta::assert_snapshot!(
4206 p.span_to_string(&span),
4207 @"00000000000000019998 years, 00000000000000239976 months, 00000000000001043497 weeks, 00000000000007304484 days, 00000000000175307616 hours, 00000000010518456960 minutes, 00000000631107417600 seconds, 00000631107417600000 milliseconds, 00631107416600000000 microseconds, 09223372036854775807 nanoseconds ago",
4208 );
4209
4210 let sdur = SignedDuration::MAX;
4211 insta::assert_snapshot!(
4212 p.duration_to_string(&sdur),
4213 @"00002562047788015215 hours, 00000000000000000030 minutes, 00000000000000000007 seconds, 00000000000000000999 milliseconds, 00000000000000000999 microseconds, 00000000000000000999 nanoseconds",
4214 );
4215
4216 let udur =
4217 core::time::Duration::MAX - core::time::Duration::from_secs(16);
4218 insta::assert_snapshot!(
4219 p.unsigned_duration_to_string(&udur),
4220 @"00005124095576030430 hours, 00000000000000000059 minutes, 00000000000000000059 seconds, 00000000000000000999 milliseconds, 00000000000000000999 microseconds, 00000000000000000999 nanoseconds",
4221 );
4222 }
4223}