Struct Zoned
struct Zoned { ... }
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
Timestampfor indicating the precise instant in time. - A
DateTimefor indicating the "civil" calendar date and clock time. - A
TimeZonefor 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
Zonedvalues from otherZonedvalues viaZoned::withby 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
DateTimeAPI is offered onZoned, but where each of its operations take time zone into account when appropriate. For example,DateTime::start_of_dayalways returns a datetime set to midnight, butZoned::start_of_dayreturns 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, aZonedcan be losslessy converted to any other datetime type in this crate:Timestamp,DateTime,DateandTime. - A
Zonedvalue 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
Zonedstores aTimeZoneitself, 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 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!;
// 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!;
// 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.build?;
assert_eq!;
# Ok::
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 Zoned;
let zdt: Zoned = "2024-06-19[America/New_York]".parse?;
assert_eq!;
// ... 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!;
# Ok::
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 ;
let zdt: Zoned = "2016-12-31 23:59:60[Australia/Tasmania]".parse?;
assert_eq!;
# Ok::
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 date;
let zdt1 = date.at.in_tz?;
let zdt2 = date.at.in_tz?;
assert!;
# Ok::
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 date;
let zdt1 = date.at.in_tz?;
let zdt2 = date.at.in_tz?;
assert!;
// But if we only compare civil datetime, the result is flipped:
assert!;
# Ok::
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 date;
let zdt1 = date.at.in_tz?;
let zdt2 = date.at.in_tz?;
assert_eq!;
# Ok::
(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_addorZoned::checked_subfor checked arithmetic.Zoned::saturating_addorZoned::saturating_subfor saturating arithmetic.
Additionally, checked arithmetic is available via the Add and Sub
trait implementations. When the result overflows, a panic occurs.
use ;
let start = date.at.in_tz?;
// `Zoned` doesn't implement `Copy`, so we use `&start` instead of `start`.
let one_week_later = &start + 1.weeks;
assert_eq!;
# Ok::
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 ;
let zdt1 = date.at.in_tz?;
let zdt2 = date.at.in_tz?;
assert_eq!;
# Ok::
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 ;
let zdt1 = date.at.in_tz?;
let zdt2 = date.at.in_tz?;
assert_eq!;
# Ok::
Or even round the span returned:
use ;
let zdt1 = date.at.in_tz?;
let zdt2 = date.at.in_tz?;
assert_eq!;
// `ZonedDifference` uses truncation as a rounding mode by default,
// but you can set the rounding mode to break ties away from zero:
assert_eq!;
# Ok::
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 ;
let zdt = date
.at
.in_tz?;
assert_eq!;
// Or alternatively, make use of the `From<(Unit, i64)> for ZonedRound`
// trait implementation:
assert_eq!;
# Ok::
See Zoned::round for more details.
Implementations
impl Zoned
fn strptime<impl AsRef<[u8]>: AsRef<[u8]>, impl AsRef<[u8]>: AsRef<[u8]>>(format: impl AsRef<[u8]>, input: impl AsRef<[u8]>) -> Result<Zoned, Error>Parses a zoned datetime in
inputmatching the givenformat.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::strtimemodule documentation.Warning
The
strtimemodule APIs do not require an IANA time zone identifier to parse aZoned. If one is not used, then if you format a zoned datetime in a time zone likeAmerica/New_Yorkand 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
%Qdirective 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 parsingZonedvalues.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 Zoned; let zdt = strptime?; assert_eq!; # Ok::fn strftime<'f, F: 'f + ?Sized + AsRef<[u8]>>(self: &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::strtimemodule documentation.Warning
The
strtimemodule 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 likeAmerica/New_Yorkand 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
strtimemodules APIs are useful for ad hoc formatting and parsing, but they shouldn't be used as an interchange format. For an interchange format, the defaultstd::fmt::Displayandstd::str::FromStrtrait implementations onZonedare 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::Displayfor more information.To format in a way that surfaces errors without panicking, use either
fmt::strtime::formatorfmt::strtime::BrokenDownTime::format.Example
While the output of the Unix
datecommand is likely locale specific, this is what it looks like on my system:use date; let zdt = date.at.in_tz?; let string = zdt.strftime.to_string; assert_eq!; # Ok::
impl Zoned
fn now() -> ZonedReturns the current system time in this system's time zone.
If the system's time zone could not be found, then
TimeZone::UTCis used instead. When this happens, aWARNlevel log message will be emitted. (To see it, one will need to install a logger that is compatible with thelogcrate and enable Jiff'sloggingCargo feature.)To create a
Zonedvalue for the current time in a particular time zone other than the system default time zone, useTimestamp::now().to_zoned(time_zone). In particular, usingTimestamp::nowavoids the work required to fetch the system time zone if you didZoned::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_fromwith astd::time::SystemTimeas input.This may also panic when
SystemTime::now()itself panics. The most common context in which this happens is on thewasm32-unknown-unknowntarget. If you're using that target in the context of the web (for example, viawasm-pack), and you're an application, then you should enable Jiff'sjsfeature. 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 ; assert!;fn new(timestamp: Timestamp, time_zone: TimeZone) -> ZonedCreates a new
Zonedvalue 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
ZonedWithviaZoned::with.Construction from civil time
A
Zonedvalue can also be created from a civil time via the following methods:DateTime::in_tzdoes a Time Zone Database lookup given a time zone name string.DateTime::to_zonedaccepts aTimeZone.Date::in_tzdoes a Time Zone Database lookup given a time zone name string and attempts to use midnight as the clock time.Date::to_zonedaccepts aTimeZoneand 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::Compatiblestrategy to automatically resolve these corner cases.If one wants to control how ambiguity is resolved (including by returning an error), use
TimeZone::to_ambiguous_zonedand select the desired strategy via a method onAmbiguousZoned.Example: What was the civil time in Tasmania at the Unix epoch?
use ; let tz = get?; let zdt = new; assert_eq!; # Ok::Example: What was the civil time in New York when World War 1 ended?
use date; let zdt1 = date.at.in_tz?; let zdt2 = zdt1.in_tz?; assert_eq!; # Ok::fn with(self: &Self) -> ZonedWithCreate a builder for constructing a new
DateTimefrom the fields of this datetime.See the methods on
ZonedWithfor the different ways one can set the fields of a newZoned.Note that this doesn't support changing the time zone. If you want a
Zonedvalue of the same instant but in a different time zone, useZoned::in_tzorZoned::with_time_zone. If you want aZonedvalue of the same civil datetime (assuming it isn't ambiguous) but in a different time zone, then useZoned::datetimefollowed byDateTime::in_tzorDateTime::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 date; let zdt1 = date.at.in_tz?; let zdt2 = zdt1.with.month.day.build?; assert_eq!; let zdt1 = date.at.in_tz?; let zdt2 = zdt1.with.day.month.build?; assert_eq!; # Ok::fn with_time_zone(self: &Self, time_zone: TimeZone) -> ZonedReturn 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 civilDateTimemay be different.Example: What was the civil time in New York when World War 1 ended?
use ; let from = get?; let to = get?; let zdt1 = date.at.to_zoned?; // 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; assert_eq!; # Ok::fn in_tz(self: &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 civilDateTimemay be different.The name given is resolved to a
TimeZoneby using the defaultTimeZoneDatabasecreated bytz::db. Indeed, this is a convenience function forDateTime::to_zonedwhere 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 date; let zdt1 = date.at.in_tz?; // 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.in_tz?; assert_eq!; # Ok::fn time_zone(self: &Self) -> &TimeZoneReturns the time zone attached to this
Zonedvalue.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 Zoned; let zdt: Zoned = "2024-07-03 14:31[america/new_york]".parse?; assert_eq!; # Ok::fn year(self: &Self) -> i16Returns the year for this zoned datetime.
The value returned is guaranteed to be in the range
-9999..=9999.Example
use date; let zdt1 = date.at.in_tz?; assert_eq!; let zdt2 = date.at.in_tz?; assert_eq!; let zdt3 = date.at.in_tz?; assert_eq!; # Ok::fn era_year(self: &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 than0. In the Gregorian calendar, the era labelsBCEandCEare used to disambiguate between years less than or equal to0and years greater than0, 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 ; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn month(self: &Self) -> i8Returns the month for this zoned datetime.
The value returned is guaranteed to be in the range
1..=12.Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn day(self: &Self) -> i8Returns the day for this zoned datetime.
The value returned is guaranteed to be in the range
1..=31.Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn hour(self: &Self) -> i8Returns the "hour" component of this zoned datetime.
The value returned is guaranteed to be in the range
0..=23.Example
use date; let zdt = date .at .in_tz?; assert_eq!; # Ok::fn minute(self: &Self) -> i8Returns the "minute" component of this zoned datetime.
The value returned is guaranteed to be in the range
0..=59.Example
use date; let zdt = date .at .in_tz?; assert_eq!; # Ok::fn second(self: &Self) -> i8Returns the "second" component of this zoned datetime.
The value returned is guaranteed to be in the range
0..=59.Example
use date; let zdt = date .at .in_tz?; assert_eq!; # Ok::fn millisecond(self: &Self) -> i16Returns the "millisecond" component of this zoned datetime.
The value returned is guaranteed to be in the range
0..=999.Example
use date; let zdt = date .at .in_tz?; assert_eq!; # Ok::fn microsecond(self: &Self) -> i16Returns the "microsecond" component of this zoned datetime.
The value returned is guaranteed to be in the range
0..=999.Example
use date; let zdt = date .at .in_tz?; assert_eq!; # Ok::fn nanosecond(self: &Self) -> i16Returns the "nanosecond" component of this zoned datetime.
The value returned is guaranteed to be in the range
0..=999.Example
use date; let zdt = date .at .in_tz?; assert_eq!; # Ok::fn subsec_nanosecond(self: &Self) -> i32Returns the fractional nanosecond for this
Zonedvalue.If you want to set this value on
Zoned, then useZonedWith::subsec_nanosecondviaZoned::with.The value returned is guaranteed to be in the range
0..=999_999_999.Example
This shows the relationship between constructing a
Zonedvalue with routines likewith().millisecond()and accessing the entire fractional part as a nanosecond:use date; let zdt1 = date .at .in_tz?; assert_eq!; let zdt2 = zdt1.with.millisecond.build?; assert_eq!; # Ok::Example: nanoseconds from a timestamp
This shows how the fractional nanosecond part of a
Zonedvalue manifests from a specific timestamp.use ; // 1,234 nanoseconds after the Unix epoch. let zdt = new?.in_tz?; assert_eq!; // 1,234 nanoseconds before the Unix epoch. let zdt = new?.in_tz?; // The nanosecond is equal to `1_000_000_000 - 1_234`. assert_eq!; // Looking at the other components of the time value might help. assert_eq!; assert_eq!; assert_eq!; # Ok::fn weekday(self: &Self) -> WeekdayReturns the weekday corresponding to this zoned datetime.
Example
use ; // The Unix epoch was on a Thursday. let zdt = date.at.in_tz?; assert_eq!; // One can also get the weekday as an offset in a variety of schemes. assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn day_of_year(self: &Self) -> i16Returns 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 range1..=365.Example
use date; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn day_of_year_no_leap(self: &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 returnsNone.The value
365always corresponds to the last day in the year, December 31, even for leap years.Example
use date; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn start_of_day(self: &Self) -> Result<Zoned, Error>Returns the beginning of the day, corresponding to
00:00:00civil 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 ; let zdt = date.at.in_tz?; assert_eq!; # Ok::Example: start of day may not be midnight
In some time zones, gap transitions may begin at midnight. This implies that
00:xx:yydoes not exist on a clock in that time zone for that day.use ; let zdt = date.at.in_tz?; assert_eq!; # Ok::Example: error because of overflow
In some cases, it's possible for
Zonedvalue 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 ; // 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 = fixed; let zdt = date.at.to_zoned?; assert!; // The next day works fine since -9999-01-04T00:00:00+25:59:59 is // representable. let zdt = date.at.to_zoned?; assert_eq!; # Ok::fn end_of_day(self: &Self) -> Result<Zoned, Error>Returns the end of the day, corresponding to
23:59:59.999999999civil 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 date; let zdt = date .at .in_tz?; assert_eq!; # Ok::Example: error because of overflow
In some cases, it's possible for
Zonedvalue 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 ; // While 9999-12-30T01:30-04 is representable as a Zoned // value, the start of the corresponding day is not! let tz = get?; let zdt = date.at.to_zoned?; assert!; // The previous day works fine since 9999-12-29T23:59:59.999999999-04 // is representable. let zdt = date.at.to_zoned?; assert_eq!; # Ok::fn first_of_month(self: &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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::first_of_month, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn last_of_month(self: &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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::last_of_month, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn days_in_month(self: &Self) -> i8Returns 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 date; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; # Ok::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 ; let first_of_month = date.in_tz?; assert_eq!; let one_month_later = first_of_month.checked_add?; let options = new .largest .smallest .mode; let span = first_of_month.until?; let days = .round as i64; // Try the above in a different time zone, like America/New_York, and // you'll get 31 here. assert_eq!; # Ok::fn first_of_year(self: &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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::first_of_year, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn last_of_year(self: &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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::last_of_year, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn days_in_year(self: &Self) -> i16Returns 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
365or366.Example
use date; let zdt = date.at.in_tz?; assert_eq!; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn in_leap_year(self: &Self) -> boolReturns true if and only if the year in which this zoned datetime resides is a leap year.
Example
use date; let zdt = date.at.in_tz?; assert!; let zdt = date.at.in_tz?; assert!; # Ok::fn tomorrow(self: &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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::tomorrow, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Errors
This returns an error when one day following this zoned datetime would exceed the maximum
Zonedvalue.Example
use ; let zdt = date.at.in_tz?; assert_eq!; // The max doesn't have a tomorrow. assert!; # Ok::Example: ambiguous datetimes are automatically resolved
use ; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn yesterday(self: &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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::yesterday, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Errors
This returns an error when one day preceding this zoned datetime would be less than the minimum
Zonedvalue.Example
use ; let zdt = date.at.in_tz?; assert_eq!; // The min doesn't have a yesterday. assert!; # Ok::Example: ambiguous datetimes are automatically resolved
use ; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn nth_weekday_of_month(self: &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
nthparameter 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-1to "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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::nth_weekday_of_month, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Errors
This returns an error when
nthis0, or if it is5or-5and 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 thisZoned's time zone. (This can only happen close the boundaries of anTimestamp.)Example
This shows how to get the nth weekday in a month, starting from the beginning of the month:
use ; let zdt = date.at.in_tz?; let second_friday = zdt.nth_weekday_of_month?; assert_eq!; # Ok::This shows how to do the reverse of the above. That is, the nth last weekday in a month:
use ; let zdt = date.at.in_tz?; let last_thursday = zdt.nth_weekday_of_month?; assert_eq!; let second_last_thursday = zdt.nth_weekday_of_month?; assert_eq!; # Ok::This routine can return an error if there isn't an
nthweekday for this month. For example, March 2024 only has 4 Mondays:use ; let zdt = date.at.in_tz?; let fourth_monday = zdt.nth_weekday_of_month?; assert_eq!; // There is no 5th Monday. assert!; // Same goes for counting backwards. assert!; # Ok::fn nth_weekday(self: &Self, nth: i32, weekday: Weekday) -> Result<Zoned, Error>Returns the "nth" weekday from this zoned datetime, not including itself.
The
nthparameter 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
Zonedis a precise instant in time) and the same clock time on the returned zoned datetime is ambiguous. In this case, theDisambiguation::Compatiblestrategy will be used to turn it into a precise instant. If you want to use a different disambiguation strategy, then useZoned::datetimeto get the civil datetime, then useDateTime::nth_weekday, then useTimeZone::to_ambiguous_zonedand apply your preferred disambiguation strategy.Errors
This returns an error when
nthis0, or if it would otherwise result in a date that overflows the minimum/maximum values ofZoned.Example
This example shows how to find the "nth" weekday going forwards in time:
use ; // Use a Sunday in March as our start date. let zdt = date.at.in_tz?; assert_eq!; // The first next Monday is tomorrow! let next_monday = zdt.nth_weekday?; assert_eq!; // But the next Sunday is a week away, because this doesn't // include the current weekday. let next_sunday = zdt.nth_weekday?; assert_eq!; // "not this Thursday, but next Thursday" let next_next_thursday = zdt.nth_weekday?; assert_eq!; # Ok::This example shows how to find the "nth" weekday going backwards in time:
use ; // Use a Sunday in March as our start date. let zdt = date.at.in_tz?; assert_eq!; // "last Saturday" was yesterday! let last_saturday = zdt.nth_weekday?; assert_eq!; // "last Sunday" was a week ago. let last_sunday = zdt.nth_weekday?; assert_eq!; // "not last Thursday, but the one before" let prev_prev_thursday = zdt.nth_weekday?; assert_eq!; # Ok::This example shows that overflow results in an error in either direction:
use ; let zdt = MAX.in_tz?; assert_eq!; assert!; let zdt = MIN.in_tz?; assert_eq!; assert!; # Ok::Example: getting the start of the week
Given a date, one can use
nth_weekdayto 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 ; let zdt = date.at.in_tz?; // For weeks starting with Sunday. let start_of_week = zdt.tomorrow?.nth_weekday?; assert_eq!; // For weeks starting with Monday. let start_of_week = zdt.tomorrow?.nth_weekday?; assert_eq!; # Ok::In the above example, we first get the date after the current one because
nth_weekdaydoes not consider itself when counting. This works as expected even at the boundaries of a week:use ; // The start of the week. let zdt = date.at.in_tz?; let start_of_week = zdt.tomorrow?.nth_weekday?; assert_eq!; // The end of the week. let zdt = date .at .in_tz?; let start_of_week = zdt .tomorrow? .nth_weekday? .with.time.build?; assert_eq!; # Ok::fn timestamp(self: &Self) -> TimestampReturns the precise instant in time referred to by this zoned datetime.
Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn datetime(self: &Self) -> DateTimeReturns the civil datetime component of this zoned datetime.
Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn date(self: &Self) -> DateReturns the civil date component of this zoned datetime.
Example
use date; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn time(self: &Self) -> TimeReturns the civil time component of this zoned datetime.
Example
use ; let zdt = date.at.in_tz?; assert_eq!; # Ok::fn iso_week_date(self: Self) -> ISOWeekDateConstruct a civil ISO 8601 week date from this zoned datetime.
The
ISOWeekDatetype describes itself in more detail, but in brief, the ISO week date calendar system eschews months in favor of weeks.This routine is equivalent to
ISOWeekDate::from_date(zdt.date()).Example
This shows a number of examples demonstrating the conversion from a Gregorian date to an ISO 8601 week date:
use ; let zdt = date.at.in_tz?; let weekdate = zdt.iso_week_date; assert_eq!; assert_eq!; assert_eq!; let zdt = date.at.in_tz?; let weekdate = zdt.iso_week_date; assert_eq!; assert_eq!; assert_eq!; let zdt = date.at.in_tz?; let weekdate = zdt.iso_week_date; assert_eq!; assert_eq!; assert_eq!; let zdt = date.at.in_tz?; let weekdate = zdt.iso_week_date; assert_eq!; assert_eq!; assert_eq!; # Ok::fn offset(self: &Self) -> OffsetReturns the time zone offset of this zoned datetime.
Example
use date; let zdt = date.at.in_tz?; // -05 because New York is in "standard" time at this point. assert_eq!; let zdt = date.at.in_tz?; // But we get -04 once "summer" or "daylight saving time" starts. assert_eq!; # Ok::fn checked_add<A: Into<ZonedArithmetic>>(self: &Self, duration: A) -> Result<Zoned, Error>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,SignedDurationorstd::time::Duration. This is achieved viaFromtrait implementations for theZonedArithmetictype.Properties
This routine is not reversible because some additions may be ambiguous. For example, adding
1 monthto the zoned datetime2024-03-31T00:00:00[America/New_York]will produce2024-04-30T00:00:00[America/New_York]since April has only 30 days in a month. Moreover, subtracting1 monthfrom2024-04-30T00:00:00[America/New_York]will produce2024-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
SignedDurationor astd::time::Durationare 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
ToSpantrait for convenient creation of spans.use ; let zdt = date .at .in_tz?; let got = zdt.checked_add?; assert_eq!; let zdt = date.at.in_tz?; let got = zdt.checked_add?; assert_eq!; # Ok::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 ofzdt + ...sinceAddis implemented for&Zonedand notZoned. This is becauseZonedis notCopy.use ; let zdt = date .at .in_tz?; let got = &zdt + 20.years.months.nanoseconds; assert_eq!; # Ok::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 ; let zdt = date.at.in_tz?; let one_day_later = zdt.checked_add?; assert_eq!; let twenty_four_hours_later = zdt.checked_add?; assert_eq!; # Ok::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::Compatiblestrategy 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 at2024-03-10 02:00:00inAmerica/New_York. The "compatible" strategy chooses the later time in a gap:.use ; let zdt = date.at.in_tz?; let one_day_later = zdt.checked_add?; assert_eq!; # Ok::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 ; let zdt = date.at.in_tz?; let one_day_later = zdt.checked_add?; assert_eq!; # Ok::Example: negative spans are supported
use ; let zdt = date .at .in_tz?; assert_eq!; # Ok::Example: error on overflow
use ; let zdt = date.at.in_tz?; assert!; assert!; # Ok::Example: adding absolute durations
This shows how to add signed and unsigned absolute durations to a
Zoned.use Duration; use ; let zdt = date.at.in_tz?; let dur = from_hours; assert_eq!; assert_eq!; let dur = from_secs; assert_eq!; // One cannot negate an unsigned duration, // but you can subtract it! assert_eq!; # Ok::fn checked_sub<A: Into<ZonedArithmetic>>(self: &Self, duration: A) -> Result<Zoned, Error>This routine is identical to
Zoned::checked_addwith 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 ofzdt - ...sinceSubis implemented for&Zonedand notZoned. This is becauseZonedis notCopy.use Duration; use ; let zdt = date .at .in_tz?; let got = &zdt - 20.years.months.nanoseconds; assert_eq!; let dur = new; assert_eq!; let dur = new; assert_eq!; # Ok::fn saturating_add<A: Into<ZonedArithmetic>>(self: &Self, duration: A) -> ZonedThis routine is identical to
Zoned::checked_add, except the result saturates on overflow. That is, instead of overflow, eitherTimestamp::MINorTimestamp::MAX(in thisZonedvalue'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 ; let zdt = date.at.in_tz?; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn saturating_sub<A: Into<ZonedArithmetic>>(self: &Self, duration: A) -> ZonedThis routine is identical to
Zoned::saturating_addwith the span parameter negated.Example
use ; let zdt = date.at.in_tz?; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn until<'a, A: Into<ZonedDifference<'a>>>(self: &Self, other: A) -> Result<Span, Error>Returns a span representing the elapsed time from this zoned datetime until the given
otherzoned datetime.When
otheroccurs 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
ZonedDifferencevalue. Since this routine accepts anything that implementsInto<ZonedDifference>, once can pass a&Zoneddirectly. One can also pass a(Unit, &Zoned), whereUnitis treated asZonedDifference::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 mostUnit::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 toself.since(other_without_rounding_options).map(|span| -span), followed by a call toSpan::roundwith 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
ZonedDifferenceis misconfigured. For example, if the smallest unit provided is bigger than the largest unit.An error can also occur if units greater than
Unit::Hourare requested and if the time zones in the provided zoned datetimes are distinct. (SeeTimeZone'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
ZonedDifferenceconfiguration, then this routine will never fail.Example
use ; let earlier = date.at.in_tz?; let later = date.at.in_tz?; assert_eq!; // Flipping the dates is fine, but you'll get a negative span. assert_eq!; # Ok::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 ZonedDifferencetrait implementation.use ; let zdt1 = date.at.in_tz?; let zdt2 = date.at.in_tz?; // The default limits durations to using "hours" as the biggest unit. let span = zdt1.until?; assert_eq!; // But we can ask for units all the way up to years. let span = zdt1.until?; assert_eq!; # Ok::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
ZonedDifferencein order to gain full configurability.use ; let zdt1 = date.at.in_tz?; let zdt2 = date.at.in_tz?; let span = zdt1.until?; assert_eq!; // We can combine smallest and largest units too! let span = zdt1.until?; assert_eq!; # Ok::Example: units biggers than days inhibit reversibility
If you ask for units bigger than hours, then adding the span returned to the
otherzoned datetime is not guaranteed to result in the original zoned datetime. For example:use ; let zdt1 = date.at.in_tz?; let zdt2 = date.at.in_tz?; let span = zdt1.until?; assert_eq!; let maybe_original = zdt2.checked_sub?; // Not the same as the original datetime! assert_eq!; // But in the default configuration, hours are always the biggest unit // and reversibility is guaranteed. let span = zdt1.until?; assert_eq!; let is_original = zdt2.checked_sub?; assert_eq!; # Ok::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-02corresponds to 31 days, but subtracting one month from2024-05-01corresponds to 30 days.fn since<'a, A: Into<ZonedDifference<'a>>>(self: &Self, other: A) -> Result<Span, Error>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 aSpancan represent the difference between any two possible zoned datetimes, it will never panic. Note that we use&zdt1 - &zdt2instead ofzdt1 - zdt2sinceSubis implemented for&Zonedand notZoned. This is becauseZonedis notCopy.use ; let earlier = date.at.in_tz?; let later = date.at.in_tz?; assert_eq!; # Ok::fn duration_until(self: &Self, other: &Zoned) -> SignedDurationReturns an absolute duration representing the elapsed time from this zoned datetime until the given
otherzoned datetime.When
otheroccurs 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::untilcan return an error in some cases due to misconfiguration. But like this routine,Zoned::untilnever panics or returns an error in its default configuration.When should I use this versus
Zoned::until?See the type documentation for
SignedDurationfor the section on when one should useSpanand when one should useSignedDuration. In short, useSpan(and thereforeTimestamp::until) unless you have a specific reason to do otherwise.Example
use ; let earlier = date.at.in_tz?; let later = date.at.in_tz?; assert_eq!; // Flipping the dates is fine, but you'll get a negative span. assert_eq!; # Ok::Example: difference with
Zoned::untilThe main difference between this routine and
Zoned::untilis 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 ; let zdt1 = date.at.in_tz?; let zdt2 = date.at.in_tz?; let span = zdt1.until?; assert_eq!; let duration = zdt1.duration_until; // This day was only 23 hours long! assert_eq!; // 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 = new.largest.relative; let span = try_from?.round?; assert_eq!; # Ok::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 aSignedDurationand then convert it to astd::time::Duration:use Duration; use date; let zdt1 = date.at.in_tz?; let zdt2 = date.at.in_tz?; let duration = try_from?; assert_eq!; // Note that unsigned durations cannot represent all // possible differences! If the duration would be negative, // then the conversion fails: assert!; # Ok::fn duration_since(self: &Self, other: &Zoned) -> SignedDurationThis routine is identical to
Zoned::duration_until, but the order of the parameters is flipped.Example
use ; let earlier = date.at.in_tz?; let later = date.at.in_tz?; assert_eq!; # Ok::fn round<R: Into<ZonedRound>>(self: &Self, options: R) -> Result<Zoned, Error>Rounds this zoned datetime according to the
ZonedRoundconfiguration 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 viaZonedRound::increment. Finally, the rounding strategy itself can be configured viaZonedRound::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
ZonedRoundis 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 are1,2,4,5,100and500. Namely, any integer that divides evenly into1,000nanoseconds since there are1,000nanoseconds 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
ZonedRoundmanually.use ; // rounds up let zdt = date.at.in_tz?; assert_eq!; // rounds down let zdt = date.at.in_tz?; assert_eq!; # Ok::Example: changing the rounding mode
The default rounding mode is
RoundMode::HalfExpand, which breaks ties by rounding away from zero. But other modes likeRoundMode::Trunccan be used too:use ; let zdt = date.at.in_tz?; assert_eq!; // 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!; # Ok::Example: rounding to the nearest 5 minute increment
use ; // rounds down let zdt = date .at .in_tz?; assert_eq!; // rounds up let zdt = date .at .in_tz?; assert_eq!; # Ok::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 ; let zdt1: Zoned = "2024-03-10T01:59:00-05[America/New_York]".parse?; let zdt2 = zdt1.round?; assert_eq!; # Ok::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-03from offset-04to-05, here is an example that rounds the first 1 o'clock hour:use ; let zdt1: Zoned = "2024-11-03T01:59:01-04[America/New_York]".parse?; let zdt2 = zdt1.round?; assert_eq!; # Ok::And now the second 1 o'clock hour. Notice how the rounded result stays in the second 1 o'clock hour.
use ; let zdt1: Zoned = "2024-11-03T01:59:01-05[America/New_York]".parse?; let zdt2 = zdt1.round?; assert_eq!; # Ok::Example: overflow error
This example demonstrates that it's possible for this operation to result in an error from zoned datetime arithmetic overflow.
use ; let zdt = MAX.in_tz?; assert!; # Ok::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 AddAssign for Zoned
fn add_assign(self: &mut Self, rhs: SignedDuration)
impl AddAssign for Zoned
fn add_assign(self: &mut Self, rhs: Span)
impl AddAssign for Zoned
fn add_assign(self: &mut Self, rhs: UnsignedDuration)
impl Clone for Zoned
fn clone(self: &Self) -> Zoned
impl Debug for Zoned
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl Default for Zoned
fn default() -> Zoned
impl Display for Zoned
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl Eq for Zoned
impl Freeze for Zoned
impl FromStr for Zoned
fn from_str(string: &str) -> Result<Zoned, Error>
impl Hash for Zoned
fn hash<H: core::hash::Hasher>(self: &Self, state: &mut H)
impl Ord for Zoned
fn cmp(self: &Self, rhs: &Zoned) -> Ordering
impl PartialEq for Zoned
fn eq(self: &Self, rhs: &Zoned) -> bool
impl PartialOrd for Zoned
fn partial_cmp(self: &Self, rhs: &Zoned) -> Option<Ordering>
impl RefUnwindSafe for Zoned
impl Send for Zoned
impl Serialize for Zoned
fn serialize<S: serde::Serializer>(self: &Self, serializer: S) -> Result<<S as >::Ok, <S as >::Error>
impl SubAssign for Zoned
fn sub_assign(self: &mut Self, rhs: UnsignedDuration)
impl SubAssign for Zoned
fn sub_assign(self: &mut Self, rhs: SignedDuration)
impl SubAssign for Zoned
fn sub_assign(self: &mut Self, rhs: Span)
impl Sync for Zoned
impl TryFrom for Zoned
fn try_from(system_time: SystemTime) -> Result<Zoned, Error>
impl Unpin for Zoned
impl UnsafeUnpin for Zoned
impl UnwindSafe for Zoned
impl<'de> Deserialize for Zoned
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Zoned, <D as >::Error>
impl<T> Any for Zoned
fn type_id(self: &Self) -> TypeId
impl<T> Borrow for Zoned
fn borrow(self: &Self) -> &T
impl<T> BorrowMut for Zoned
fn borrow_mut(self: &mut Self) -> &mut T
impl<T> CloneToUninit for Zoned
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)
impl<T> DeserializeOwned for Zoned
impl<T> From for Zoned
fn from(t: T) -> TReturns the argument unchanged.
impl<T> ToOwned for Zoned
fn to_owned(self: &Self) -> Tfn clone_into(self: &Self, target: &mut T)
impl<T> ToString for Zoned
fn to_string(self: &Self) -> String
impl<T, U> Into for Zoned
fn into(self: Self) -> UCalls
U::from(self).That is, this conversion is whatever the implementation of
[From]<T> for Uchooses to do.
impl<T, U> TryFrom for Zoned
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
impl<T, U> TryInto for Zoned
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>