Struct Config

pub struct Config<C> { /* private fields */ }

Configuration for customizing the behavior of formatting or parsing.

One important use case enabled by this type is the ability to set a Custom trait implementation to use when calling BrokenDownTime::format_with_config or BrokenDownTime::to_string_with_config.

It is generally expected that most callers should not need to use this. At present, the only reasons to use this are:

Example

This example shows how to use PosixCustom via strtime formatting:

use jiff::{civil, fmt::strtime::{BrokenDownTime, PosixCustom, Config}};

let config = Config::new().custom(PosixCustom::new());
let dt = civil::date(2025, 7, 1).at(17, 30, 0, 0);
let tm = BrokenDownTime::from(dt);
assert_eq!(
    tm.to_string_with_config(&config, "%c")?,
    "Tue Jul  1 17:30:00 2025",
);

# Ok::<(), Box<dyn std::error::Error>>(())

Implementations

impl Config<DefaultCustom>

const fn new() -> Config<DefaultCustom>

Create a new default Config that uses DefaultCustom.

impl<C> Config<C>

fn custom<U: Custom>(self, custom: U) -> Config<U>

Set the implementation of Custom to use in strtime-style APIs that use this configuration.

fn lenient(self, yes: bool) -> Config<C>

Enable lenient formatting.

When this is enabled, most errors that occur during formatting are silently ignored. For example, if you try to format %z with a BrokenDownTime that lacks a time zone offset, this would normally result in an error. In contrast, when lenient mode is enabled, this would just result in %z being written literally. Similarly, using invalid UTF-8 in the format string would normally result in an error. In lenient mode, invalid UTF-8 is automatically turned into the Unicode replacement codepoint U+FFFD (which looks like this: ).

Generally speaking, when this is enabled, the only error that can occur when formatting is if a write to the underlying writer fails. When using a writer that never errors (like String, unless allocation fails), it follows that enabling lenient parsing will result in a formatting operation that never fails (unless allocation fails).

This currently has no effect on parsing, although this may change in the future.

Lenient formatting is disabled by default. It is strongly recommended to keep it disabled in order to avoid mysterious failure modes for end users. You should only enable this if you have strict requirements to conform to legacy software behavior.

API stability

An artifact of lenient parsing is that most error behaviors are squashed in favor of writing the errant conversion specifier literally. This means that if you use something like %+, which is currently unrecognized, then that will result in a literal %+ in the string returned. But Jiff may one day add support for %+ in a semver compatible release.

Stated differently, the set of unknown or error conditions is not fixed and may decrease with time. This in turn means that the precise conditions under which a conversion specifier gets written literally to the resulting string may change over time in semver compatible releases of Jiff.

The alternative would be that Jiff could never add any new conversion specifiers without making a semver incompatible release. The intent of this policy is to avoid that scenario and permit reasonable evolution of Jiff's strtime support.

Example

This example shows how %z will be written literally if it would otherwise fail:

use jiff::{civil, fmt::strtime::{BrokenDownTime, Config}};

let tm = BrokenDownTime::from(civil::date(2025, 4, 30));
assert_eq!(
    tm.to_string("%F %z").unwrap_err().to_string(),
    "strftime formatting failed: %z failed: \
     requires time zone offset",
);

// Now enable lenient mode:
let config = Config::new().lenient(true);
assert_eq!(
    tm.to_string_with_config(&config, "%F %z").unwrap(),
    "2025-04-30 %z",
);

// Lenient mode also applies when using an unsupported
// or unrecognized conversion specifier. This would
// normally return an error for example:
assert_eq!(
    tm.to_string_with_config(&config, "%+ %0").unwrap(),
    "%+ %0",
);

Trait Implementations

impl<C: Clone> Clone for Config<C>

fn clone(&self) -> Config<C>

impl<C: Debug> Debug for Config<C>

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Auto Trait Implementations

impl<C> Freeze for Config<C> where C: Freeze,

impl<C> RefUnwindSafe for Config<C> where C: RefUnwindSafe,

impl<C> Send for Config<C> where C: Send,

impl<C> Sync for Config<C> where C: Sync,

impl<C> Unpin for Config<C> where C: Unpin,

impl<C> UnsafeUnpin for Config<C> where C: UnsafeUnpin,

impl<C> UnwindSafe for Config<C> where C: UnwindSafe,

Blanket Implementations

impl<T> Any for Config<C> where T: 'static + ?Sized,

fn type_id(&self) -> TypeId

impl<T> Borrow<T> for Config<C> where T: ?Sized,

fn borrow(&self) -> &T

impl<T> BorrowMut<T> for Config<C> where T: ?Sized,

fn borrow_mut(&mut self) -> &mut T

impl<T> CloneToUninit for Config<C> where T: Clone,

unsafe fn clone_to_uninit(&self, dest: *mut u8)

impl<T> From<T> for Config<C>

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> ToOwned for Config<C> where T: Clone,

type Owned = T;
fn to_owned(&self) -> T
fn clone_into(&self, target: &mut T)

impl<T, U> Into<U> for Config<C> where U: From<T>,

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of [From]<T> for U chooses to do.

impl<T, U> TryFrom<U> for Config<C> where U: Into<T>,

type Error = Infallible;
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

impl<T, U> TryInto<U> for Config<C> where U: TryFrom<T>,

type Error = <U as TryFrom<T>>::Error;
fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>