Struct Timestamp
struct Timestamp { ... }
An instant in time represented as the number of nanoseconds since the Unix epoch.
A timestamp is always in the Unix timescale with a UTC offset of zero.
To obtain civil or "local" datetime units like year, month, day or hour, a
timestamp needs to be combined with a TimeZone to create a Zoned.
That can be done with Timestamp::in_tz or Timestamp::to_zoned.
The integer count of nanoseconds since the Unix epoch is signed, where
the Unix epoch is 1970-01-01 00:00:00Z. A positive timestamp indicates
a point in time after the Unix epoch. A negative timestamp indicates a
point in time before the Unix epoch.
Parsing and printing
The Timestamp type provides convenient trait implementations of
std::str::FromStr and [std::fmt::Display]:
use Timestamp;
let ts: Timestamp = "2024-06-19 15:22:45-04".parse?;
assert_eq!;
# Ok::
A Timestamp can also be parsed from something that contains a
timestamp, but with perhaps other data (such as a time zone):
use Timestamp;
let ts: Timestamp = "2024-06-19T15:22:45-04[America/New_York]".parse?;
assert_eq!;
# Ok::
For more information on the specific format supported, see the
fmt::temporal module documentation.
Default value
For convenience, this type implements the Default trait. Its default
value corresponds to 1970-01-01T00:00:00.000000000. That is, it is the
Unix epoch. One can also access this value via the Timestamp::UNIX_EPOCH
constant.
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 timestamp with a second
component of 60, then it is automatically constrained to 59:
use Timestamp;
let ts: Timestamp = "2016-12-31 23:59:60Z".parse?;
assert_eq!;
# Ok::
Comparisons
The Timestamp type provides both Eq and Ord trait implementations
to facilitate easy comparisons. When a timestamp ts1 occurs before a
timestamp ts2, then dt1 < dt2. For example:
use Timestamp;
let ts1 = from_second?;
let ts2 = from_second?;
assert!;
# Ok::
Arithmetic
This type provides routines for adding and subtracting spans of time, as
well as computing the span of time between two Timestamp values.
For adding or subtracting spans of time, one can use any of the following routines:
Timestamp::checked_addorTimestamp::checked_subfor checked arithmetic.Timestamp::saturating_addorTimestamp::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 ts1: Timestamp = "2024-02-25T15:45Z".parse?;
let ts2 = ts1 - 24.hours;
assert_eq!;
# Ok::
One can compute the span of time between two timestamps using either
Timestamp::until or Timestamp::since. It's also possible to
subtract two Timestamp values directly via a Sub trait implementation:
use ;
let ts1: Timestamp = "2024-05-03 23:30:00.123Z".parse?;
let ts2: Timestamp = "2024-02-25 07Z".parse?;
// The default is to return spans with units no bigger than seconds.
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
seconds (as exemplified above), but we can ask for bigger units (up to
hours):
use ;
let ts1: Timestamp = "2024-05-03 23:30:00.123Z".parse?;
let ts2: Timestamp = "2024-02-25 07Z".parse?;
assert_eq!;
# Ok::
You can also round the span returned:
use ;
let ts1: Timestamp = "2024-05-03 23:30:59.123Z".parse?;
let ts2: Timestamp = "2024-05-02 07Z".parse?;
assert_eq!;
// `TimestampDifference` 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 timestamps
A Timestamp can be rounded based on a TimestampRound configuration of
smallest units, rounding increment and rounding mode. Here's an example
showing how to round to the nearest third hour:
use ;
let ts: Timestamp = "2024-06-19 16:27:29.999999999Z".parse?;
assert_eq!;
// Or alternatively, make use of the `From<(Unit, i64)> for TimestampRound`
// trait implementation:
assert_eq!;
# Ok::
See Timestamp::round for more details.
An instant in time
Unlike a civil::DateTime, a Timestamp
always corresponds, unambiguously, to a precise instant in time (to
nanosecond precision). This means that attaching a time zone to a timestamp
is always unambiguous because there's never any question as to which
instant it refers to. This is true even for gaps in civil time.
For example, in America/New_York, clocks were moved ahead one hour
at clock time 2024-03-10 02:00:00. That is, the 2 o'clock hour never
appeared on clocks in the America/New_York region. Since parsing a
timestamp always requires an offset, the time it refers to is unambiguous.
We can see this by writing a clock time, 02:30, that never existed but
with two different offsets:
use Timestamp;
// All we're doing here is attaching an offset to a civil datetime.
// There is no time zone information here, and thus there is no
// accounting for ambiguity due to daylight saving time transitions.
let before_hour_jump: Timestamp = "2024-03-10 02:30-04".parse?;
let after_hour_jump: Timestamp = "2024-03-10 02:30-05".parse?;
// This shows the instant in time in UTC.
assert_eq!;
assert_eq!;
// Now let's attach each instant to an `America/New_York` time zone.
let zdt_before = before_hour_jump.in_tz?;
let zdt_after = after_hour_jump.in_tz?;
// And now we can see that even though the original instant refers to
// the 2 o'clock hour, since that hour never existed on the clocks in
// `America/New_York`, an instant with a time zone correctly adjusts.
assert_eq!;
assert_eq!;
# Ok::
In the example above, there is never a step that is incorrect or has an
alternative answer. Every step is unambiguous because we never involve
any civil datetimes.
But note that if the datetime string you're parsing from lacks an offset, then it could be ambiguous even if a time zone is specified. In this case, parsing will always fail:
use Timestamp;
let result = "2024-06-30 08:30[America/New_York]".;
assert_eq!;
Converting a civil datetime to a timestamp
Sometimes you want to convert the "time on the clock" to a precise instant in time. One way to do this was demonstrated in the previous section, but it only works if you know your current time zone offset:
use Timestamp;
let ts: Timestamp = "2024-06-30 08:36-04".parse?;
assert_eq!;
# Ok::
The above happened to be the precise instant in time I wrote the example.
Since I happened to know the offset, this worked okay. But what if I
didn't? We could instead construct a civil datetime and attach a time zone
to it. This will create a Zoned value, from which we can access the
timestamp:
use date;
let clock = date.at.in_tz?;
assert_eq!;
# Ok::
Implementations
impl Timestamp
fn now() -> TimestampReturns the current system time as a timestamp.
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
Timestamp::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 Timestamp; assert!;fn new(second: i64, nanosecond: i32) -> Result<Timestamp, Error>Creates a new instant in time represented as a timestamp.
While a timestamp is logically a count of nanoseconds since the Unix epoch, this constructor provides a convenience way of constructing the timestamp from two components: seconds and fractional seconds expressed as nanoseconds.
The signs of
secondandnanosecondneed not be the same.Errors
This returns an error if the given components would correspond to an instant outside the supported range. Also,
nanosecondis limited to the range-999,999,999..=999,999,999.Example
This example shows the instant in time 123,456,789 seconds after the Unix epoch:
use Timestamp; assert_eq!; # Ok::Example: normalized sign
This example shows how
secondandnanosecondare resolved when their signs differ.use Timestamp; let ts = new?; assert_eq!; assert_eq!; let ts = new?; assert_eq!; assert_eq!; # Ok::Example: limits
The minimum timestamp has nanoseconds set to zero, while the maximum timestamp has nanoseconds set to
999,999,999:use Timestamp; assert_eq!; assert_eq!;As a consequence, nanoseconds cannot be negative when a timestamp has minimal seconds:
use Timestamp; assert!; // But they can be positive! let one_ns_more = new?; assert_eq!; // Or, when combined with a minimal offset: assert_eq!; # Ok::const fn constant(second: i64, nanosecond: i32) -> TimestampCreates a new
Timestampvalue in aconstcontext.Panics
This routine panics when
Timestamp::newwould return an error. That is, when the given components would correspond to an instant outside the supported range. Also,nanosecondis limited to the range-999,999,999..=999,999,999.Example
This example shows the instant in time 123,456,789 seconds after the Unix epoch:
use Timestamp; assert_eq!;fn from_second(second: i64) -> Result<Timestamp, Error>Creates a new instant in time from the number of seconds elapsed since the Unix epoch.
When
secondis negative, it corresponds to an instant in time before the Unix epoch. A smaller number corresponds to an instant in time further into the past.Errors
This returns an error if the given second corresponds to a timestamp outside of the
Timestamp::MINandTimestamp::MAXboundaries.Example
This example shows the instants in time 1 second immediately after and before the Unix epoch:
use Timestamp; assert_eq!; assert_eq!; # Ok::fn from_millisecond(millisecond: i64) -> Result<Timestamp, Error>Creates a new instant in time from the number of milliseconds elapsed since the Unix epoch.
When
millisecondis negative, it corresponds to an instant in time before the Unix epoch. A smaller number corresponds to an instant in time further into the past.Errors
This returns an error if the given millisecond corresponds to a timestamp outside of the
Timestamp::MINandTimestamp::MAXboundaries.Example
This example shows the instants in time 1 millisecond immediately after and before the Unix epoch:
use Timestamp; assert_eq!; assert_eq!; # Ok::fn from_microsecond(microsecond: i64) -> Result<Timestamp, Error>Creates a new instant in time from the number of microseconds elapsed since the Unix epoch.
When
microsecondis negative, it corresponds to an instant in time before the Unix epoch. A smaller number corresponds to an instant in time further into the past.Errors
This returns an error if the given microsecond corresponds to a timestamp outside of the
Timestamp::MINandTimestamp::MAXboundaries.Example
This example shows the instants in time 1 microsecond immediately after and before the Unix epoch:
use Timestamp; assert_eq!; assert_eq!; # Ok::fn from_nanosecond(nanosecond: i128) -> Result<Timestamp, Error>Creates a new instant in time from the number of nanoseconds elapsed since the Unix epoch.
When
nanosecondis negative, it corresponds to an instant in time before the Unix epoch. A smaller number corresponds to an instant in time further into the past.Errors
This returns an error if the given nanosecond corresponds to a timestamp outside of the
Timestamp::MINandTimestamp::MAXboundaries.Example
This example shows the instants in time 1 nanosecond immediately after and before the Unix epoch:
use Timestamp; assert_eq!; assert_eq!; # Ok::fn from_duration(duration: SignedDuration) -> Result<Timestamp, Error>Creates a new timestamp from a
Durationwith the given sign since the Unix epoch.Positive durations result in a timestamp after the Unix epoch. Negative durations result in a timestamp before the Unix epoch.
Errors
This returns an error if the given duration corresponds to a timestamp outside of the
Timestamp::MINandTimestamp::MAXboundaries.Example
How one might construct a
Timestampfrom aSystemTime:use SystemTime; use ; let unix_epoch = UNIX_EPOCH; let now = now; let duration = system_until?; let ts = from_duration?; assert!; # Ok::Of course, one should just use
Timestamp::try_fromfor this instead. Indeed, the above example is copied almost exactly from theTryFromimplementation.Example: out of bounds
This example shows how some of the boundary conditions are dealt with.
use ; // OK, we get the minimum timestamp supported by Jiff: let duration = new; let ts = from_duration?; assert_eq!; // We use the minimum number of seconds, but even subtracting // one more nanosecond after it will result in an error. let duration = new; assert_eq!; # Ok::fn as_second(self: Self) -> i64Returns this timestamp as a number of seconds since the Unix epoch.
This only returns the number of whole seconds. That is, if there are any fractional seconds in this timestamp, then they are truncated.
Example
use Timestamp; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; # Ok::fn as_millisecond(self: Self) -> i64Returns this timestamp as a number of milliseconds since the Unix epoch.
This only returns the number of whole milliseconds. That is, if there are any fractional milliseconds in this timestamp, then they are truncated.
Example
use Timestamp; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; # Ok::fn as_microsecond(self: Self) -> i64Returns this timestamp as a number of microseconds since the Unix epoch.
This only returns the number of whole microseconds. That is, if there are any fractional microseconds in this timestamp, then they are truncated.
Example
use Timestamp; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; # Ok::fn as_nanosecond(self: Self) -> i128Returns this timestamp as a number of nanoseconds since the Unix epoch.
Since a
Timestamphas a nanosecond precision, the nanoseconds returned here represent this timestamp losslessly. That is, the nanoseconds returned can be used withTimestamp::from_nanosecondto create an identical timestamp with no loss of precision.Example
use Timestamp; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; # Ok::fn subsec_millisecond(self: Self) -> i32Returns the fractional second component of this timestamp in units of milliseconds.
It is guaranteed that this will never return a value that is greater than 1 second (or less than -1 second).
This only returns the number of whole milliseconds. That is, if there are any fractional milliseconds in this timestamp, then they are truncated.
Example
use Timestamp; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; # Ok::fn subsec_microsecond(self: Self) -> i32Returns the fractional second component of this timestamp in units of microseconds.
It is guaranteed that this will never return a value that is greater than 1 second (or less than -1 second).
This only returns the number of whole microseconds. That is, if there are any fractional microseconds in this timestamp, then they are truncated.
Example
use Timestamp; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; # Ok::fn subsec_nanosecond(self: Self) -> i32Returns the fractional second component of this timestamp in units of nanoseconds.
It is guaranteed that this will never return a value that is greater than 1 second (or less than -1 second).
Example
use Timestamp; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; let ts = new?; assert_eq!; # Ok::fn as_duration(self: Self) -> SignedDurationReturns this timestamp as a
SignedDurationsince the Unix epoch.Example
use ; assert_eq!; assert_eq!; assert_eq!; # Ok::fn signum(self: Self) -> i8Returns the sign of this timestamp.
This can return one of three possible values:
0when this timestamp is precisely equivalent toTimestamp::UNIX_EPOCH.1when this timestamp occurs after the Unix epoch.-1when this timestamp occurs before the Unix epoch.
The sign returned is guaranteed to match the sign of all "getter" methods on
Timestamp. For example,Timestamp::as_secondandTimestamp::subsec_nanosecond. This is true even if the signs of thesecondandnanosecondcomponents were mixed when given to theTimestamp::newconstructor.Example
use Timestamp; let ts = new?; assert_eq!; // The mixed signs were normalized away! assert_eq!; assert_eq!; // The same applies for negative timestamps. let ts = new?; assert_eq!; assert_eq!; assert_eq!; # Ok::fn is_zero(self: Self) -> boolReturns true if and only if this timestamp corresponds to the instant in time known as the Unix epoch.
Example
use Timestamp; assert!;fn in_tz(self: Self, time_zone_name: &str) -> Result<Zoned, Error>Creates a
Zonedvalue by attaching a time zone for the given name to this instant in time.The name given is resolved to a
TimeZoneby using the defaultTimeZoneDatabasecreated bytz::db. Indeed, this is a convenience function forTimestamp::to_zonedwhere the time zone database lookup is done automatically.Assuming the time zone name could be resolved to a
TimeZone, this routine is otherwise infallible and never results in any ambiguity since both aTimestampand aZonedcorrespond to precise instant in time. This is unlikecivil::DateTime::to_zoned, where a civil datetime might correspond to more than one instant in time (i.e., a fold, typically DST ending) or no instants in time (i.e., a gap, typically DST starting).Errors
This returns an error when the given time zone name could not be found in the default time zone database.
Example
This is a simple example of converting the instant that is
123,456,789seconds after the Unix epoch to an instant that is aware of its time zone:use Timestamp; let ts = new.unwrap; let zdt = ts.in_tz?; assert_eq!; # Ok::This can be used to answer questions like, "What time was it at the Unix epoch in Tasmania?"
use Timestamp; // Time zone database lookups are case insensitive! let zdt = UNIX_EPOCH.in_tz?; assert_eq!; # Ok::Example: errors
This routine can return an error when the time zone is unrecognized:
use Timestamp; assert!;fn to_zoned(self: Self, tz: TimeZone) -> ZonedCreates a
Zonedvalue by attaching the given time zone to this instant in time.This is infallible and never results in any ambiguity since both a
Timestampand aZonedcorrespond to precise instant in time. This is unlikecivil::DateTime::to_zoned, where a civil datetime might correspond to more than one instant in time (i.e., a fold, typically DST ending) or no instants in time (i.e., a gap, typically DST starting).In the common case of a time zone being represented as a name string, like
Australia/Tasmania, consider usingTimestamp::in_tzinstead.Example
This example shows how to create a zoned value with a fixed time zone offset:
use ; let ts = new.unwrap; let tz = fixed; let zdt = ts.to_zoned; // A time zone annotation is still included in the printable version // of the Zoned value, but it is fixed to a particular offset. assert_eq!;Example: POSIX time zone strings
This example shows how to create a time zone from a POSIX time zone string that describes the transition to and from daylight saving time for
America/St_Johns. In particular, this rule uses non-zero minutes, which is atypical.use ; let ts = new?; let tz = posix?; let zdt = ts.to_zoned; // There isn't any agreed upon mechanism for transmitting a POSIX time // zone string within an RFC 9557 TZ annotation, so Jiff just emits the // offset. In practice, POSIX TZ strings are rarely user facing anyway. // (They are still in widespread use as an implementation detail of the // IANA Time Zone Database however.) assert_eq!; # Ok::fn checked_add<A: Into<TimestampArithmetic>>(self: Self, duration: A) -> Result<Timestamp, Error>Add the given span of time to this timestamp.
This operation accepts three different duration types:
Span,SignedDurationorstd::time::Duration. This is achieved viaFromtrait implementations for theTimestampArithmetictype.Properties
Given a timestamp
ts1and a spans, and assumingts2 = ts1 + sexists, it follows then thatts1 = ts2 - sfor all values ofts1andsthat sum to a validts2.In short, subtracting the given span from the sum returned by this function is guaranteed to result in precisely the original timestamp.
Errors
If the sum would overflow the minimum or maximum timestamp values, then an error is returned.
This also returns an error if the given duration is a
Spanwith any non-zero units greater than hours. If you want to use bigger units, convert this timestamp to aZonedand useZoned::checked_add. This error occurs because aTimestamphas no time zone attached to it, and thus cannot unambiguously resolve the length of a single day.Example
This shows how to add
5hours to the Unix epoch:use ; let ts = UNIX_EPOCH.checked_add?; assert_eq!; # Ok::Example: negative spans are supported
This shows how to add
-5hours to the Unix epoch. This is the same as subtracting5hours from the Unix epoch.use ; let ts = UNIX_EPOCH.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.use ; let ts1 = new?; assert_eq!; let ts2 = ts1 + 1.hour.minutes.nanoseconds; assert_eq!; # Ok::Example: error on overflow
use ; let ts = MAX; assert_eq!; assert!; let ts = MIN; assert_eq!; assert!;Example: adding absolute durations
This shows how to add signed and unsigned absolute durations to a
Timestamp.use Duration; use ; let ts1 = new?; assert_eq!; let dur = new; assert_eq!; let dur = new; assert_eq!; # Ok::fn checked_sub<A: Into<TimestampArithmetic>>(self: Self, duration: A) -> Result<Timestamp, Error>This routine is identical to
Timestamp::checked_addwith the duration negated.Errors
This has the same error conditions as
Timestamp::checked_add.Example
This routine can be used via the
-operator. Note though that if it fails, it will result in a panic.use ; let ts1 = new?; assert_eq!; let ts2 = ts1 - 1.hour.minutes.nanoseconds; assert_eq!; # Ok::Example: use with
SignedDurationandstd::time::Durationuse Duration; use ; let ts1 = new?; assert_eq!; let dur = new; assert_eq!; let dur = new; assert_eq!; # Ok::fn saturating_add<A: Into<TimestampArithmetic>>(self: Self, duration: A) -> Result<Timestamp, Error>This routine is identical to
Timestamp::checked_add, except the result saturates on overflow. That is, instead of overflow, eitherTimestamp::MINorTimestamp::MAXis returned.Errors
This returns an error if the given
Spancontains any non-zero units greater than hours.Example
This example shows that arithmetic saturates on overflow.
use ; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn saturating_sub<A: Into<TimestampArithmetic>>(self: Self, duration: A) -> Result<Timestamp, Error>This routine is identical to
Timestamp::saturating_addwith the span parameter negated.Errors
This returns an error if the given
Spancontains any non-zero units greater than hours.Example
This example shows that arithmetic saturates on overflow.
use ; assert_eq!; assert_eq!; assert_eq!; assert_eq!; assert_eq!; # Ok::fn until<A: Into<TimestampDifference>>(self: Self, other: A) -> Result<Span, Error>Returns a span representing the elapsed time from this timestamp until the given
othertimestamp.When
otheroccurs before this timestamp, 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 seconds.
This operation is configured by providing a
TimestampDifferencevalue. Since this routine accepts anything that implementsInto<TimestampDifference>, once can pass aTimestampdirectly. One can also pass a(Unit, Timestamp), whereUnitis treated asTimestampDifference::largest.Properties
It is guaranteed that if the returned span is subtracted from
other, and if no rounding is requested, then the original timestamp 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 timestamps 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
TimestampDifferenceis misconfigured. For example, if the smallest unit provided is bigger than the largest unit, or if the largest unit provided is bigger than hours. (To use bigger units with an instant in time, useZoned::untilinstead.)It is guaranteed that if one provides a timestamp with the default
TimestampDifferenceconfiguration, then this routine will never fail.Example
use ; let earlier: Timestamp = "2006-08-24T22:30:00Z".parse?; let later: Timestamp = "2019-01-31 21:00:00Z".parse?; assert_eq!; // Flipping the timestamps 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, Timestamp)> for TimestampDifferencetrait implementation.use ; let ts1: Timestamp = "1995-12-07T03:24:30.000003500Z".parse?; let ts2: Timestamp = "2019-01-31 15:30:00Z".parse?; // The default limits durations to using "seconds" as the biggest unit. let span = ts1.until?; assert_eq!; // But we can ask for units all the way up to hours. let span = ts1.until?; assert_eq!; # Ok::Example: rounding the result
This shows how one might find the difference between two timestamps and have the result rounded such that sub-seconds are removed.
In this case, we need to hand-construct a
TimestampDifferencein order to gain full configurability.use ; let ts1: Timestamp = "1995-12-07 03:24:30.000003500Z".parse?; let ts2: Timestamp = "2019-01-31 15:30:00Z".parse?; let span = ts1.until?; assert_eq!; // We can combine smallest and largest units too! let span = ts1.until?; assert_eq!; # Ok::fn since<A: Into<TimestampDifference>>(self: Self, other: A) -> Result<Span, Error>This routine is identical to
Timestamp::until, but the order of the parameters is flipped.Errors
This has the same error conditions as
Timestamp::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 timestamps, it will never panic.use ; let earlier: Timestamp = "2006-08-24T22:30:00Z".parse?; let later: Timestamp = "2019-01-31 21:00:00Z".parse?; assert_eq!; # Ok::fn duration_until(self: Self, other: Timestamp) -> SignedDurationReturns an absolute duration representing the elapsed time from this timestamp until the given
othertimestamp.When
otheroccurs before this timestamp, then the duration returned will be negative.Unlike
Timestamp::until, this always returns a duration corresponding to a 96-bit integer of nanoseconds between two timestamps.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,
Timestamp::untilcan return an error in some cases due to misconfiguration. But like this routine,Timestamp::untilnever panics or returns an error in its default configuration.When should I use this versus
Timestamp::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: Timestamp = "2006-08-24T22:30:00Z".parse?; let later: Timestamp = "2019-01-31 21:00:00Z".parse?; assert_eq!; // Flipping the timestamps is fine, but you'll get a negative span. assert_eq!; # Ok::Example: difference with
Timestamp::untilThe primary difference between this routine and
Timestamp::until, other than the return type, is that this routine is likely to be faster. Namely, it does simple 96-bit integer math, where asTimestamp::untilhas to do a bit more work to deal with the different types of units on aSpan.Additionally, since the difference between two timestamps is always expressed in units of hours or smaller, and units of hours or smaller are always uniform, there is no "expressive" difference between this routine and
Timestamp::until. Because of this, one can always convert betweenSpanandSignedDurationas returned by methods onTimestampwithout a relative datetime:use ; let ts1: Timestamp = "2024-02-28T00:00:00Z".parse?; let ts2: Timestamp = "2024-03-01T00:00:00Z".parse?; let dur = ts1.duration_until; // Guaranteed to never fail because the duration // between two civil times never exceeds the limits // of a `Span`. let span = try_from.unwrap; assert_eq!; // Guaranteed to succeed and always return the original // duration because the units are always hours or smaller, // and thus uniform. This means a relative datetime is // never required to do this conversion. let dur = try_from.unwrap; assert_eq!; # Ok::This conversion guarantee also applies to
Timestamp::untilsince it always returns a balanced span. That is, it never returns spans like1 second 1000 milliseconds. (Those cannot be losslessly converted to aSignedDurationsince aSignedDurationis only represented as a single 96-bit integer of nanoseconds.)fn duration_since(self: Self, other: Timestamp) -> SignedDurationThis routine is identical to
Timestamp::duration_until, but the order of the parameters is flipped.Example
use ; let earlier: Timestamp = "2006-08-24T22:30:00Z".parse?; let later: Timestamp = "2019-01-31 21:00:00Z".parse?; assert_eq!; # Ok::fn round<R: Into<TimestampRound>>(self: Self, options: R) -> Result<Timestamp, Error>Rounds this timestamp according to the
TimestampRoundconfiguration given.The principal option is
TimestampRound::smallest, which allows one to configure the smallest units in the returned timestamp. Rounding is what determines whether the specified smallest unit should keep its current value or whether it should be incremented. Moreover, the amount it should be incremented can be configured viaTimestampRound::increment. Finally, the rounding strategy itself can be configured viaTimestampRound::mode.Note that this routine is generic and accepts anything that implements
Into<TimestampRound>. Some notable implementations are:From<Unit> for TimestampRound, which will automatically create aTimestampRound::new().smallest(unit)from the unit provided.From<(Unit, i64)> for TimestampRound, which will automatically create aTimestampRound::new().smallest(unit).increment(number)from the unit and increment provided.
Errors
This returns an error if the smallest unit configured on the given
TimestampRoundis bigger than hours.The rounding increment, when combined with the smallest unit (which defaults to
Unit::Nanosecond), must divide evenly into86,400seconds (one 24-hour civil day). For example, increments of both 45 seconds and 15 minutes are allowed, but 7 seconds and 25 minutes are both not allowed.Example
This is a basic example that demonstrates rounding a timestamp to the nearest hour. This also demonstrates calling this method with the smallest unit directly, instead of constructing a
TimestampRoundmanually.use ; let ts: Timestamp = "2024-06-19 15:30:00Z".parse?; assert_eq!; let ts: Timestamp = "2024-06-19 15:29:59Z".parse?; 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 ; // The default will round up to the next hour for any time past the // 30 minute mark, but using truncation rounding will always round // down. let ts: Timestamp = "2024-06-19 15:30:00Z".parse?; assert_eq!; # Ok::Example: rounding to the nearest 5 minute increment
use ; // rounds down let ts: Timestamp = "2024-06-19T15:27:29.999999999Z".parse?; assert_eq!; // rounds up let ts: Timestamp = "2024-06-19T15:27:30Z".parse?; assert_eq!; # Ok::fn series(self: Self, period: Span) -> TimestampSeriesReturn an iterator of periodic timestamps determined by the given span.
The given span may be negative, in which case, the iterator will move backwards through time. The iterator won't stop until either the span itself overflows, or it would otherwise exceed the minimum or maximum
Timestampvalue.Example: when to check a glucose monitor
When my cat had diabetes, my veterinarian installed a glucose monitor and instructed me to scan it about every 5 hours. This example lists all of the times I need to scan it for the 2 days following its installation:
use ; let start: Timestamp = "2023-07-15 16:30:00-04".parse?; let end = start.checked_add?; let mut scan_times = vec!; for ts in start.series.take_while assert_eq!; # Ok::
impl Timestamp
fn strptime<impl AsRef<[u8]>: AsRef<[u8]>, impl AsRef<[u8]>: AsRef<[u8]>>(format: impl AsRef<[u8]>, input: impl AsRef<[u8]>) -> Result<Timestamp, Error>Parses a timestamp (expressed as broken down time) 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.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 timestamp. For example, if an offset wasn't parsed. (The offset is needed to turn the civil time parsed into a precise instant in time.)
Example
This example shows how to parse a datetime string into a timestamp:
use Timestamp; let ts = strptime?; assert_eq!; # Ok::fn strftime<'f, F: 'f + ?Sized + AsRef<[u8]>>(self: &Self, format: &'f F) -> Display<'f>Formats this timestamp 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.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
This shows how to format a timestamp into a human readable datetime in UTC:
use ; let ts = from_second?; let string = ts.strftime.to_string; assert_eq!; # Ok::fn display_with_offset(self: &Self, offset: Offset) -> TimestampDisplayWithOffsetFormat a
Timestampdatetime into a string with the given offset.This will format to an RFC 3339 compatible string with an offset.
This will never use either
Z(for Zulu time) or-00:00as an offset. This is because Zulu time (and-00:00) mean "the time in UTC is known, but the offset to local time is unknown." Since this routine accepts an explicit offset, the offset is known. For example,Offset::UTCwill be formatted as+00:00.To format an RFC 3339 string in Zulu time, use the default
std::fmt::Displaytrait implementation onTimestamp.Example
use ; let ts = from_second?; assert_eq!; # Ok::
impl Add for Timestamp
fn add(self: Self, rhs: UnsignedDuration) -> Timestamp
impl Add for Timestamp
fn add(self: Self, rhs: SignedDuration) -> Timestamp
impl Add for Timestamp
fn add(self: Self, rhs: Span) -> Timestamp
impl AddAssign for Timestamp
fn add_assign(self: &mut Self, rhs: Span)
impl AddAssign for Timestamp
fn add_assign(self: &mut Self, rhs: UnsignedDuration)
impl AddAssign for Timestamp
fn add_assign(self: &mut Self, rhs: SignedDuration)
impl Clone for Timestamp
fn clone(self: &Self) -> Timestamp
impl Copy for Timestamp
impl Debug for Timestamp
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl Default for Timestamp
fn default() -> Timestamp
impl Display for Timestamp
fn fmt(self: &Self, f: &mut Formatter<'_>) -> Result
impl Eq for Timestamp
impl Freeze for Timestamp
impl From for Timestamp
fn from(zdt: Zoned) -> Timestamp
impl FromStr for Timestamp
fn from_str(string: &str) -> Result<Timestamp, Error>
impl Hash for Timestamp
fn hash<H: core::hash::Hasher>(self: &Self, state: &mut H)
impl Ord for Timestamp
fn cmp(self: &Self, rhs: &Timestamp) -> Ordering
impl PartialEq for Timestamp
fn eq(self: &Self, rhs: &Timestamp) -> bool
impl PartialOrd for Timestamp
fn partial_cmp(self: &Self, rhs: &Timestamp) -> Option<Ordering>
impl RefUnwindSafe for Timestamp
impl Send for Timestamp
impl Serialize for Timestamp
fn serialize<S: serde::Serializer>(self: &Self, serializer: S) -> Result<<S as >::Ok, <S as >::Error>
impl Sub for Timestamp
fn sub(self: Self, rhs: UnsignedDuration) -> Timestamp
impl Sub for Timestamp
fn sub(self: Self, rhs: SignedDuration) -> Timestamp
impl Sub for Timestamp
fn sub(self: Self, rhs: Timestamp) -> Span
impl Sub for Timestamp
fn sub(self: Self, rhs: Span) -> Timestamp
impl SubAssign for Timestamp
fn sub_assign(self: &mut Self, rhs: Span)
impl SubAssign for Timestamp
fn sub_assign(self: &mut Self, rhs: UnsignedDuration)
impl SubAssign for Timestamp
fn sub_assign(self: &mut Self, rhs: SignedDuration)
impl Sync for Timestamp
impl TryFrom for Timestamp
fn try_from(system_time: SystemTime) -> Result<Timestamp, Error>
impl Unpin for Timestamp
impl UnsafeUnpin for Timestamp
impl UnwindSafe for Timestamp
impl<'a> From for Timestamp
fn from(zdt: &'a Zoned) -> Timestamp
impl<'de> Deserialize for Timestamp
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Timestamp, <D as >::Error>
impl<T> Any for Timestamp
fn type_id(self: &Self) -> TypeId
impl<T> Borrow for Timestamp
fn borrow(self: &Self) -> &T
impl<T> BorrowMut for Timestamp
fn borrow_mut(self: &mut Self) -> &mut T
impl<T> CloneToUninit for Timestamp
unsafe fn clone_to_uninit(self: &Self, dest: *mut u8)
impl<T> DeserializeOwned for Timestamp
impl<T> From for Timestamp
fn from(t: T) -> TReturns the argument unchanged.
impl<T> ToOwned for Timestamp
fn to_owned(self: &Self) -> Tfn clone_into(self: &Self, target: &mut T)
impl<T> ToString for Timestamp
fn to_string(self: &Self) -> String
impl<T, U> Into for Timestamp
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 Timestamp
fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
impl<T, U> TryInto for Timestamp
fn try_into(self: Self) -> Result<U, <U as TryFrom<T>>::Error>