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