Struct SpanPrinter
struct SpanPrinter { ... }
A printer for Jiff's "friendly" duration format.
This printer provides a lot of different knobs for controlling how
durations are formatted. It supports formatting both SignedDuration
and Span.
Example: automatic use through Display
The default configuration of this printer is used for "alternate" display
formatting for both SignedDuration and [Span]:
use ;
let span = 1.year.months.hours.seconds.nanoseconds;
assert_eq!;
let sdur = new;
assert_eq!;
Example: variety of formatting configurations
This example shows a few different ways of formatting the same Span:
use ;
let span = 1.year.months.hours.seconds.nanoseconds;
let printer = new;
assert_eq!;
let printer = new
.designator;
assert_eq!;
let printer = new
.spacing
.designator;
assert_eq!;
let printer = new
.spacing
.comma_after_designator
.designator;
assert_eq!;
let printer = new
.hours_minutes_seconds
.spacing
.comma_after_designator
.designator;
assert_eq!;
Example: negative durations
By default, a negative duration will be represented with an ago suffix:
use ;
let span = -1.year.months.hours.seconds.nanoseconds;
let printer = new;
assert_eq!;
But one can also use a prefix - sign instead. Usually this works better
without any spacing and compact designators:
use ;
let span = -1.year.months.hours.seconds.nanoseconds;
let printer = new
.spacing
.designator;
assert_eq!;
Implementations
impl SpanPrinter
const fn new() -> SpanPrinterCreates a new printer for the "friendly" duration format.
The printer returned uses the default configuration. This is identical to
SpanPrinter::default, but it can be used in aconstcontext.Example
This example shows how to format a duration directly to a
Vec<u8>.use ; static PRINTER: SpanPrinter = new; let span = 1.year.months; let mut buf = vec!; // Writing to a `Vec<u8>` never fails (aside from OOM). PRINTER.print_span.unwrap; assert_eq!;const fn designator(self: Self, designator: Designator) -> SpanPrinterConfigures the kind of unit designators to use.
There are no specific advantages or disadvantages to the kind of designator you pick other than aesthetic preference. Shorter designators are also likely faster to parse and print.
The default is
Designator::Compact, which uses things likeyrinstead ofyear(verbose) ory(compact).Example
use ; let span = 1.year.months; let printer = new; assert_eq!; let printer = new.designator; assert_eq!; let printer = new.designator; assert_eq!;const fn spacing(self: Self, spacing: Spacing) -> SpanPrinterConfigures the spacing between the units and the designator labels.
The default is
Spacing::BetweenUnits, which results in durations like1y 2mo.Spacing::Nonewould result in1y2moandSpacing::BetweenUnitsAndDesignatorswould result in1 y 2 mo.Example
use ; let span = 1.year.months; // The default tries to balance spacing with compact // unit designators. let printer = new; assert_eq!; // But you can use slightly more descriptive // designators without being too verbose. let printer = new .designator; assert_eq!; // When spacing is removed, it usually looks nicer // to use compact unit designators. let printer = new .spacing .designator; assert_eq!; // Conversely, when using more spacing, it usually // looks nicer to use verbose unit designators. let printer = new .spacing .designator; assert_eq!;Example:
Spacing::Nonecan still result in whitespaceIn the case that
SpanPrinter::hours_minutes_secondsis enabled and one is formatting a span with non-zero calendar units, then an ASCII whitespace is inserted between the calendar and non-calendar units even whenSpacing::Noneis used:use ; let span = 1.year.months.hours; let printer = new .spacing .hours_minutes_seconds; assert_eq!;const fn direction(self: Self, direction: Direction) -> SpanPrinterConfigures how and when the sign for the duration is written.
The default is
Direction::Auto. In most cases, this results in writing the suffixagoafter printing the duration units when the sign of the duration is negative. And when the sign is positive, there is no suffix. However, this can vary based on other settings. For example, whenSpanPrinter::spacingis set toSpacing::None, thenDirection::Autois treated as if it wereDirection::Sign.Example
use ; let duration = from_secs; let printer = new; assert_eq!; let printer = new.direction; assert_eq!;const fn fractional(self: Self, unit: Option<FractionalUnit>) -> SpanPrinterEnable fractional formatting for the given unit.
When
SpanPrinter::hours_minutes_secondsis enabled, then this setting is automatically set toFractionalUnit::Second. Otherwise, it defaults toNone, which means no fractions are ever written.Example
This example shows how to write the same duration with different fractional settings:
use ; let duration = from_secs; let printer = new .fractional; assert_eq!; let printer = new .fractional; assert_eq!; let printer = new .fractional; assert_eq!;Example: precision loss
Because the "friendly" format is limited to 9 decimal places, when using
FractionalUnit::HourorFractionalUnit::Minute, it is possible for precision loss to occur.use ; // one nanosecond let duration = new; let printer = new .fractional; assert_eq!; let printer = new .fractional; assert_eq!;const fn comma_after_designator(self: Self, yes: bool) -> SpanPrinterWhen enabled, commas are written after unit designators.
This is disabled by default.
Example
use ; static PRINTER: SpanPrinter = new .designator .spacing .comma_after_designator; let span = 5.years.months.milliseconds; assert_eq!;const fn hours_minutes_seconds(self: Self, yes: bool) -> SpanPrinterFormats the span or duration into a
HH:MM:SS[.fffffffff]format.When formatting a
Spanwith non-zero calendar units (units of days or greater), then the calendar units are formatted as typical with their corresponding designators. For example,1d 01:00:00. Note that when formatting aSignedDuration, calendar units are never used.When this is enabled, many of the other options are either ignored or fixed to a specific setting:
- Since this format does not use any unit designators for units of
hours or smaller, the
SpanPrinter::designatorsetting is ignored for hours or smaller. It is still used when formatting aSpanwith non-zero calendar units. SpanPrinter::spacingsetting is ignored for units of hours or smaller.- The
SpanPrinter::fractionalsetting is forcefully set toFractionalUnit::Second. It cannot be changed. - The
SpanPrinter::comma_after_designatorsetting is ignored for units of hours or smaller. - When the padding is not specified, it defaults to
2for hours, minutes and seconds and0for any calendar units present. - The precision setting is respected as documented.
This format is useful in contexts for interfacing with existing systems that require this style of format, or if the
HH:MM:SSis just in general preferred.Loss of fidelity
When using this format with a
Span, sub-second units are formatted as a fractional second. This means that1000 millisecondsand1 secondformat to precisely the same string. This is similar to the loss of fidelity when usingfmt::temporalto format spans in the ISO 8601 duration format.Example
This shows how to format a
SpaninHH:MM:SSformat:use ; static PRINTER: SpanPrinter = new.hours_minutes_seconds; let span = 2.hours.minutes.seconds.milliseconds; assert_eq!; assert_eq!; // This shows what happens with calendar units. let span = 15.days.hours.minutes.seconds.milliseconds; assert_eq!; // Notice that because calendar units are specified and the sign // setting is set to "auto" by default, it has switched to a suffix. assert_eq!;And this shows the same, but with a [
SignedDuration]:use ; static PRINTER: SpanPrinter = new.hours_minutes_seconds; let duration = new; assert_eq!; assert_eq!;Example:
SpanversusSignedDurationThe main advantage of a
Spanis that, except for fractional components, the unit values emitted correspond precisely to the values in theSpan. Where as for aSignedDuration, the units are always computed from a single absolute duration in a way that is always balanced:use ; static PRINTER: SpanPrinter = new.hours_minutes_seconds; let span = 120.minutes; assert_eq!; let duration = from_mins; assert_eq!;Of course, a balanced duration is sometimes what you want. But
Spanaffords the flexibility of controlling precisely what the unit values are.- Since this format does not use any unit designators for units of
hours or smaller, the
const fn padding(self: Self, digits: u8) -> SpanPrinterThe padding to use when writing unit values.
If a unit value has fewer digits than specified here, it is padded to the left with zeroes. (To control precision, i.e., padding to the right when writing fractional values, use
SpanPrinter::precision.)By default, when writing in the hours-minutes-seconds format, a padding of
2is used for units of hours, minutes and seconds. Otherwise, a padding of0is used.Example
This shows some examples of configuring padding when writing in default format with unit designators:
use ; let printer = new; assert_eq!; let printer = new.padding; assert_eq!;And this shows some examples with the hours-minutes-seconds format. Notice how padding is enabled by default.
use ; let printer = new.hours_minutes_seconds; assert_eq!; let printer = new.hours_minutes_seconds.padding; assert_eq!; // In this case, under the default configuration, the padding // for calendar units is 0 but the padding for time units is 2. let printer = new.hours_minutes_seconds; assert_eq!;const fn precision(self: Self, precision: Option<u8>) -> SpanPrinterThe precision to use when writing fractional unit values.
This setting has no effect if fractional formatting isn't enabled. Fractional formatting is only enabled when
SpanPrinter::fractionalis set or ifSpanPrinter::hours_minutes_secondsare enabled. Neither are enabled by default.A precision of
Some(0)implies that truncation of any fractional component always occurs.The default value is
None, which means the precision is automatically determined from the value. If no fractional component is needed, then none will be printed.Example
use ; // No effect, because fractions aren't enabled. let printer = new.precision; assert_eq!; // Precision setting takes effect! let printer = new .precision .fractional; assert_eq!; // The HH:MM:SS format automatically enables fractional // second values. let printer = new // Truncate to millisecond precision. .precision .hours_minutes_seconds; let span = 1.second.milliseconds.microseconds.nanoseconds; assert_eq!; // Same as above, but with the designator or "expanded" // format. This requires explicitly enabling fractional // units. let printer = new // Truncate to millisecond precision. .precision .fractional; let span = 1.second.milliseconds.microseconds.nanoseconds; assert_eq!;const fn zero_unit(self: Self, unit: Unit) -> SpanPrinterSets the unit to use when printing a duration that is zero.
When
SpanPrinter::fractionalis set, then this setting is ignored and the zero unit corresponds to the fractional unit specified.This defaults to
Unit::Second.Example
use ; // The default just always uses seconds. let printer = new; assert_eq!; // We can set our own unit. let printer = new.zero_unit; assert_eq!; // But it's overridden if fractional units are set. let printer = new .zero_unit .fractional; assert_eq!; // One use case for this option is if you're rounding // spans and want the zero unit to reflect the smallest // unit you're using. let printer = new.zero_unit; let span = 5.hours.minutes.seconds; let rounded = span.round?; assert_eq!; let span = 5.seconds; let rounded = span.round?; assert_eq!; # Ok::The same applies for
SignedDuration:use ; // The default just always uses seconds. let printer = new; assert_eq!; // We can set our own unit. let printer = new.zero_unit; assert_eq!;fn span_to_string(self: &Self, span: &Span) -> StringFormat a
Spaninto a string using the "friendly" format.This is a convenience routine for
SpanPrinter::print_spanwith aString.Example
use ; static PRINTER: SpanPrinter = new; let span = 3.years.months; assert_eq!;fn duration_to_string(self: &Self, duration: &SignedDuration) -> StringFormat a
SignedDurationinto a string using the "friendly" format.This balances the units of the duration up to at most hours automatically.
This is a convenience routine for
SpanPrinter::print_durationwith aString.Example
use ; static PRINTER: SpanPrinter = new; let dur = new; assert_eq!; assert_eq!; // Or, if you prefer fractional seconds: static PRINTER_FRACTIONAL: SpanPrinter = new .fractional; assert_eq!;fn print_span<W: Write>(self: &Self, span: &Span, wtr: W) -> Result<(), Error>Print a
Spanto the given writer using the "friendly" format.Errors
This only returns an error when writing to the given
Writeimplementation would fail. Some such implementations, like forStringandVec<u8>, never fail (unless memory allocation fails). In such cases, it would be appropriate to callunwrap()on the result.Example
use ; static PRINTER: SpanPrinter = new; let span = 3.years.months; let mut buf = Stringnew; // Printing to a `String` can never fail. PRINTER.print_span.unwrap; assert_eq!;fn print_duration<W: Write>(self: &Self, duration: &SignedDuration, wtr: W) -> Result<(), Error>Print a
SignedDurationto the given writer using the "friendly" format.This balances the units of the duration up to at most hours automatically.
Errors
This only returns an error when writing to the given
Writeimplementation would fail. Some such implementations, like forStringandVec<u8>, never fail (unless memory allocation fails). In such cases, it would be appropriate to callunwrap()on the result.Example
use ; static PRINTER: SpanPrinter = new; let dur = new; let mut buf = Stringnew; // Printing to a `String` can never fail. PRINTER.print_duration.unwrap; assert_eq!; // Negative durations are supported. buf.clear; PRINTER.print_duration.unwrap; assert_eq!;
impl Clone for SpanPrinter
fn clone(self: &Self) -> SpanPrinter
impl Debug for SpanPrinter
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl Default for SpanPrinter
fn default() -> SpanPrinter
impl Freeze for SpanPrinter
impl RefUnwindSafe for SpanPrinter
impl Send for SpanPrinter
impl Sync for SpanPrinter
impl Unpin for SpanPrinter
impl UnsafeUnpin for SpanPrinter
impl UnwindSafe for SpanPrinter
impl<T> Any for SpanPrinter
fn type_id(self: &Self) -> TypeId
impl<T> Borrow for SpanPrinter
fn borrow(self: &Self) -> &T
impl<T> BorrowMut for SpanPrinter
fn borrow_mut(self: &mut Self) -> &mut T
impl<T> CloneToUninit for SpanPrinter
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)
impl<T> From for SpanPrinter
fn from(t: T) -> TReturns the argument unchanged.
impl<T> ToOwned for SpanPrinter
fn to_owned(self: &Self) -> Tfn clone_into(self: &Self, target: &mut T)
impl<T, U> Into for SpanPrinter
fn into(self: Self) -> UCalls
U::from(self).That is, this conversion is whatever the implementation of
[From]<T> for Uchooses to do.
impl<T, U> TryFrom for SpanPrinter
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
impl<T, U> TryInto for SpanPrinter
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>