Enum PiecesOffset

enum PiecesOffset

An offset parsed from a Temporal ISO 8601 datetime string, for use with Pieces.

One can almost think of this as effectively equivalent to an Offset. And indeed, all PiecesOffset values can be convert to an Offset. However, some offsets in a datetime string have a different connotation that can't be captured by an Offset.

For example, the offsets Z, -00:00 and +00:00 all map to Offset::UTC after parsing. However, Z and -00:00 generally indicate that the offset from local time is unknown, where as +00:00 indicates that the offset from local is known and is zero. This type permits callers to inspect what offset was actually written.

Example

This example shows how one can create Temporal ISO 8601 datetime strings with +00:00, -00:00 or Z offsets.

use jiff::{
    fmt::temporal::{Pieces, PiecesNumericOffset},
    tz::Offset,
    Timestamp,
};

// If you create a `Pieces` from a `Timestamp` with a UTC offset,
// then this is interpreted as "the offset from UTC is known and is
// zero."
let pieces = Pieces::from((Timestamp::UNIX_EPOCH, Offset::UTC));
assert_eq!(pieces.to_string(), "1970-01-01T00:00:00+00:00");

// Otherwise, if you create a `Pieces` from just a `Timestamp` with
// no offset, then it is interpreted as "the offset from UTC is not
// known." Typically, this is rendered with `Z` for "Zulu":
let pieces = Pieces::from(Timestamp::UNIX_EPOCH);
assert_eq!(pieces.to_string(), "1970-01-01T00:00:00Z");

// But it might be the case that you want to use `-00:00` instead,
// perhaps to conform to some existing convention or legacy
// applications that require it:
let pieces = Pieces::from(Timestamp::UNIX_EPOCH)
    .with_offset(
        PiecesNumericOffset::from(Offset::UTC).with_negative_zero(),
    );
assert_eq!(pieces.to_string(), "1970-01-01T00:00:00-00:00");

Without Pieces, it's not otherwise possible to emit a -00:00 offset. For example, DateTimePrinter::print_timestamp will always emit Z, which is consider semantically identical to -00:00 by RFC 9557. There's no specific use case where it's expected that you should need to write -00:00 instead of Z, but it's conceivable legacy or otherwise inflexible applications might want it. Or perhaps, in some systems, there is a distinction to draw between Z and -00:00.

Variants

Zulu

The "Zulu" offset, corresponding to UTC in a context where the offset for civil time is unknown or unavailable.

RFC 9557 defines this as equivalent in semantic meaning to -00:00:

If the time in UTC is known, but the offset to local time is unknown, this can be represented with an offset of Z. (The original version of this specification provided -00:00 for this purpose, which is not allowed by ISO-8601:2000 and therefore is less interoperable; Section 3.3 of RFC 5322 describes a related convention for email, which does not have this problem). This differs semantically from an offset of +00:00, which implies that UTC is the preferred reference point for the specified time.

Numeric(PiecesNumericOffset)

A specific numeric offset, including whether the parsed sign is negative.

The sign is usually redundant, since an Offset is itself signed. But it can be used to distinguish between +00:00 (+00 is the preferred offset) and -00:00 (+00 is what should be used, but only because the offset to local time is not known). Generally speaking, one should regard -00:00 as equivalent to Z, per RFC 9557.

Implementations

impl PiecesOffset

fn to_numeric_offset(self: &Self) -> Offset

Converts this offset to a concrete numeric offset in all cases.

If this was a Z or a -00:00 offset, then Offset::UTC is returned. In all other cases, the underlying numeric offset is returned as-is.

Example

use jiff::{
    fmt::temporal::{Pieces, PiecesNumericOffset, PiecesOffset},
    tz::Offset,
};

let pieces = Pieces::parse("1970-01-01T00:00:00Z")?;
let off = pieces.offset().unwrap();
// Parsed as Zulu.
assert_eq!(off, PiecesOffset::Zulu);
// Gets converted from Zulu to UTC, i.e., just zero.
assert_eq!(off.to_numeric_offset(), Offset::UTC);

let pieces = Pieces::parse("1970-01-01T00:00:00-00:00")?;
let off = pieces.offset().unwrap();
// Parsed as a negative zero.
assert_eq!(off, PiecesOffset::from(
    PiecesNumericOffset::from(Offset::UTC).with_negative_zero(),
));
// Gets converted from -00:00 to UTC, i.e., just zero.
assert_eq!(off.to_numeric_offset(), Offset::UTC);

let pieces = Pieces::parse("1970-01-01T00:00:00+00:00")?;
let off = pieces.offset().unwrap();
// Parsed as a positive zero.
assert_eq!(off, PiecesOffset::from(
    PiecesNumericOffset::from(Offset::UTC),
));
// Gets converted from -00:00 to UTC, i.e., just zero.
assert_eq!(off.to_numeric_offset(), Offset::UTC);

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

impl Clone for PiecesOffset

fn clone(self: &Self) -> PiecesOffset

impl Copy for PiecesOffset

impl Debug for PiecesOffset

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

impl Eq for PiecesOffset

impl Freeze for PiecesOffset

impl From for PiecesOffset

fn from(offset: Offset) -> PiecesOffset

impl From for PiecesOffset

fn from(offset: PiecesNumericOffset) -> PiecesOffset

impl Hash for PiecesOffset

fn hash<__H: $crate::hash::Hasher>(self: &Self, state: &mut __H)

impl PartialEq for PiecesOffset

fn eq(self: &Self, other: &PiecesOffset) -> bool

impl RefUnwindSafe for PiecesOffset

impl Send for PiecesOffset

impl StructuralPartialEq for PiecesOffset

impl Sync for PiecesOffset

impl Unpin for PiecesOffset

impl UnsafeUnpin for PiecesOffset

impl UnwindSafe for PiecesOffset

impl<T> Any for PiecesOffset

fn type_id(self: &Self) -> TypeId

impl<T> Borrow for PiecesOffset

fn borrow(self: &Self) -> &T

impl<T> BorrowMut for PiecesOffset

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

impl<T> CloneToUninit for PiecesOffset

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

impl<T> From for PiecesOffset

fn from(t: T) -> T

Returns the argument unchanged.

impl<T> ToOwned for PiecesOffset

fn to_owned(self: &Self) -> T
fn clone_into(self: &Self, target: &mut T)

impl<T, U> Into for PiecesOffset

fn into(self: 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 for PiecesOffset

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

impl<T, U> TryInto for PiecesOffset

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