Struct Zoned
pub struct Zoned { /* private fields */ }
dep_jiff
and alloc
only.Expand description
A time zone aware instant in time.
A Zoned
value can be thought of as the combination of following types,
all rolled into one:
- A
Timestamp
for indicating the precise instant in time. - A
DateTime
for indicating the “civil” calendar date and clock time. - A
TimeZone
for indicating how to apply time zone transitions while performing arithmetic.
In particular, a Zoned
is specifically designed for dealing with
datetimes in a time zone aware manner. Here are some highlights:
- Arithmetic automatically adjusts for daylight saving time (DST), using the rules defined by RFC 5545.
- Creating new
Zoned
values from otherZoned
values viaZoned::with
by changing clock time (e.g.,02:30
) can do so without worrying that the time will be invalid due to DST transitions. - An approximate superset of the
DateTime
API is offered onZoned
, but where each of its operations take time zone into account when appropriate. For example,DateTime::start_of_day
always returns a datetime set to midnight, butZoned::start_of_day
returns the first instant of a day, which might not be midnight if there is a time zone transition at midnight. - When using a
Zoned
, it is easy to switch between civil datetime (the day you see on the calendar and the time you see on the clock) and Unix time (a precise instant in time). Indeed, aZoned
can be losslessy converted to any other datetime type in this crate:Timestamp
,DateTime
,Date
andTime
. - A
Zoned
value can be losslessly serialized and deserialized, via serde, by adhering to RFC 8536. An example of a serialized zoned datetime is2024-07-04T08:39:00-04:00[America/New_York]
. - Since a
Zoned
stores aTimeZone
itself, multiple time zone aware operations can be chained together without repeatedly specifying the time zone.
§Parsing and printing
The Zoned
type provides convenient trait implementations of
std::str::FromStr
and std::fmt::Display
:
use jiff::Zoned;
let zdt: Zoned = "2024-06-19 15:22[America/New_York]".parse()?;
// Notice that the second component and the offset have both been added.
assert_eq!(zdt.to_string(), "2024-06-19T15:22:00-04:00[America/New_York]");
// While in the above case the datetime is unambiguous, in some cases, it
// can be ambiguous. In these cases, an offset is required to correctly
// roundtrip a zoned datetime. For example, on 2024-11-03 in New York, the
// 1 o'clock hour was repeated twice, corresponding to the end of daylight
// saving time.
//
// So because of the ambiguity, this time could be in offset -04 (the first
// time 1 o'clock is on the clock) or it could be -05 (the second time
// 1 o'clock is on the clock, corresponding to the end of DST).
//
// By default, parsing uses a "compatible" strategy for resolving all cases
// of ambiguity: in forward transitions (gaps), the later time is selected.
// And in backward transitions (folds), the earlier time is selected.
let zdt: Zoned = "2024-11-03 01:30[America/New_York]".parse()?;
// As we can see, since this was a fold, the earlier time was selected
// because the -04 offset is the first time 1 o'clock appears on the clock.
assert_eq!(zdt.to_string(), "2024-11-03T01:30:00-04:00[America/New_York]");
// But if we changed the offset and re-serialized, the only thing that
// changes is, indeed, the offset. This demonstrates that the offset is
// key to ensuring lossless serialization.
let zdt = zdt.with().offset(jiff::tz::offset(-5)).build()?;
assert_eq!(zdt.to_string(), "2024-11-03T01:30:00-05:00[America/New_York]");
A Zoned
can also be parsed from just a time zone aware date (but the
time zone annotation is still required). In this case, the time is set to
midnight:
use jiff::Zoned;
let zdt: Zoned = "2024-06-19[America/New_York]".parse()?;
assert_eq!(zdt.to_string(), "2024-06-19T00:00:00-04:00[America/New_York]");
// ... although it isn't always midnight, in the case of a time zone
// transition at midnight!
let zdt: Zoned = "2015-10-18[America/Sao_Paulo]".parse()?;
assert_eq!(zdt.to_string(), "2015-10-18T01:00:00-02:00[America/Sao_Paulo]");
For more information on the specific format supported, see the
fmt::temporal
module documentation.
§Leap seconds
Jiff does not support leap seconds. Jiff behaves as if they don’t exist.
The only exception is that if one parses a datetime with a second component
of 60
, then it is automatically constrained to 59
:
use jiff::{civil::date, Zoned};
let zdt: Zoned = "2016-12-31 23:59:60[Australia/Tasmania]".parse()?;
assert_eq!(zdt.datetime(), date(2016, 12, 31).at(23, 59, 59, 0));
§Comparisons
The Zoned
type provides both Eq
and Ord
trait implementations to
facilitate easy comparisons. When a zoned datetime zdt1
occurs before a
zoned datetime zdt2
, then zdt1 < zdt2
. For example:
use jiff::civil::date;
let zdt1 = date(2024, 3, 11).at(1, 25, 15, 0).intz("America/New_York")?;
let zdt2 = date(2025, 1, 31).at(0, 30, 0, 0).intz("America/New_York")?;
assert!(zdt1 < zdt2);
Note that Zoned
comparisons only consider the precise instant in time.
The civil datetime or even the time zone are completely ignored. So it’s
possible for a zoned datetime to be less than another even if it’s civil
datetime is bigger:
use jiff::civil::date;
let zdt1 = date(2024, 7, 4).at(12, 0, 0, 0).intz("America/New_York")?;
let zdt2 = date(2024, 7, 4).at(11, 0, 0, 0).intz("America/Los_Angeles")?;
assert!(zdt1 < zdt2);
// But if we only compare civil datetime, the result is flipped:
assert!(zdt1.datetime() > zdt2.datetime());
The same applies for equality as well. Two Zoned
values are equal, even
if they have different time zones, when the instant in time is identical:
use jiff::civil::date;
let zdt1 = date(2024, 7, 4).at(12, 0, 0, 0).intz("America/New_York")?;
let zdt2 = date(2024, 7, 4).at(9, 0, 0, 0).intz("America/Los_Angeles")?;
assert_eq!(zdt1, zdt2);
(Note that this is diifferent from
Temporal’s ZonedDateTime.equals
comparison, which will
take time zone into account for equality. This is because Eq
and Ord
trait implementations must be consistent in Rust. If you need Temporal’s
behavior, then use zdt1 == zdt2 && zdt1.time_zone() == zdt2.time_zone()
.)
§Arithmetic
This type provides routines for adding and subtracting spans of time, as
well as computing the span of time between two Zoned
values. These
operations take time zones into account.
For adding or subtracting spans of time, one can use any of the following routines:
Zoned::checked_add
orZoned::checked_sub
for checked arithmetic.Zoned::saturating_add
orZoned::saturating_sub
for saturating arithmetic.
Additionally, checked arithmetic is available via the Add
and Sub
trait implementations. When the result overflows, a panic occurs.
use jiff::{civil::date, ToSpan};
let start = date(2024, 2, 25).at(15, 45, 0, 0).intz("America/New_York")?;
// `Zoned` doesn't implement `Copy`, so we use `&start` instead of `start`.
let one_week_later = &start + 1.weeks();
assert_eq!(one_week_later.datetime(), date(2024, 3, 3).at(15, 45, 0, 0));
One can compute the span of time between two zoned datetimes using either
Zoned::until
or Zoned::since
. It’s also possible to subtract
two Zoned
values directly via a Sub
trait implementation:
use jiff::{civil::date, ToSpan};
let zdt1 = date(2024, 5, 3).at(23, 30, 0, 0).intz("America/New_York")?;
let zdt2 = date(2024, 2, 25).at(7, 0, 0, 0).intz("America/New_York")?;
assert_eq!(&zdt1 - &zdt2, 1647.hours().minutes(30));
The until
and since
APIs are polymorphic and allow re-balancing and
rounding the span returned. For example, the default largest unit is hours
(as exemplified above), but we can ask for bigger units:
use jiff::{civil::date, ToSpan, Unit};
let zdt1 = date(2024, 5, 3).at(23, 30, 0, 0).intz("America/New_York")?;
let zdt2 = date(2024, 2, 25).at(7, 0, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt1.since((Unit::Year, &zdt2))?,
2.months().days(7).hours(16).minutes(30),
);
Or even round the span returned:
use jiff::{civil::date, RoundMode, ToSpan, Unit, ZonedDifference};
let zdt1 = date(2024, 5, 3).at(23, 30, 0, 0).intz("America/New_York")?;
let zdt2 = date(2024, 2, 25).at(7, 0, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt1.since(
ZonedDifference::new(&zdt2)
.smallest(Unit::Day)
.largest(Unit::Year),
)?,
2.months().days(7),
);
// `ZonedDifference` uses truncation as a rounding mode by default,
// but you can set the rounding mode to break ties away from zero:
assert_eq!(
zdt1.since(
ZonedDifference::new(&zdt2)
.smallest(Unit::Day)
.largest(Unit::Year)
.mode(RoundMode::HalfExpand),
)?,
// Rounds up to 8 days.
2.months().days(8),
);
§Rounding
A Zoned
can be rounded based on a ZonedRound
configuration of
smallest units, rounding increment and rounding mode. Here’s an example
showing how to round to the nearest third hour:
use jiff::{civil::date, Unit, ZonedRound};
let zdt = date(2024, 6, 19)
.at(16, 27, 29, 999_999_999)
.intz("America/New_York")?;
assert_eq!(
zdt.round(ZonedRound::new().smallest(Unit::Hour).increment(3))?,
date(2024, 6, 19).at(15, 0, 0, 0).intz("America/New_York")?,
);
// Or alternatively, make use of the `From<(Unit, i64)> for ZonedRound`
// trait implementation:
assert_eq!(
zdt.round((Unit::Hour, 3))?,
date(2024, 6, 19).at(15, 0, 0, 0).intz("America/New_York")?,
);
See Zoned::round
for more details.
Implementations§
§impl Zoned
impl Zoned
pub fn now() -> Zoned
pub fn now() -> Zoned
Returns the current system time in this system’s time zone.
If the system’s time zone could not be found, then TimeZone::UTC
is used instead. When this happens, a WARN
level log message will
be emitted. (To see it, one will need to install a logger that is
compatible with the log
crate and enable Jiff’s logging
Cargo
feature.)
To create a Zoned
value for the current time in a particular
time zone other than the system default time zone, use
Timestamp::now().to_zoned(time_zone)
. In particular, using
Timestamp::now
avoids the work required to fetch the system time
zone if you did Zoned::now().with_time_zone(time_zone)
.
§Panics
This panics if the system clock is set to a time value outside of the
range -009999-01-01T00:00:00Z..=9999-12-31T11:59:59.999999999Z
. The
justification here is that it is reasonable to expect the system clock
to be set to a somewhat sane, if imprecise, value.
If you want to get the current Unix time fallibly, use
Zoned::try_from
with a std::time::SystemTime
as input.
This may also panic when SystemTime::now()
itself panics. The most
common context in which this happens is on the wasm32-unknown-unknown
target. If you’re using that target in the context of the web (for
example, via wasm-pack
), and you’re an application, then you should
enable Jiff’s js
feature. This will automatically instruct Jiff in
this very specific circumstance to execute JavaScript code to determine
the current time from the web browser.
§Example
use jiff::{Timestamp, Zoned};
assert!(Zoned::now().timestamp() > Timestamp::UNIX_EPOCH);
pub fn new(timestamp: Timestamp, time_zone: TimeZone) -> Zoned
pub fn new(timestamp: Timestamp, time_zone: TimeZone) -> Zoned
Creates a new Zoned
value from a specific instant in a particular
time zone. The time zone determines how to render the instant in time
into civil time. (Also known as “clock,” “wall,” “local” or “naive”
time.)
To create a new zoned datetime from another with a particular field
value, use the methods on ZonedWith
via Zoned::with
.
§Construction from civil time
A Zoned
value can also be created from a civil time via the following
methods:
DateTime::intz
does a Time Zone Database lookup given a time zone name string.DateTime::to_zoned
accepts aTimeZone
.Date::intz
does a Time Zone Database lookup given a time zone name string and attempts to use midnight as the clock time.Date::to_zoned
accepts aTimeZone
and attempts to use midnight as the clock time.
Whenever one is converting from civil time to a zoned
datetime, it is possible for the civil time to be ambiguous.
That is, it might be a clock reading that could refer to
multiple possible instants in time, or it might be a clock
reading that never exists. The above routines will use a
Disambiguation::Compatible
strategy to automatically resolve these corner cases.
If one wants to control how ambiguity is resolved (including
by returning an error), use TimeZone::to_ambiguous_zoned
and select the desired strategy via a method on
AmbiguousZoned
.
§Example: What was the civil time in Tasmania at the Unix epoch?
use jiff::{tz::TimeZone, Timestamp, Zoned};
let tz = TimeZone::get("Australia/Tasmania")?;
let zdt = Zoned::new(Timestamp::UNIX_EPOCH, tz);
assert_eq!(
zdt.to_string(),
"1970-01-01T11:00:00+11:00[Australia/Tasmania]",
);
§Example: What was the civil time in New York when World War 1 ended?
use jiff::civil::date;
let zdt1 = date(1918, 11, 11).at(11, 0, 0, 0).intz("Europe/Paris")?;
let zdt2 = zdt1.intz("America/New_York")?;
assert_eq!(
zdt2.to_string(),
"1918-11-11T06:00:00-05:00[America/New_York]",
);
pub fn with(&self) -> ZonedWith
pub fn with(&self) -> ZonedWith
Create a builder for constructing a new DateTime
from the fields of
this datetime.
See the methods on ZonedWith
for the different ways one can set
the fields of a new Zoned
.
Note that this doesn’t support changing the time zone. If you want a
Zoned
value of the same instant but in a different time zone, use
Zoned::intz
or Zoned::with_time_zone
. If you want a Zoned
value of the same civil datetime (assuming it isn’t ambiguous) but in
a different time zone, then use Zoned::datetime
followed by
DateTime::intz
or DateTime::to_zoned
.
§Example
The builder ensures one can chain together the individual components
of a zoned datetime without it failing at an intermediate step. For
example, if you had a date of 2024-10-31T00:00:00[America/New_York]
and wanted to change both the day and the month, and each setting was
validated independent of the other, you would need to be careful to set
the day first and then the month. In some cases, you would need to set
the month first and then the day!
But with the builder, you can set values in any order:
use jiff::civil::date;
let zdt1 = date(2024, 10, 31).at(0, 0, 0, 0).intz("America/New_York")?;
let zdt2 = zdt1.with().month(11).day(30).build()?;
assert_eq!(
zdt2,
date(2024, 11, 30).at(0, 0, 0, 0).intz("America/New_York")?,
);
let zdt1 = date(2024, 4, 30).at(0, 0, 0, 0).intz("America/New_York")?;
let zdt2 = zdt1.with().day(31).month(7).build()?;
assert_eq!(
zdt2,
date(2024, 7, 31).at(0, 0, 0, 0).intz("America/New_York")?,
);
pub fn with_time_zone(&self, time_zone: TimeZone) -> Zoned
pub fn with_time_zone(&self, time_zone: TimeZone) -> Zoned
Return a new zoned datetime with precisely the same instant in a different time zone.
The zoned datetime returned is guaranteed to have an equivalent
Timestamp
. However, its civil DateTime
may be different.
§Example: What was the civil time in New York when World War 1 ended?
use jiff::{civil::date, tz::TimeZone};
let from = TimeZone::get("Europe/Paris")?;
let to = TimeZone::get("America/New_York")?;
let zdt1 = date(1918, 11, 11).at(11, 0, 0, 0).to_zoned(from)?;
// Switch zdt1 to a different time zone, but keeping the same instant
// in time. The civil time changes, but not the instant!
let zdt2 = zdt1.with_time_zone(to);
assert_eq!(
zdt2.to_string(),
"1918-11-11T06:00:00-05:00[America/New_York]",
);
pub fn intz(&self, name: &str) -> Result<Zoned, Error> ⓘ
pub fn intz(&self, name: &str) -> Result<Zoned, Error> ⓘ
Return a new zoned datetime with precisely the same instant in a different time zone.
The zoned datetime returned is guaranteed to have an equivalent
Timestamp
. However, its civil DateTime
may be different.
The name given is resolved to a TimeZone
by using the default
TimeZoneDatabase
created by
tz::db
. Indeed, this is a convenience function for
DateTime::to_zoned
where the time zone database lookup is done
automatically.
§Errors
This returns an error when the given time zone name could not be found in the default time zone database.
§Example: What was the civil time in New York when World War 1 ended?
use jiff::civil::date;
let zdt1 = date(1918, 11, 11).at(11, 0, 0, 0).intz("Europe/Paris")?;
// Switch zdt1 to a different time zone, but keeping the same instant
// in time. The civil time changes, but not the instant!
let zdt2 = zdt1.intz("America/New_York")?;
assert_eq!(
zdt2.to_string(),
"1918-11-11T06:00:00-05:00[America/New_York]",
);
pub fn time_zone(&self) -> &TimeZone
pub fn time_zone(&self) -> &TimeZone
Returns the time zone attached to this Zoned
value.
A time zone is more than just an offset. A time zone is a series of rules for determining the civil time for a corresponding instant. Indeed, a zoned datetime uses its time zone to perform zone-aware arithmetic, rounding and serialization.
§Example
use jiff::Zoned;
let zdt: Zoned = "2024-07-03 14:31[america/new_york]".parse()?;
assert_eq!(zdt.time_zone().iana_name(), Some("America/New_York"));
pub fn year(&self) -> i16 ⓘ
pub fn year(&self) -> i16 ⓘ
Returns the year for this zoned datetime.
The value returned is guaranteed to be in the range -9999..=9999
.
§Example
use jiff::civil::date;
let zdt1 = date(2024, 3, 9).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt1.year(), 2024);
let zdt2 = date(-2024, 3, 9).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt2.year(), -2024);
let zdt3 = date(0, 3, 9).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt3.year(), 0);
pub fn era_year(&self) -> (i16, Era) ⓘ
pub fn era_year(&self) -> (i16, Era) ⓘ
Returns the year and its era.
This crate specifically allows years to be negative or 0
, where as
years written for the Gregorian calendar are always positive and
greater than 0
. In the Gregorian calendar, the era labels BCE
and
CE
are used to disambiguate between years less than or equal to 0
and years greater than 0
, respectively.
The crate is designed this way so that years in the latest era (that
is, CE
) are aligned with years in this crate.
The year returned is guaranteed to be in the range 1..=10000
.
§Example
use jiff::civil::{Era, date};
let zdt = date(2024, 10, 3).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.era_year(), (2024, Era::CE));
let zdt = date(1, 10, 3).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.era_year(), (1, Era::CE));
let zdt = date(0, 10, 3).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.era_year(), (1, Era::BCE));
let zdt = date(-1, 10, 3).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.era_year(), (2, Era::BCE));
let zdt = date(-10, 10, 3).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.era_year(), (11, Era::BCE));
let zdt = date(-9_999, 10, 3).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.era_year(), (10_000, Era::BCE));
pub fn month(&self) -> i8 ⓘ
pub fn month(&self) -> i8 ⓘ
Returns the month for this zoned datetime.
The value returned is guaranteed to be in the range 1..=12
.
§Example
use jiff::civil::date;
let zdt = date(2024, 3, 9).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.month(), 3);
pub fn day(&self) -> i8 ⓘ
pub fn day(&self) -> i8 ⓘ
Returns the day for this zoned datetime.
The value returned is guaranteed to be in the range 1..=31
.
§Example
use jiff::civil::date;
let zdt = date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day(), 29);
pub fn hour(&self) -> i8 ⓘ
pub fn hour(&self) -> i8 ⓘ
Returns the “hour” component of this zoned datetime.
The value returned is guaranteed to be in the range 0..=23
.
§Example
use jiff::civil::date;
let zdt = date(2000, 1, 2)
.at(3, 4, 5, 123_456_789)
.intz("America/New_York")?;
assert_eq!(zdt.hour(), 3);
pub fn minute(&self) -> i8 ⓘ
pub fn minute(&self) -> i8 ⓘ
Returns the “minute” component of this zoned datetime.
The value returned is guaranteed to be in the range 0..=59
.
§Example
use jiff::civil::date;
let zdt = date(2000, 1, 2)
.at(3, 4, 5, 123_456_789)
.intz("America/New_York")?;
assert_eq!(zdt.minute(), 4);
pub fn second(&self) -> i8 ⓘ
pub fn second(&self) -> i8 ⓘ
Returns the “second” component of this zoned datetime.
The value returned is guaranteed to be in the range 0..=59
.
§Example
use jiff::civil::date;
let zdt = date(2000, 1, 2)
.at(3, 4, 5, 123_456_789)
.intz("America/New_York")?;
assert_eq!(zdt.second(), 5);
pub fn millisecond(&self) -> i16 ⓘ
pub fn millisecond(&self) -> i16 ⓘ
Returns the “millisecond” component of this zoned datetime.
The value returned is guaranteed to be in the range 0..=999
.
§Example
use jiff::civil::date;
let zdt = date(2000, 1, 2)
.at(3, 4, 5, 123_456_789)
.intz("America/New_York")?;
assert_eq!(zdt.millisecond(), 123);
pub fn microsecond(&self) -> i16 ⓘ
pub fn microsecond(&self) -> i16 ⓘ
Returns the “microsecond” component of this zoned datetime.
The value returned is guaranteed to be in the range 0..=999
.
§Example
use jiff::civil::date;
let zdt = date(2000, 1, 2)
.at(3, 4, 5, 123_456_789)
.intz("America/New_York")?;
assert_eq!(zdt.microsecond(), 456);
pub fn nanosecond(&self) -> i16 ⓘ
pub fn nanosecond(&self) -> i16 ⓘ
Returns the “nanosecond” component of this zoned datetime.
The value returned is guaranteed to be in the range 0..=999
.
§Example
use jiff::civil::date;
let zdt = date(2000, 1, 2)
.at(3, 4, 5, 123_456_789)
.intz("America/New_York")?;
assert_eq!(zdt.nanosecond(), 789);
pub fn subsec_nanosecond(&self) -> i32 ⓘ
pub fn subsec_nanosecond(&self) -> i32 ⓘ
Returns the fractional nanosecond for this Zoned
value.
If you want to set this value on Zoned
, then use
ZonedWith::subsec_nanosecond
via Zoned::with
.
The value returned is guaranteed to be in the range 0..=999_999_999
.
§Example
This shows the relationship between constructing a Zoned
value
with routines like with().millisecond()
and accessing the entire
fractional part as a nanosecond:
use jiff::civil::date;
let zdt1 = date(2000, 1, 2)
.at(3, 4, 5, 123_456_789)
.intz("America/New_York")?;
assert_eq!(zdt1.subsec_nanosecond(), 123_456_789);
let zdt2 = zdt1.with().millisecond(333).build()?;
assert_eq!(zdt2.subsec_nanosecond(), 333_456_789);
§Example: nanoseconds from a timestamp
This shows how the fractional nanosecond part of a Zoned
value
manifests from a specific timestamp.
use jiff::{civil, Timestamp};
// 1,234 nanoseconds after the Unix epoch.
let zdt = Timestamp::new(0, 1_234)?.intz("UTC")?;
assert_eq!(zdt.subsec_nanosecond(), 1_234);
// 1,234 nanoseconds before the Unix epoch.
let zdt = Timestamp::new(0, -1_234)?.intz("UTC")?;
// The nanosecond is equal to `1_000_000_000 - 1_234`.
assert_eq!(zdt.subsec_nanosecond(), 999998766);
// Looking at the other components of the time value might help.
assert_eq!(zdt.hour(), 23);
assert_eq!(zdt.minute(), 59);
assert_eq!(zdt.second(), 59);
pub fn weekday(&self) -> Weekday
pub fn weekday(&self) -> Weekday
Returns the weekday corresponding to this zoned datetime.
§Example
use jiff::civil::{Weekday, date};
// The Unix epoch was on a Thursday.
let zdt = date(1970, 1, 1).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.weekday(), Weekday::Thursday);
// One can also get the weekday as an offset in a variety of schemes.
assert_eq!(zdt.weekday().to_monday_zero_offset(), 3);
assert_eq!(zdt.weekday().to_monday_one_offset(), 4);
assert_eq!(zdt.weekday().to_sunday_zero_offset(), 4);
assert_eq!(zdt.weekday().to_sunday_one_offset(), 5);
pub fn day_of_year(&self) -> i16 ⓘ
pub fn day_of_year(&self) -> i16 ⓘ
Returns the ordinal day of the year that this zoned datetime resides in.
For leap years, this always returns a value in the range 1..=366
.
Otherwise, the value is in the range 1..=365
.
§Example
use jiff::civil::date;
let zdt = date(2006, 8, 24).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day_of_year(), 236);
let zdt = date(2023, 12, 31).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day_of_year(), 365);
let zdt = date(2024, 12, 31).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day_of_year(), 366);
pub fn day_of_year_no_leap(&self) -> Option<i16> ⓘ
pub fn day_of_year_no_leap(&self) -> Option<i16> ⓘ
Returns the ordinal day of the year that this zoned datetime resides in, but ignores leap years.
That is, the range of possible values returned by this routine is
1..=365
, even if this date resides in a leap year. If this date is
February 29, then this routine returns None
.
The value 365
always corresponds to the last day in the year,
December 31, even for leap years.
§Example
use jiff::civil::date;
let zdt = date(2006, 8, 24).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day_of_year_no_leap(), Some(236));
let zdt = date(2023, 12, 31).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day_of_year_no_leap(), Some(365));
let zdt = date(2024, 12, 31).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day_of_year_no_leap(), Some(365));
let zdt = date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.day_of_year_no_leap(), None);
pub fn start_of_day(&self) -> Result<Zoned, Error> ⓘ
pub fn start_of_day(&self) -> Result<Zoned, Error> ⓘ
Returns the beginning of the day, corresponding to 00:00:00
civil
time, that this datetime resides in.
While in nearly all cases the time returned will be 00:00:00
, it is
possible for the time to be different from midnight if there is a time
zone transition at midnight.
§Example
use jiff::{civil::date, Zoned};
let zdt = date(2015, 10, 18).at(12, 0, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.start_of_day()?.to_string(),
"2015-10-18T00:00:00-04:00[America/New_York]",
);
§Example: start of day may not be midnight
In some time zones, gap transitions may begin at midnight. This implies
that 00:xx:yy
does not exist on a clock in that time zone for that
day.
use jiff::{civil::date, Zoned};
let zdt = date(2015, 10, 18).at(12, 0, 0, 0).intz("America/Sao_Paulo")?;
assert_eq!(
zdt.start_of_day()?.to_string(),
// not midnight!
"2015-10-18T01:00:00-02:00[America/Sao_Paulo]",
);
§Example: error because of overflow
In some cases, it’s possible for Zoned
value to be able to represent
an instant in time later in the day for a particular time zone, but not
earlier in the day. This can only occur near the minimum datetime value
supported by Jiff.
use jiff::{civil::date, tz::{TimeZone, Offset}, Zoned};
// While -9999-01-03T04:00:00+25:59:59 is representable as a Zoned
// value, the start of the corresponding day is not!
let tz = TimeZone::fixed(Offset::MAX);
let zdt = date(-9999, 1, 3).at(4, 0, 0, 0).to_zoned(tz.clone())?;
assert!(zdt.start_of_day().is_err());
// The next day works fine since -9999-01-04T00:00:00+25:59:59 is
// representable.
let zdt = date(-9999, 1, 4).at(15, 0, 0, 0).to_zoned(tz)?;
assert_eq!(
zdt.start_of_day()?.datetime(),
date(-9999, 1, 4).at(0, 0, 0, 0),
);
pub fn end_of_day(&self) -> Result<Zoned, Error> ⓘ
pub fn end_of_day(&self) -> Result<Zoned, Error> ⓘ
Returns the end of the day, corresponding to 23:59:59.999999999
civil
time, that this datetime resides in.
While in nearly all cases the time returned will be
23:59:59.999999999
, it is possible for the time to be different if
there is a time zone transition covering that time.
§Example
use jiff::civil::date;
let zdt = date(2024, 7, 3)
.at(7, 30, 10, 123_456_789)
.intz("America/New_York")?;
assert_eq!(
zdt.end_of_day()?,
date(2024, 7, 3)
.at(23, 59, 59, 999_999_999)
.intz("America/New_York")?,
);
§Example: error because of overflow
In some cases, it’s possible for Zoned
value to be able to represent
an instant in time earlier in the day for a particular time zone, but
not later in the day. This can only occur near the maximum datetime
value supported by Jiff.
use jiff::{civil::date, tz::{TimeZone, Offset}, Zoned};
// While 9999-12-30T01:30-04 is representable as a Zoned
// value, the start of the corresponding day is not!
let tz = TimeZone::get("America/New_York")?;
let zdt = date(9999, 12, 30).at(1, 30, 0, 0).to_zoned(tz.clone())?;
assert!(zdt.end_of_day().is_err());
// The previous day works fine since 9999-12-29T23:59:59.999999999-04
// is representable.
let zdt = date(9999, 12, 29).at(1, 30, 0, 0).to_zoned(tz.clone())?;
assert_eq!(
zdt.end_of_day()?,
date(9999, 12, 29)
.at(23, 59, 59, 999_999_999)
.intz("America/New_York")?,
);
pub fn first_of_month(&self) -> Result<Zoned, Error> ⓘ
pub fn first_of_month(&self) -> Result<Zoned, Error> ⓘ
Returns the first date of the month that this zoned datetime resides in.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::first_of_month
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Example
use jiff::civil::date;
let zdt = date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.first_of_month()?,
date(2024, 2, 1).at(7, 30, 0, 0).intz("America/New_York")?,
);
pub fn last_of_month(&self) -> Result<Zoned, Error> ⓘ
pub fn last_of_month(&self) -> Result<Zoned, Error> ⓘ
Returns the last date of the month that this zoned datetime resides in.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::last_of_month
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Example
use jiff::civil::date;
let zdt = date(2024, 2, 5).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.last_of_month()?,
date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?,
);
pub fn days_in_month(&self) -> i8 ⓘ
pub fn days_in_month(&self) -> i8 ⓘ
Returns the ordinal number of the last day in the month in which this zoned datetime resides.
This is phrased as “the ordinal number of the last day” instead of “the number of days” because some months may be missing days due to time zone transitions. However, this is extraordinarily rare.
This is guaranteed to always return one of the following values, depending on the year and the month: 28, 29, 30 or 31.
§Example
use jiff::civil::date;
let zdt = date(2024, 2, 10).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.days_in_month(), 29);
let zdt = date(2023, 2, 10).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.days_in_month(), 28);
let zdt = date(2024, 8, 15).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.days_in_month(), 31);
§Example: count of days in month
In Pacific/Apia
, December 2011 did not have a December 30. Instead,
the calendar skipped from December 29 right to December 31.
If you really do need the count of days in a month in a time zone aware fashion, then it’s possible to achieve through arithmetic:
use jiff::{civil::date, RoundMode, ToSpan, Unit, ZonedDifference};
let first_of_month = date(2011, 12, 1).intz("Pacific/Apia")?;
assert_eq!(first_of_month.days_in_month(), 31);
let one_month_later = first_of_month.checked_add(1.month())?;
let options = ZonedDifference::new(&one_month_later)
.largest(Unit::Hour)
.smallest(Unit::Hour)
.mode(RoundMode::HalfExpand);
let span = first_of_month.until(options)?;
let days = ((span.get_hours() as f64) / 24.0).round() as i64;
// Try the above in a different time zone, like America/New_York, and
// you'll get 31 here.
assert_eq!(days, 30);
pub fn first_of_year(&self) -> Result<Zoned, Error> ⓘ
pub fn first_of_year(&self) -> Result<Zoned, Error> ⓘ
Returns the first date of the year that this zoned datetime resides in.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::first_of_year
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Example
use jiff::civil::date;
let zdt = date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.first_of_year()?,
date(2024, 1, 1).at(7, 30, 0, 0).intz("America/New_York")?,
);
pub fn last_of_year(&self) -> Result<Zoned, Error> ⓘ
pub fn last_of_year(&self) -> Result<Zoned, Error> ⓘ
Returns the last date of the year that this zoned datetime resides in.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::last_of_year
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Example
use jiff::civil::date;
let zdt = date(2024, 2, 5).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.last_of_year()?,
date(2024, 12, 31).at(7, 30, 0, 0).intz("America/New_York")?,
);
pub fn days_in_year(&self) -> i16 ⓘ
pub fn days_in_year(&self) -> i16 ⓘ
Returns the ordinal number of the last day in the year in which this zoned datetime resides.
This is phrased as “the ordinal number of the last day” instead of “the number of days” because some years may be missing days due to time zone transitions. However, this is extraordinarily rare.
This is guaranteed to always return either 365
or 366
.
§Example
use jiff::civil::date;
let zdt = date(2024, 7, 10).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.days_in_year(), 366);
let zdt = date(2023, 7, 10).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.days_in_year(), 365);
pub fn in_leap_year(&self) -> bool
pub fn in_leap_year(&self) -> bool
Returns true if and only if the year in which this zoned datetime resides is a leap year.
§Example
use jiff::civil::date;
let zdt = date(2024, 1, 1).at(7, 30, 0, 0).intz("America/New_York")?;
assert!(zdt.in_leap_year());
let zdt = date(2023, 12, 31).at(7, 30, 0, 0).intz("America/New_York")?;
assert!(!zdt.in_leap_year());
pub fn tomorrow(&self) -> Result<Zoned, Error> ⓘ
pub fn tomorrow(&self) -> Result<Zoned, Error> ⓘ
Returns the zoned datetime with a date immediately following this one.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::tomorrow
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Errors
This returns an error when one day following this zoned datetime would
exceed the maximum Zoned
value.
§Example
use jiff::{civil::date, Timestamp};
let zdt = date(2024, 2, 28).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.tomorrow()?,
date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?,
);
// The max doesn't have a tomorrow.
assert!(Timestamp::MAX.intz("America/New_York")?.tomorrow().is_err());
§Example: ambiguous datetimes are automatically resolved
use jiff::{civil::date, Timestamp};
let zdt = date(2024, 3, 9).at(2, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.tomorrow()?,
date(2024, 3, 10).at(3, 30, 0, 0).intz("America/New_York")?,
);
pub fn yesterday(&self) -> Result<Zoned, Error> ⓘ
pub fn yesterday(&self) -> Result<Zoned, Error> ⓘ
Returns the zoned datetime with a date immediately preceding this one.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::yesterday
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Errors
This returns an error when one day preceding this zoned datetime would
be less than the minimum Zoned
value.
§Example
use jiff::{civil::date, Timestamp};
let zdt = date(2024, 3, 1).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.yesterday()?,
date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?,
);
// The min doesn't have a yesterday.
assert!(Timestamp::MIN.intz("America/New_York")?.yesterday().is_err());
§Example: ambiguous datetimes are automatically resolved
use jiff::{civil::date, Timestamp};
let zdt = date(2024, 11, 4).at(1, 30, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.yesterday()?.to_string(),
// Consistent with the "compatible" disambiguation strategy, the
// "first" 1 o'clock hour is selected. You can tell this because
// the offset is -04, which corresponds to DST time in New York.
// The second 1 o'clock hour would have offset -05.
"2024-11-03T01:30:00-04:00[America/New_York]",
);
pub fn nth_weekday_of_month(
&self,
nth: i8,
weekday: Weekday,
) -> Result<Zoned, Error> ⓘ
pub fn nth_weekday_of_month( &self, nth: i8, weekday: Weekday, ) -> Result<Zoned, Error> ⓘ
Returns the “nth” weekday from the beginning or end of the month in which this zoned datetime resides.
The nth
parameter can be positive or negative. A positive value
computes the “nth” weekday from the beginning of the month. A negative
value computes the “nth” weekday from the end of the month. So for
example, use -1
to “find the last weekday” in this date’s month.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::nth_weekday_of_month
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Errors
This returns an error when nth
is 0
, or if it is 5
or -5
and
there is no 5th weekday from the beginning or end of the month. This
could also return an error if the corresponding datetime could not be
represented as an instant for this Zoned
’s time zone. (This can only
happen close the boundaries of an Timestamp
.)
§Example
This shows how to get the nth weekday in a month, starting from the beginning of the month:
use jiff::civil::{Weekday, date};
let zdt = date(2017, 3, 1).at(7, 30, 0, 0).intz("America/New_York")?;
let second_friday = zdt.nth_weekday_of_month(2, Weekday::Friday)?;
assert_eq!(
second_friday,
date(2017, 3, 10).at(7, 30, 0, 0).intz("America/New_York")?,
);
This shows how to do the reverse of the above. That is, the nth last weekday in a month:
use jiff::civil::{Weekday, date};
let zdt = date(2024, 3, 1).at(7, 30, 0, 0).intz("America/New_York")?;
let last_thursday = zdt.nth_weekday_of_month(-1, Weekday::Thursday)?;
assert_eq!(
last_thursday,
date(2024, 3, 28).at(7, 30, 0, 0).intz("America/New_York")?,
);
let second_last_thursday = zdt.nth_weekday_of_month(
-2,
Weekday::Thursday,
)?;
assert_eq!(
second_last_thursday,
date(2024, 3, 21).at(7, 30, 0, 0).intz("America/New_York")?,
);
This routine can return an error if there isn’t an nth
weekday
for this month. For example, March 2024 only has 4 Mondays:
use jiff::civil::{Weekday, date};
let zdt = date(2024, 3, 25).at(7, 30, 0, 0).intz("America/New_York")?;
let fourth_monday = zdt.nth_weekday_of_month(4, Weekday::Monday)?;
assert_eq!(
fourth_monday,
date(2024, 3, 25).at(7, 30, 0, 0).intz("America/New_York")?,
);
// There is no 5th Monday.
assert!(zdt.nth_weekday_of_month(5, Weekday::Monday).is_err());
// Same goes for counting backwards.
assert!(zdt.nth_weekday_of_month(-5, Weekday::Monday).is_err());
pub fn nth_weekday(&self, nth: i32, weekday: Weekday) -> Result<Zoned, Error> ⓘ
pub fn nth_weekday(&self, nth: i32, weekday: Weekday) -> Result<Zoned, Error> ⓘ
Returns the “nth” weekday from this zoned datetime, not including itself.
The nth
parameter can be positive or negative. A positive value
computes the “nth” weekday starting at the day after this date and
going forwards in time. A negative value computes the “nth” weekday
starting at the day before this date and going backwards in time.
For example, if this zoned datetime’s weekday is a Sunday and the first
Sunday is asked for (that is, zdt.nth_weekday(1, Weekday::Sunday)
),
then the result is a week from this zoned datetime corresponding to the
following Sunday.
In most cases, the time in the zoned datetime returned remains
unchanged. In some cases, the time may change if the time
on the previous date was unambiguous (always true, since a
Zoned
is a precise instant in time) and the same clock time
on the returned zoned datetime is ambiguous. In this case, the
Disambiguation::Compatible
strategy will be used to turn it into a precise instant. If you want to
use a different disambiguation strategy, then use Zoned::datetime
to get the civil datetime, then use DateTime::nth_weekday
,
then use TimeZone::to_ambiguous_zoned
and apply your preferred
disambiguation strategy.
§Errors
This returns an error when nth
is 0
, or if it would otherwise
result in a date that overflows the minimum/maximum values of
Zoned
.
§Example
This example shows how to find the “nth” weekday going forwards in time:
use jiff::civil::{Weekday, date};
// Use a Sunday in March as our start date.
let zdt = date(2024, 3, 10).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.weekday(), Weekday::Sunday);
// The first next Monday is tomorrow!
let next_monday = zdt.nth_weekday(1, Weekday::Monday)?;
assert_eq!(
next_monday,
date(2024, 3, 11).at(7, 30, 0, 0).intz("America/New_York")?,
);
// But the next Sunday is a week away, because this doesn't
// include the current weekday.
let next_sunday = zdt.nth_weekday(1, Weekday::Sunday)?;
assert_eq!(
next_sunday,
date(2024, 3, 17).at(7, 30, 0, 0).intz("America/New_York")?,
);
// "not this Thursday, but next Thursday"
let next_next_thursday = zdt.nth_weekday(2, Weekday::Thursday)?;
assert_eq!(
next_next_thursday,
date(2024, 3, 21).at(7, 30, 0, 0).intz("America/New_York")?,
);
This example shows how to find the “nth” weekday going backwards in time:
use jiff::civil::{Weekday, date};
// Use a Sunday in March as our start date.
let zdt = date(2024, 3, 10).at(7, 30, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.weekday(), Weekday::Sunday);
// "last Saturday" was yesterday!
let last_saturday = zdt.nth_weekday(-1, Weekday::Saturday)?;
assert_eq!(
last_saturday,
date(2024, 3, 9).at(7, 30, 0, 0).intz("America/New_York")?,
);
// "last Sunday" was a week ago.
let last_sunday = zdt.nth_weekday(-1, Weekday::Sunday)?;
assert_eq!(
last_sunday,
date(2024, 3, 3).at(7, 30, 0, 0).intz("America/New_York")?,
);
// "not last Thursday, but the one before"
let prev_prev_thursday = zdt.nth_weekday(-2, Weekday::Thursday)?;
assert_eq!(
prev_prev_thursday,
date(2024, 2, 29).at(7, 30, 0, 0).intz("America/New_York")?,
);
This example shows that overflow results in an error in either direction:
use jiff::{civil::Weekday, Timestamp};
let zdt = Timestamp::MAX.intz("America/New_York")?;
assert_eq!(zdt.weekday(), Weekday::Thursday);
assert!(zdt.nth_weekday(1, Weekday::Saturday).is_err());
let zdt = Timestamp::MIN.intz("America/New_York")?;
assert_eq!(zdt.weekday(), Weekday::Monday);
assert!(zdt.nth_weekday(-1, Weekday::Sunday).is_err());
§Example: getting the start of the week
Given a date, one can use nth_weekday
to determine the start of the
week in which the date resides in. This might vary based on whether
the weeks start on Sunday or Monday. This example shows how to handle
both.
use jiff::civil::{Weekday, date};
let zdt = date(2024, 3, 15).at(7, 30, 0, 0).intz("America/New_York")?;
// For weeks starting with Sunday.
let start_of_week = zdt.tomorrow()?.nth_weekday(-1, Weekday::Sunday)?;
assert_eq!(
start_of_week,
date(2024, 3, 10).at(7, 30, 0, 0).intz("America/New_York")?,
);
// For weeks starting with Monday.
let start_of_week = zdt.tomorrow()?.nth_weekday(-1, Weekday::Monday)?;
assert_eq!(
start_of_week,
date(2024, 3, 11).at(7, 30, 0, 0).intz("America/New_York")?,
);
In the above example, we first get the date after the current one
because nth_weekday
does not consider itself when counting. This
works as expected even at the boundaries of a week:
use jiff::civil::{Time, Weekday, date};
// The start of the week.
let zdt = date(2024, 3, 10).at(0, 0, 0, 0).intz("America/New_York")?;
let start_of_week = zdt.tomorrow()?.nth_weekday(-1, Weekday::Sunday)?;
assert_eq!(
start_of_week,
date(2024, 3, 10).at(0, 0, 0, 0).intz("America/New_York")?,
);
// The end of the week.
let zdt = date(2024, 3, 16)
.at(23, 59, 59, 999_999_999)
.intz("America/New_York")?;
let start_of_week = zdt
.tomorrow()?
.nth_weekday(-1, Weekday::Sunday)?
.with().time(Time::midnight()).build()?;
assert_eq!(
start_of_week,
date(2024, 3, 10).at(0, 0, 0, 0).intz("America/New_York")?,
);
pub fn timestamp(&self) -> Timestamp
pub fn timestamp(&self) -> Timestamp
Returns the precise instant in time referred to by this zoned datetime.
§Example
use jiff::civil::date;
let zdt = date(2024, 3, 14).at(18, 45, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.timestamp().as_second(), 1_710_456_300);
pub fn datetime(&self) -> DateTime
pub fn datetime(&self) -> DateTime
Returns the civil datetime component of this zoned datetime.
§Example
use jiff::civil::date;
let zdt = date(2024, 3, 14).at(18, 45, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.datetime(), date(2024, 3, 14).at(18, 45, 0, 0));
pub fn date(&self) -> Date
pub fn date(&self) -> Date
Returns the civil date component of this zoned datetime.
§Example
use jiff::civil::date;
let zdt = date(2024, 3, 14).at(18, 45, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.date(), date(2024, 3, 14));
pub fn time(&self) -> Time
pub fn time(&self) -> Time
Returns the civil time component of this zoned datetime.
§Example
use jiff::civil::{date, time};
let zdt = date(2024, 3, 14).at(18, 45, 0, 0).intz("America/New_York")?;
assert_eq!(zdt.time(), time(18, 45, 0, 0));
pub fn offset(&self) -> Offset
pub fn offset(&self) -> Offset
Returns the time zone offset of this zoned datetime.
§Example
use jiff::civil::date;
let zdt = date(2024, 2, 14).at(18, 45, 0, 0).intz("America/New_York")?;
// -05 because New York is in "standard" time at this point.
assert_eq!(zdt.offset(), jiff::tz::offset(-5));
let zdt = date(2024, 7, 14).at(18, 45, 0, 0).intz("America/New_York")?;
// But we get -04 once "summer" or "daylight saving time" starts.
assert_eq!(zdt.offset(), jiff::tz::offset(-4));
pub fn checked_add<A>(&self, duration: A) -> Result<Zoned, Error> ⓘwhere
A: Into<ZonedArithmetic>,
pub fn checked_add<A>(&self, duration: A) -> Result<Zoned, Error> ⓘwhere
A: Into<ZonedArithmetic>,
Add the given span of time to this zoned datetime. If the sum would overflow the minimum or maximum zoned datetime values, then an error is returned.
This operation accepts three different duration types: Span
,
SignedDuration
or std::time::Duration
. This is achieved via
From
trait implementations for the ZonedArithmetic
type.
§Properties
This routine is not reversible because some additions may
be ambiguous. For example, adding 1 month
to the zoned
datetime 2024-03-31T00:00:00[America/New_York]
will produce
2024-04-30T00:00:00[America/New_York]
since April has
only 30 days in a month. Moreover, subtracting 1 month
from 2024-04-30T00:00:00[America/New_York]
will produce
2024-03-30T00:00:00[America/New_York]
, which is not the date we
started with.
A similar argument applies for days, since with zoned datetimes, different days can be different lengths.
If spans of time are limited to units of hours (or less), then this
routine is reversible. This also implies that all operations with a
SignedDuration
or a std::time::Duration
are reversible.
§Errors
If the span added to this zoned datetime would result in a zoned
datetime that exceeds the range of a Zoned
, then this will return an
error.
§Example
This shows a few examples of adding spans of time to various zoned
datetimes. We make use of the ToSpan
trait for
convenient creation of spans.
use jiff::{civil::date, ToSpan};
let zdt = date(1995, 12, 7)
.at(3, 24, 30, 3_500)
.intz("America/New_York")?;
let got = zdt.checked_add(20.years().months(4).nanoseconds(500))?;
assert_eq!(
got,
date(2016, 4, 7).at(3, 24, 30, 4_000).intz("America/New_York")?,
);
let zdt = date(2019, 1, 31).at(15, 30, 0, 0).intz("America/New_York")?;
let got = zdt.checked_add(1.months())?;
assert_eq!(
got,
date(2019, 2, 28).at(15, 30, 0, 0).intz("America/New_York")?,
);
§Example: available via addition operator
This routine can be used via the +
operator. Note though that if it
fails, it will result in a panic. Note that we use &zdt + ...
instead
of zdt + ...
since Add
is implemented for &Zoned
and not Zoned
.
This is because Zoned
is not Copy
.
use jiff::{civil::date, ToSpan};
let zdt = date(1995, 12, 7)
.at(3, 24, 30, 3_500)
.intz("America/New_York")?;
let got = &zdt + 20.years().months(4).nanoseconds(500);
assert_eq!(
got,
date(2016, 4, 7).at(3, 24, 30, 4_000).intz("America/New_York")?,
);
§Example: zone aware arithmetic
This example demonstrates the difference between “add 1 day” and “add 24 hours.” In the former case, 1 day might not correspond to 24 hours if there is a time zone transition in the intervening period. However, adding 24 hours always means adding exactly 24 hours.
use jiff::{civil::date, ToSpan};
let zdt = date(2024, 3, 10).at(0, 0, 0, 0).intz("America/New_York")?;
let one_day_later = zdt.checked_add(1.day())?;
assert_eq!(
one_day_later.to_string(),
"2024-03-11T00:00:00-04:00[America/New_York]",
);
let twenty_four_hours_later = zdt.checked_add(24.hours())?;
assert_eq!(
twenty_four_hours_later.to_string(),
"2024-03-11T01:00:00-04:00[America/New_York]",
);
§Example: automatic disambiguation
This example demonstrates what happens when adding a span
of time results in an ambiguous zoned datetime. Zone aware
arithmetic uses automatic disambiguation corresponding to the
Disambiguation::Compatible
strategy for resolving an ambiguous datetime to a precise instant.
For example, in the case below, there is a gap in the clocks for 1
hour starting at 2024-03-10 02:00:00
in America/New_York
. The
“compatible” strategy chooses the later time in a gap:.
use jiff::{civil::date, ToSpan};
let zdt = date(2024, 3, 9).at(2, 30, 0, 0).intz("America/New_York")?;
let one_day_later = zdt.checked_add(1.day())?;
assert_eq!(
one_day_later.to_string(),
"2024-03-10T03:30:00-04:00[America/New_York]",
);
And this example demonstrates the “compatible” strategy when arithmetic
results in an ambiguous datetime in a fold. In this case, we make use
of the fact that the 1 o’clock hour was repeated on 2024-11-03
.
use jiff::{civil::date, ToSpan};
let zdt = date(2024, 11, 2).at(1, 30, 0, 0).intz("America/New_York")?;
let one_day_later = zdt.checked_add(1.day())?;
assert_eq!(
one_day_later.to_string(),
// This corresponds to the first iteration of the 1 o'clock hour,
// i.e., when DST is still in effect. It's the earlier time.
"2024-11-03T01:30:00-04:00[America/New_York]",
);
§Example: negative spans are supported
use jiff::{civil::date, ToSpan};
let zdt = date(2024, 3, 31)
.at(19, 5, 59, 999_999_999)
.intz("America/New_York")?;
assert_eq!(
zdt.checked_add(-1.months())?,
date(2024, 2, 29).
at(19, 5, 59, 999_999_999)
.intz("America/New_York")?,
);
§Example: error on overflow
use jiff::{civil::date, ToSpan};
let zdt = date(2024, 3, 31).at(13, 13, 13, 13).intz("America/New_York")?;
assert!(zdt.checked_add(9000.years()).is_err());
assert!(zdt.checked_add(-19000.years()).is_err());
§Example: adding absolute durations
This shows how to add signed and unsigned absolute durations to a
Zoned
.
use std::time::Duration;
use jiff::{civil::date, SignedDuration};
let zdt = date(2024, 2, 29).at(0, 0, 0, 0).intz("US/Eastern")?;
let dur = SignedDuration::from_hours(25);
assert_eq!(
zdt.checked_add(dur)?,
date(2024, 3, 1).at(1, 0, 0, 0).intz("US/Eastern")?,
);
assert_eq!(
zdt.checked_add(-dur)?,
date(2024, 2, 27).at(23, 0, 0, 0).intz("US/Eastern")?,
);
let dur = Duration::from_secs(25 * 60 * 60);
assert_eq!(
zdt.checked_add(dur)?,
date(2024, 3, 1).at(1, 0, 0, 0).intz("US/Eastern")?,
);
// One cannot negate an unsigned duration,
// but you can subtract it!
assert_eq!(
zdt.checked_sub(dur)?,
date(2024, 2, 27).at(23, 0, 0, 0).intz("US/Eastern")?,
);
pub fn checked_sub<A>(&self, duration: A) -> Result<Zoned, Error> ⓘwhere
A: Into<ZonedArithmetic>,
pub fn checked_sub<A>(&self, duration: A) -> Result<Zoned, Error> ⓘwhere
A: Into<ZonedArithmetic>,
This routine is identical to Zoned::checked_add
with the
duration negated.
§Errors
This has the same error conditions as Zoned::checked_add
.
§Example
This routine can be used via the -
operator. Note though that if it
fails, it will result in a panic. Note that we use &zdt - ...
instead
of zdt - ...
since Sub
is implemented for &Zoned
and not Zoned
.
This is because Zoned
is not Copy
.
use std::time::Duration;
use jiff::{civil::date, SignedDuration, ToSpan};
let zdt = date(1995, 12, 7)
.at(3, 24, 30, 3_500)
.intz("America/New_York")?;
let got = &zdt - 20.years().months(4).nanoseconds(500);
assert_eq!(
got,
date(1975, 8, 7).at(3, 24, 30, 3_000).intz("America/New_York")?,
);
let dur = SignedDuration::new(24 * 60 * 60, 500);
assert_eq!(
&zdt - dur,
date(1995, 12, 6).at(3, 24, 30, 3_000).intz("America/New_York")?,
);
let dur = Duration::new(24 * 60 * 60, 500);
assert_eq!(
&zdt - dur,
date(1995, 12, 6).at(3, 24, 30, 3_000).intz("America/New_York")?,
);
pub fn saturating_add<A>(&self, duration: A) -> Zonedwhere
A: Into<ZonedArithmetic>,
pub fn saturating_add<A>(&self, duration: A) -> Zonedwhere
A: Into<ZonedArithmetic>,
This routine is identical to Zoned::checked_add
, except the
result saturates on overflow. That is, instead of overflow, either
Timestamp::MIN
or Timestamp::MAX
(in this Zoned
value’s time
zone) is returned.
§Properties
The properties of this routine are identical to Zoned::checked_add
,
except that if saturation occurs, then the result is not reversible.
§Example
use jiff::{civil::date, SignedDuration, Timestamp, ToSpan};
let zdt = date(2024, 3, 31).at(13, 13, 13, 13).intz("America/New_York")?;
assert_eq!(Timestamp::MAX, zdt.saturating_add(9000.years()).timestamp());
assert_eq!(Timestamp::MIN, zdt.saturating_add(-19000.years()).timestamp());
assert_eq!(Timestamp::MAX, zdt.saturating_add(SignedDuration::MAX).timestamp());
assert_eq!(Timestamp::MIN, zdt.saturating_add(SignedDuration::MIN).timestamp());
assert_eq!(Timestamp::MAX, zdt.saturating_add(std::time::Duration::MAX).timestamp());
pub fn saturating_sub<A>(&self, duration: A) -> Zonedwhere
A: Into<ZonedArithmetic>,
pub fn saturating_sub<A>(&self, duration: A) -> Zonedwhere
A: Into<ZonedArithmetic>,
This routine is identical to Zoned::saturating_add
with the span
parameter negated.
§Example
use jiff::{civil::date, SignedDuration, Timestamp, ToSpan};
let zdt = date(2024, 3, 31).at(13, 13, 13, 13).intz("America/New_York")?;
assert_eq!(Timestamp::MIN, zdt.saturating_sub(19000.years()).timestamp());
assert_eq!(Timestamp::MAX, zdt.saturating_sub(-9000.years()).timestamp());
assert_eq!(Timestamp::MIN, zdt.saturating_sub(SignedDuration::MAX).timestamp());
assert_eq!(Timestamp::MAX, zdt.saturating_sub(SignedDuration::MIN).timestamp());
assert_eq!(Timestamp::MIN, zdt.saturating_sub(std::time::Duration::MAX).timestamp());
pub fn until<'a, A>(&self, other: A) -> Result<Span, Error> ⓘwhere
A: Into<ZonedDifference<'a>>,
pub fn until<'a, A>(&self, other: A) -> Result<Span, Error> ⓘwhere
A: Into<ZonedDifference<'a>>,
Returns a span representing the elapsed time from this zoned datetime
until the given other
zoned datetime.
When other
occurs before this datetime, then the span returned will
be negative.
Depending on the input provided, the span returned is rounded. It may also be balanced up to bigger units than the default. By default, the span returned is balanced such that the biggest possible unit is hours.
This operation is configured by providing a ZonedDifference
value. Since this routine accepts anything that implements
Into<ZonedDifference>
, once can pass a &Zoned
directly.
One can also pass a (Unit, &Zoned)
, where Unit
is treated as
ZonedDifference::largest
.
§Properties
It is guaranteed that if the returned span is subtracted from other
,
and if no rounding is requested, and if the largest unit requested
is at most Unit::Hour
, then the original zoned datetime will be
returned.
This routine is equivalent to self.since(other).map(|span| -span)
if no rounding options are set. If rounding options are set, then
it’s equivalent to
self.since(other_without_rounding_options).map(|span| -span)
,
followed by a call to Span::round
with the appropriate rounding
options set. This is because the negation of a span can result in
different rounding results depending on the rounding mode.
§Errors
An error can occur in some cases when the requested configuration
would result in a span that is beyond allowable limits. For example,
the nanosecond component of a span cannot represent the span of
time between the minimum and maximum zoned datetime supported by Jiff.
Therefore, if one requests a span with its largest unit set to
Unit::Nanosecond
, then it’s possible for this routine to fail.
An error can also occur if ZonedDifference
is misconfigured. For
example, if the smallest unit provided is bigger than the largest unit.
An error can also occur if units greater than Unit::Hour
are
requested and if the time zones in the provided zoned datetimes
are distinct. (See TimeZone
’s section on equality for details on
how equality is determined.) This error occurs because the length of
a day may vary depending on the time zone. To work around this
restriction, convert one or both of the zoned datetimes into the same
time zone.
It is guaranteed that if one provides a datetime with the default
ZonedDifference
configuration, then this routine will never
fail.
§Example
use jiff::{civil::date, ToSpan};
let earlier = date(2006, 8, 24).at(22, 30, 0, 0).intz("America/New_York")?;
let later = date(2019, 1, 31).at(21, 0, 0, 0).intz("America/New_York")?;
assert_eq!(earlier.until(&later)?, 109_031.hours().minutes(30));
// Flipping the dates is fine, but you'll get a negative span.
assert_eq!(later.until(&earlier)?, -109_031.hours().minutes(30));
§Example: using bigger units
This example shows how to expand the span returned to bigger units.
This makes use of a From<(Unit, &Zoned)> for ZonedDifference
trait implementation.
use jiff::{civil::date, Unit, ToSpan};
let zdt1 = date(1995, 12, 07).at(3, 24, 30, 3500).intz("America/New_York")?;
let zdt2 = date(2019, 01, 31).at(15, 30, 0, 0).intz("America/New_York")?;
// The default limits durations to using "hours" as the biggest unit.
let span = zdt1.until(&zdt2)?;
assert_eq!(span.to_string(), "PT202956H5M29.9999965S");
// But we can ask for units all the way up to years.
let span = zdt1.until((Unit::Year, &zdt2))?;
assert_eq!(span.to_string(), "P23Y1M24DT12H5M29.9999965S");
§Example: rounding the result
This shows how one might find the difference between two zoned datetimes and have the result rounded such that sub-seconds are removed.
In this case, we need to hand-construct a ZonedDifference
in order to gain full configurability.
use jiff::{civil::date, Unit, ToSpan, ZonedDifference};
let zdt1 = date(1995, 12, 07).at(3, 24, 30, 3500).intz("America/New_York")?;
let zdt2 = date(2019, 01, 31).at(15, 30, 0, 0).intz("America/New_York")?;
let span = zdt1.until(
ZonedDifference::from(&zdt2).smallest(Unit::Second),
)?;
assert_eq!(span, 202_956.hours().minutes(5).seconds(29));
// We can combine smallest and largest units too!
let span = zdt1.until(
ZonedDifference::from(&zdt2)
.smallest(Unit::Second)
.largest(Unit::Year),
)?;
assert_eq!(span, 23.years().months(1).days(24).hours(12).minutes(5).seconds(29));
§Example: units biggers than days inhibit reversibility
If you ask for units bigger than hours, then adding the span returned
to the other
zoned datetime is not guaranteed to result in the
original zoned datetime. For example:
use jiff::{civil::date, Unit, ToSpan};
let zdt1 = date(2024, 3, 2).at(0, 0, 0, 0).intz("America/New_York")?;
let zdt2 = date(2024, 5, 1).at(0, 0, 0, 0).intz("America/New_York")?;
let span = zdt1.until((Unit::Month, &zdt2))?;
assert_eq!(span, 1.month().days(29));
let maybe_original = zdt2.checked_sub(span)?;
// Not the same as the original datetime!
assert_eq!(
maybe_original,
date(2024, 3, 3).at(0, 0, 0, 0).intz("America/New_York")?,
);
// But in the default configuration, hours are always the biggest unit
// and reversibility is guaranteed.
let span = zdt1.until(&zdt2)?;
assert_eq!(span, 1439.hours());
let is_original = zdt2.checked_sub(span)?;
assert_eq!(is_original, zdt1);
This occurs because spans are added as if by adding the biggest units
first, and then the smaller units. Because months vary in length,
their meaning can change depending on how the span is added. In this
case, adding one month to 2024-03-02
corresponds to 31 days, but
subtracting one month from 2024-05-01
corresponds to 30 days.
pub fn since<'a, A>(&self, other: A) -> Result<Span, Error> ⓘwhere
A: Into<ZonedDifference<'a>>,
pub fn since<'a, A>(&self, other: A) -> Result<Span, Error> ⓘwhere
A: Into<ZonedDifference<'a>>,
This routine is identical to Zoned::until
, but the order of the
parameters is flipped.
§Errors
This has the same error conditions as Zoned::until
.
§Example
This routine can be used via the -
operator. Since the default
configuration is used and because a Span
can represent the difference
between any two possible zoned datetimes, it will never panic. Note
that we use &zdt1 - &zdt2
instead of zdt1 - zdt2
since Sub
is
implemented for &Zoned
and not Zoned
. This is because Zoned
is
not Copy
.
use jiff::{civil::date, ToSpan};
let earlier = date(2006, 8, 24).at(22, 30, 0, 0).intz("America/New_York")?;
let later = date(2019, 1, 31).at(21, 0, 0, 0).intz("America/New_York")?;
assert_eq!(&later - &earlier, 109_031.hours().minutes(30));
pub fn duration_until(&self, other: &Zoned) -> SignedDuration
pub fn duration_until(&self, other: &Zoned) -> SignedDuration
Returns an absolute duration representing the elapsed time from this
zoned datetime until the given other
zoned datetime.
When other
occurs before this zoned datetime, then the duration
returned will be negative.
Unlike Zoned::until
, this always returns a duration
corresponding to a 96-bit integer of nanoseconds between two
zoned datetimes.
§Fallibility
This routine never panics or returns an error. Since there are no
configuration options that can be incorrectly provided, no error is
possible when calling this routine. In contrast, Zoned::until
can return an error in some cases due to misconfiguration. But like
this routine, Zoned::until
never panics or returns an error in
its default configuration.
§When should I use this versus Zoned::until
?
See the type documentation for SignedDuration
for the section on
when one should use Span
and when one should use SignedDuration
.
In short, use Span
(and therefore Timestamp::until
) unless you have
a specific reason to do otherwise.
§Example
use jiff::{civil::date, SignedDuration};
let earlier = date(2006, 8, 24).at(22, 30, 0, 0).intz("US/Eastern")?;
let later = date(2019, 1, 31).at(21, 0, 0, 0).intz("US/Eastern")?;
assert_eq!(
earlier.duration_until(&later),
SignedDuration::from_hours(109_031) + SignedDuration::from_mins(30),
);
// Flipping the dates is fine, but you'll get a negative span.
assert_eq!(
later.duration_until(&earlier),
-SignedDuration::from_hours(109_031) + -SignedDuration::from_mins(30),
);
§Example: difference with Zoned::until
The main difference between this routine and Zoned::until
is that
the latter can return units other than a 96-bit integer of nanoseconds.
While a 96-bit integer of nanoseconds can be converted into other units
like hours, this can only be done for uniform units. (Uniform units are
units for which each individual unit always corresponds to the same
elapsed time regardless of the datetime it is relative to.) This can’t
be done for units like years, months or days.
use jiff::{civil::date, SignedDuration, Span, SpanRound, ToSpan, Unit};
let zdt1 = date(2024, 3, 10).at(0, 0, 0, 0).intz("US/Eastern")?;
let zdt2 = date(2024, 3, 11).at(0, 0, 0, 0).intz("US/Eastern")?;
let span = zdt1.until((Unit::Day, &zdt2))?;
assert_eq!(span, 1.day());
let duration = zdt1.duration_until(&zdt2);
// This day was only 23 hours long!
assert_eq!(duration, SignedDuration::from_hours(23));
// There's no way to extract years, months or days from the signed
// duration like one might extract hours (because every hour
// is the same length). Instead, you actually have to convert
// it to a span and then balance it by providing a relative date!
let options = SpanRound::new().largest(Unit::Day).relative(&zdt1);
let span = Span::try_from(duration)?.round(options)?;
assert_eq!(span, 1.day());
§Example: getting an unsigned duration
If you’re looking to find the duration between two zoned datetimes as
a std::time::Duration
, you’ll need to use this method to get a
SignedDuration
and then convert it to a std::time::Duration
:
use std::time::Duration;
use jiff::civil::date;
let zdt1 = date(2024, 7, 1).at(0, 0, 0, 0).intz("US/Eastern")?;
let zdt2 = date(2024, 8, 1).at(0, 0, 0, 0).intz("US/Eastern")?;
let duration = Duration::try_from(zdt1.duration_until(&zdt2))?;
assert_eq!(duration, Duration::from_secs(31 * 24 * 60 * 60));
// Note that unsigned durations cannot represent all
// possible differences! If the duration would be negative,
// then the conversion fails:
assert!(Duration::try_from(zdt2.duration_until(&zdt1)).is_err());
pub fn duration_since(&self, other: &Zoned) -> SignedDuration
pub fn duration_since(&self, other: &Zoned) -> SignedDuration
This routine is identical to Zoned::duration_until
, but the
order of the parameters is flipped.
§Example
use jiff::{civil::date, SignedDuration};
let earlier = date(2006, 8, 24).at(22, 30, 0, 0).intz("US/Eastern")?;
let later = date(2019, 1, 31).at(21, 0, 0, 0).intz("US/Eastern")?;
assert_eq!(
later.duration_since(&earlier),
SignedDuration::from_hours(109_031) + SignedDuration::from_mins(30),
);
pub fn round<R>(&self, options: R) -> Result<Zoned, Error> ⓘwhere
R: Into<ZonedRound>,
pub fn round<R>(&self, options: R) -> Result<Zoned, Error> ⓘwhere
R: Into<ZonedRound>,
Rounds this zoned datetime according to the ZonedRound
configuration given.
The principal option is ZonedRound::smallest
, which allows one to
configure the smallest units in the returned zoned datetime. Rounding
is what determines whether that unit should keep its current value
or whether it should be incremented. Moreover, the amount it should
be incremented can be configured via ZonedRound::increment
.
Finally, the rounding strategy itself can be configured via
ZonedRound::mode
.
Note that this routine is generic and accepts anything that
implements Into<ZonedRound>
. Some notable implementations are:
From<Unit> for ZonedRound
, which will automatically create aZonedRound::new().smallest(unit)
from the unit provided.From<(Unit, i64)> for ZonedRound
, which will automatically create aZonedRound::new().smallest(unit).increment(number)
from the unit and increment provided.
§Errors
This returns an error if the smallest unit configured on the given
ZonedRound
is bigger than days. An error is also returned if
the rounding increment is greater than 1 when the units are days.
(Currently, rounding to the nearest week, month or year is not
supported.)
When the smallest unit is less than days, the rounding increment must
divide evenly into the next highest unit after the smallest unit
configured (and must not be equivalent to it). For example, if the
smallest unit is Unit::Nanosecond
, then some of the valid values
for the rounding increment are 1
, 2
, 4
, 5
, 100
and 500
.
Namely, any integer that divides evenly into 1,000
nanoseconds since
there are 1,000
nanoseconds in the next highest unit (microseconds).
This can also return an error in some cases where rounding would require arithmetic that exceeds the maximum zoned datetime value.
§Example
This is a basic example that demonstrates rounding a zoned datetime
to the nearest day. This also demonstrates calling this method with
the smallest unit directly, instead of constructing a ZonedRound
manually.
use jiff::{civil::date, Unit};
// rounds up
let zdt = date(2024, 6, 19).at(15, 0, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.round(Unit::Day)?,
date(2024, 6, 20).at(0, 0, 0, 0).intz("America/New_York")?,
);
// rounds down
let zdt = date(2024, 6, 19).at(10, 0, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.round(Unit::Day)?,
date(2024, 6, 19).at(0, 0, 0, 0).intz("America/New_York")?,
);
§Example: changing the rounding mode
The default rounding mode is RoundMode::HalfExpand
, which
breaks ties by rounding away from zero. But other modes like
RoundMode::Trunc
can be used too:
use jiff::{civil::date, RoundMode, Unit, Zoned, ZonedRound};
let zdt = date(2024, 6, 19).at(15, 0, 0, 0).intz("America/New_York")?;
assert_eq!(
zdt.round(Unit::Day)?,
date(2024, 6, 20).at(0, 0, 0, 0).intz("America/New_York")?,
);
// The default will round up to the next day for any time past noon (as
// shown above), but using truncation rounding will always round down.
assert_eq!(
zdt.round(
ZonedRound::new().smallest(Unit::Day).mode(RoundMode::Trunc),
)?,
date(2024, 6, 19).at(0, 0, 0, 0).intz("America/New_York")?,
);
§Example: rounding to the nearest 5 minute increment
use jiff::{civil::date, Unit};
// rounds down
let zdt = date(2024, 6, 19)
.at(15, 27, 29, 999_999_999)
.intz("America/New_York")?;
assert_eq!(
zdt.round((Unit::Minute, 5))?,
date(2024, 6, 19).at(15, 25, 0, 0).intz("America/New_York")?,
);
// rounds up
let zdt = date(2024, 6, 19)
.at(15, 27, 30, 0)
.intz("America/New_York")?;
assert_eq!(
zdt.round((Unit::Minute, 5))?,
date(2024, 6, 19).at(15, 30, 0, 0).intz("America/New_York")?,
);
§Example: behavior near time zone transitions
When rounding this zoned datetime near time zone transitions (such as DST), the “sensible” thing is done by default. Namely, rounding will jump to the closest instant, even if the change in civil clock time is large. For example, when rounding up into a gap, the civil clock time will jump over the gap, but the corresponding change in the instant is as one might expect:
use jiff::{Unit, Zoned};
let zdt1: Zoned = "2024-03-10T01:59:00-05[America/New_York]".parse()?;
let zdt2 = zdt1.round(Unit::Hour)?;
assert_eq!(
zdt2.to_string(),
"2024-03-10T03:00:00-04:00[America/New_York]",
);
Similarly, when rounding inside a fold, rounding will respect whether
it’s the first or second time the clock has repeated the hour. For the
DST transition in New York on 2024-11-03
from offset -04
to -05
,
here is an example that rounds the first 1 o’clock hour:
use jiff::{Unit, Zoned};
let zdt1: Zoned = "2024-11-03T01:59:01-04[America/New_York]".parse()?;
let zdt2 = zdt1.round(Unit::Minute)?;
assert_eq!(
zdt2.to_string(),
"2024-11-03T01:59:00-04:00[America/New_York]",
);
And now the second 1 o’clock hour. Notice how the rounded result stays in the second 1 o’clock hour.
use jiff::{Unit, Zoned};
let zdt1: Zoned = "2024-11-03T01:59:01-05[America/New_York]".parse()?;
let zdt2 = zdt1.round(Unit::Minute)?;
assert_eq!(
zdt2.to_string(),
"2024-11-03T01:59:00-05:00[America/New_York]",
);
§Example: overflow error
This example demonstrates that it’s possible for this operation to result in an error from zoned datetime arithmetic overflow.
use jiff::{Timestamp, Unit};
let zdt = Timestamp::MAX.intz("America/New_York")?;
assert!(zdt.round(Unit::Day).is_err());
This occurs because rounding to the nearest day for the maximum timestamp would result in rounding up to the next day. But the next day is greater than the maximum, and so this returns an error.
§impl Zoned
Parsing and formatting using a “printf”-style API.
impl Zoned
Parsing and formatting using a “printf”-style API.
pub fn strptime(
format: impl AsRef<[u8]>,
input: impl AsRef<[u8]>,
) -> Result<Zoned, Error> ⓘ
pub fn strptime( format: impl AsRef<[u8]>, input: impl AsRef<[u8]>, ) -> Result<Zoned, Error> ⓘ
Parses a zoned datetime in input
matching the given format
.
The format string uses a “printf”-style API where conversion
specifiers can be used as place holders to match components of
a datetime. For details on the specifiers supported, see the
fmt::strtime
module documentation.
§Warning
The strtime
module APIs do not require an IANA time zone identifier
to parse a Zoned
. If one is not used, then if you format a zoned
datetime in a time zone like America/New_York
and then parse it back
again, the zoned datetime you get back will be a “fixed offset” zoned
datetime. This in turn means it will not perform daylight saving time
safe arithmetic.
However, the %V
directive may be used to both format and parse an
IANA time zone identifier. It is strongly recommended to use this
directive whenever one is formatting or parsing Zoned
values.
§Errors
This returns an error when parsing failed. This might happen because the format string itself was invalid, or because the input didn’t match the format string.
This also returns an error if there wasn’t sufficient information to construct a zoned datetime. For example, if an offset wasn’t parsed.
§Example
This example shows how to parse a zoned datetime:
use jiff::Zoned;
let zdt = Zoned::strptime("%F %H:%M %:V", "2024-07-14 21:14 US/Eastern")?;
assert_eq!(zdt.to_string(), "2024-07-14T21:14:00-04:00[US/Eastern]");
pub fn strftime<'f, F>(&self, format: &'f F) -> Display<'f>
pub fn strftime<'f, F>(&self, format: &'f F) -> Display<'f>
Formats this zoned datetime according to the given format
.
The format string uses a “printf”-style API where conversion
specifiers can be used as place holders to format components of
a datetime. For details on the specifiers supported, see the
fmt::strtime
module documentation.
§Warning
The strtime
module APIs do not support parsing or formatting with
IANA time zone identifiers. This means that if you format a zoned
datetime in a time zone like America/New_York
and then parse it back
again, the zoned datetime you get back will be a “fixed offset” zoned
datetime. This in turn means it will not perform daylight saving time
safe arithmetic.
The strtime
modules APIs are useful for ad hoc formatting and
parsing, but they shouldn’t be used as an interchange format. For
an interchange format, the default std::fmt::Display
and
std::str::FromStr
trait implementations on Zoned
are appropriate.
§Errors and panics
While this routine itself does not error or panic, using the value
returned may result in a panic if formatting fails. See the
documentation on fmt::strtime::Display
for more information.
To format in a way that surfaces errors without panicking, use either
fmt::strtime::format
or fmt::strtime::BrokenDownTime::format
.
§Example
While the output of the Unix date
command is likely locale specific,
this is what it looks like on my system:
use jiff::civil::date;
let zdt = date(2024, 7, 15).at(16, 24, 59, 0).intz("America/New_York")?;
let string = zdt.strftime("%a %b %e %I:%M:%S %p %Z %Y").to_string();
assert_eq!(string, "Mon Jul 15 04:24:59 PM EDT 2024");
Trait Implementations§
§impl<'a> Add<Duration> for &'a Zoned
Adds an unsigned duration of time to a zoned datetime.
impl<'a> Add<Duration> for &'a Zoned
Adds an unsigned duration of time to a zoned datetime.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_add
.
§impl<'a> Add<SignedDuration> for &'a Zoned
Adds a signed duration of time to a zoned datetime.
impl<'a> Add<SignedDuration> for &'a Zoned
Adds a signed duration of time to a zoned datetime.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_add
.
§impl<'a> Add<Span> for &'a Zoned
Adds a span of time to a zoned datetime.
impl<'a> Add<Span> for &'a Zoned
Adds a span of time to a zoned datetime.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_add
.
§impl AddAssign<Duration> for Zoned
Adds an unsigned duration of time to a zoned datetime in place.
impl AddAssign<Duration> for Zoned
Adds an unsigned duration of time to a zoned datetime in place.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_add
.
§fn add_assign(&mut self, rhs: Duration)
fn add_assign(&mut self, rhs: Duration)
+=
operation. Read more§impl AddAssign<SignedDuration> for Zoned
Adds a signed duration of time to a zoned datetime in place.
impl AddAssign<SignedDuration> for Zoned
Adds a signed duration of time to a zoned datetime in place.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_add
.
§fn add_assign(&mut self, rhs: SignedDuration)
fn add_assign(&mut self, rhs: SignedDuration)
+=
operation. Read more§impl AddAssign<Span> for Zoned
Adds a span of time to a zoned datetime in place.
impl AddAssign<Span> for Zoned
Adds a span of time to a zoned datetime in place.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_add
.
§fn add_assign(&mut self, rhs: Span)
fn add_assign(&mut self, rhs: Span)
+=
operation. Read more§impl Debug for Zoned
Converts a Zoned
datetime into a human readable datetime string.
impl Debug for Zoned
Converts a Zoned
datetime into a human readable datetime string.
(This Debug
representation currently emits the same string as the
Display
representation, but this is not a guarantee.)
Options currently supported:
std::fmt::Formatter::precision
can be set to control the precision of the fractional second component.
§Example
use jiff::civil::date;
let zdt = date(2024, 6, 15).at(7, 0, 0, 123_000_000).intz("US/Eastern")?;
assert_eq!(
format!("{zdt:.6?}"),
"2024-06-15T07:00:00.123000-04:00[US/Eastern]",
);
// Precision values greater than 9 are clamped to 9.
assert_eq!(
format!("{zdt:.300?}"),
"2024-06-15T07:00:00.123000000-04:00[US/Eastern]",
);
// A precision of 0 implies the entire fractional
// component is always truncated.
assert_eq!(
format!("{zdt:.0?}"),
"2024-06-15T07:00:00-04:00[US/Eastern]",
);
§impl Display for Zoned
Converts a Zoned
datetime into a RFC 9557 compliant string.
impl Display for Zoned
Converts a Zoned
datetime into a RFC 9557 compliant string.
Options currently supported:
std::fmt::Formatter::precision
can be set to control the precision of the fractional second component.
§Example
use jiff::civil::date;
let zdt = date(2024, 6, 15).at(7, 0, 0, 123_000_000).intz("US/Eastern")?;
assert_eq!(
format!("{zdt:.6}"),
"2024-06-15T07:00:00.123000-04:00[US/Eastern]",
);
// Precision values greater than 9 are clamped to 9.
assert_eq!(
format!("{zdt:.300}"),
"2024-06-15T07:00:00.123000000-04:00[US/Eastern]",
);
// A precision of 0 implies the entire fractional
// component is always truncated.
assert_eq!(
format!("{zdt:.0}"),
"2024-06-15T07:00:00-04:00[US/Eastern]",
);
§impl<'a> From<&'a Zoned> for BrokenDownTime
impl<'a> From<&'a Zoned> for BrokenDownTime
§fn from(zdt: &'a Zoned) -> BrokenDownTime
fn from(zdt: &'a Zoned) -> BrokenDownTime
§impl<'a> From<&'a Zoned> for DateDifference
impl<'a> From<&'a Zoned> for DateDifference
§fn from(zdt: &'a Zoned) -> DateDifference
fn from(zdt: &'a Zoned) -> DateDifference
§impl<'a> From<&'a Zoned> for DateTimeDifference
impl<'a> From<&'a Zoned> for DateTimeDifference
§fn from(zdt: &'a Zoned) -> DateTimeDifference
fn from(zdt: &'a Zoned) -> DateTimeDifference
§impl<'a> From<&'a Zoned> for SpanRelativeTo<'a>
impl<'a> From<&'a Zoned> for SpanRelativeTo<'a>
§fn from(zdt: &'a Zoned) -> SpanRelativeTo<'a>
fn from(zdt: &'a Zoned) -> SpanRelativeTo<'a>
§impl<'a> From<&'a Zoned> for TimeDifference
impl<'a> From<&'a Zoned> for TimeDifference
§fn from(zdt: &'a Zoned) -> TimeDifference
fn from(zdt: &'a Zoned) -> TimeDifference
§impl<'a> From<&'a Zoned> for TimestampDifference
impl<'a> From<&'a Zoned> for TimestampDifference
§fn from(zdt: &'a Zoned) -> TimestampDifference
fn from(zdt: &'a Zoned) -> TimestampDifference
§impl<'a> From<&'a Zoned> for ZonedDifference<'a>
impl<'a> From<&'a Zoned> for ZonedDifference<'a>
§fn from(zdt: &'a Zoned) -> ZonedDifference<'a>
fn from(zdt: &'a Zoned) -> ZonedDifference<'a>
§impl From<Zoned> for DateDifference
impl From<Zoned> for DateDifference
§fn from(zdt: Zoned) -> DateDifference
fn from(zdt: Zoned) -> DateDifference
§impl From<Zoned> for DateTimeDifference
impl From<Zoned> for DateTimeDifference
§fn from(zdt: Zoned) -> DateTimeDifference
fn from(zdt: Zoned) -> DateTimeDifference
§impl From<Zoned> for SystemTime
impl From<Zoned> for SystemTime
§fn from(time: Zoned) -> SystemTime
fn from(time: Zoned) -> SystemTime
§impl From<Zoned> for TimeDifference
impl From<Zoned> for TimeDifference
§fn from(zdt: Zoned) -> TimeDifference
fn from(zdt: Zoned) -> TimeDifference
§impl From<Zoned> for TimestampDifference
impl From<Zoned> for TimestampDifference
§fn from(zdt: Zoned) -> TimestampDifference
fn from(zdt: Zoned) -> TimestampDifference
§impl FromStr for Zoned
Parses a zoned timestamp from the Temporal datetime format.
impl FromStr for Zoned
Parses a zoned timestamp from the Temporal datetime format.
See the fmt::temporal
for more information on
the precise format.
Note that this is only enabled when the std
feature
is enabled because it requires access to a global
TimeZoneDatabase
.
§impl Ord for Zoned
impl Ord for Zoned
§impl<'a> PartialOrd<Zoned> for &'a Zoned
impl<'a> PartialOrd<Zoned> for &'a Zoned
§impl PartialOrd for Zoned
impl PartialOrd for Zoned
§impl<'a> Sub<Duration> for &'a Zoned
Subtracts an unsigned duration of time from a zoned datetime.
impl<'a> Sub<Duration> for &'a Zoned
Subtracts an unsigned duration of time from a zoned datetime.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_sub
.
§impl<'a> Sub<SignedDuration> for &'a Zoned
Subtracts a signed duration of time from a zoned datetime.
impl<'a> Sub<SignedDuration> for &'a Zoned
Subtracts a signed duration of time from a zoned datetime.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_sub
.
§impl<'a> Sub<Span> for &'a Zoned
Subtracts a span of time from a zoned datetime.
impl<'a> Sub<Span> for &'a Zoned
Subtracts a span of time from a zoned datetime.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_sub
.
§impl<'a> Sub for &'a Zoned
Computes the span of time between two zoned datetimes.
impl<'a> Sub for &'a Zoned
Computes the span of time between two zoned datetimes.
This will return a negative span when the zoned datetime being subtracted is greater.
Since this uses the default configuration for calculating a span between two zoned datetimes (no rounding and largest units is days), this will never panic or fail in any way.
To configure the largest unit or enable rounding, use Zoned::since
.
§impl SubAssign<Duration> for Zoned
Subtracts an unsigned duration of time from a zoned datetime in place.
impl SubAssign<Duration> for Zoned
Subtracts an unsigned duration of time from a zoned datetime in place.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_sub
.
§fn sub_assign(&mut self, rhs: Duration)
fn sub_assign(&mut self, rhs: Duration)
-=
operation. Read more§impl SubAssign<SignedDuration> for Zoned
Subtracts a signed duration of time from a zoned datetime in place.
impl SubAssign<SignedDuration> for Zoned
Subtracts a signed duration of time from a zoned datetime in place.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_sub
.
§fn sub_assign(&mut self, rhs: SignedDuration)
fn sub_assign(&mut self, rhs: SignedDuration)
-=
operation. Read more§impl SubAssign<Span> for Zoned
Subtracts a span of time from a zoned datetime in place.
impl SubAssign<Span> for Zoned
Subtracts a span of time from a zoned datetime in place.
This uses checked arithmetic and panics on overflow. To handle overflow
without panics, use Zoned::checked_sub
.
§fn sub_assign(&mut self, rhs: Span)
fn sub_assign(&mut self, rhs: Span)
-=
operation. Read more§impl TryFrom<SystemTime> for Zoned
impl TryFrom<SystemTime> for Zoned
impl Eq for Zoned
Auto Trait Implementations§
impl Freeze for Zoned
impl RefUnwindSafe for Zoned
impl Send for Zoned
impl Sync for Zoned
impl Unpin for Zoned
impl UnwindSafe for Zoned
Blanket Implementations§
§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
§type ArchivedMetadata = ()
type ArchivedMetadata = ()
§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> ByteSized for T
impl<T> ByteSized for T
Source§const BYTE_ALIGN: usize = _
const BYTE_ALIGN: usize = _
Source§fn byte_align(&self) -> usize ⓘ
fn byte_align(&self) -> usize ⓘ
Source§fn ptr_size_ratio(&self) -> [usize; 2]
fn ptr_size_ratio(&self) -> [usize; 2]
Source§impl<T, R> Chain<R> for Twhere
T: ?Sized,
impl<T, R> Chain<R> for Twhere
T: ?Sized,
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Comparable<K> for Q
impl<Q, K> Comparable<K> for Q
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key
and return true
if they are equal.Source§impl<T> ExtAny for T
impl<T> ExtAny for T
Source§fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
Source§impl<T> ExtMem for Twhere
T: ?Sized,
impl<T> ExtMem for Twhere
T: ?Sized,
Source§const NEEDS_DROP: bool = _
const NEEDS_DROP: bool = _
Source§fn mem_align_of_val(&self) -> usize ⓘ
fn mem_align_of_val(&self) -> usize ⓘ
Source§fn mem_size_of_val(&self) -> usize ⓘ
fn mem_size_of_val(&self) -> usize ⓘ
Source§fn mem_needs_drop(&self) -> bool
fn mem_needs_drop(&self) -> bool
true
if dropping values of this type matters. Read moreSource§fn mem_forget(self)where
Self: Sized,
fn mem_forget(self)where
Self: Sized,
self
without running its destructor. Read moreSource§fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
Source§unsafe fn mem_zeroed<T>() -> T
unsafe fn mem_zeroed<T>() -> T
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§fn mem_as_bytes(&self) -> &[u8] ⓘ
fn mem_as_bytes(&self) -> &[u8] ⓘ
unsafe_slice
only.§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Hook for T
impl<T> Hook for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out
indicating that a T
is niched.