Struct TimeZoneDatabase
pub struct TimeZoneDatabase { /* private fields */ }
dep_jiff
and alloc
only.Expand description
A handle to a IANA Time Zone Database.
A TimeZoneDatabase
provides a way to lookup TimeZone
s by their
human readable identifiers, such as America/Los_Angeles
and
Europe/Warsaw
.
It is rare to need to create or use this type directly. Routines
like zoned datetime parsing and time zone conversion provide
convenience routines for using an implicit global time zone database
by default. This global time zone database is available via
jiff::tz::db
. But lower level parsing routines
such as
fmt::temporal::DateTimeParser::parse_zoned_with
and
civil::DateTime::to_zoned
provide a
means to use a custom copy of a TimeZoneDatabase
.
§Platform behavior
This behavior is subject to change.
On Unix systems, and when the tzdb-zoneinfo
crate feature is enabled
(which it is by default), Jiff will read the /usr/share/zoneinfo
directory for time zone data.
On Windows systems and when the tzdb-bundle-platform
crate feature is
enabled (which it is by default), or when the tzdb-bundle-always
crate
feature is enabled, then the jiff-tzdb
crate will be used to embed the
entire Time Zone Database into the compiled artifact.
In general, using /usr/share/zoneinfo
(or an equivalent) is heavily
preferred in lieu of embedding the database into your compiled artifact.
The reason is because your system copy of the Time Zone Database may be
updated, perhaps a few times a year, and it is better to get seamless
updates through your system rather than needing to wait on a Rust crate
to update and then rebuild your software. The bundling approach should
only be used when there is no plausible alternative. For example, Windows
has no canonical location for a copy of the Time Zone Database. Indeed,
this is why the Cargo configuration of Jiff specifically does not enabled
bundling by default on Unix systems, but does enable it by default on
Windows systems. Of course, if you really do need a copy of the database
bundled, then you can enable the tzdb-bundle-always
crate feature.
§Cloning
A TimeZoneDatabase
can be cheaply cloned. It will share a thread safe
cache with other copies of the same TimeZoneDatabase
.
§Caching
Because looking up a time zone on disk, reading the file into memory
and parsing the time zone transitions out of that file requires
a fair amount of work, a TimeZoneDatabase
does a fair bit of
caching. This means that the vast majority of calls to, for example,
Timestamp::intz
don’t actually need to hit
disk. It will just find a cached copy of a TimeZone
and return that.
Of course, with caching comes problems of cache invalidation. Invariably,
there are parameters that Jiff uses to manage when the cache should be
invalidated. Jiff tries to emit log messages about this when it happens. If
you find the caching behavior of Jiff to be sub-optimal for your use case,
please create an issue. (The plan is likely to expose some options for
configuring the behavior of a TimeZoneDatabase
, but I wanted to collect
user feedback first.)
§Example: list all available time zones
use jiff::tz;
for tzid in tz::db().available() {
println!("{tzid}");
}
§Example: using multiple time zone databases
Jiff supports opening and using multiple time zone databases by default.
All you need to do is point TimeZoneDatabase::from_dir
to your own
copy of the Time Zone Database, and it will handle the rest.
This example shows how to utilize multiple databases by parsing a datetime using an older copy of the IANA Time Zone Database. This example leverages the fact that the 2018 copy of the database preceded Brazil’s announcement that daylight saving time would be abolished. This meant that datetimes in the future, when parsed with the older copy of the Time Zone Database, would still follow the old daylight saving time rules. But a mere update of the database would otherwise change the meaning of the datetime.
This scenario can come up if one stores datetimes in the future. This is
also why the default offset conflict resolution strategy when parsing zoned
datetimes is OffsetConflict::Reject
,
which prevents one from silently re-interpreting datetimes to a different
timestamp.
use jiff::{fmt::temporal::DateTimeParser, tz::{self, TimeZoneDatabase}};
static PARSER: DateTimeParser = DateTimeParser::new();
// Open a version of tzdb from before Brazil announced its abolition
// of daylight saving time.
let tzdb2018 = TimeZoneDatabase::from_dir("path/to/tzdb-2018b")?;
// Open the system tzdb.
let tzdb = tz::db();
// Parse the same datetime string with the same parser, but using two
// different versions of tzdb.
let dt = "2020-01-15T12:00[America/Sao_Paulo]";
let zdt2018 = PARSER.parse_zoned_with(&tzdb2018, dt)?;
let zdt = PARSER.parse_zoned_with(tzdb, dt)?;
// Before DST was abolished, 2020-01-15 was in DST, which corresponded
// to UTC offset -02. Since DST rules applied to datetimes in the
// future, the 2018 version of tzdb would lead one to interpret
// 2020-01-15 as being in DST.
assert_eq!(zdt2018.offset(), tz::offset(-2));
// But DST was abolished in 2019, which means that 2020-01-15 was no
// no longer in DST. So after a tzdb update, the same datetime as above
// now has a different offset.
assert_eq!(zdt.offset(), tz::offset(-3));
// So if you try to parse a datetime serialized from an older copy of
// tzdb, you'll get an error under the default configuration because
// of `OffsetConflict::Reject`. This would succeed if you parsed it
// using tzdb2018!
assert!(PARSER.parse_zoned_with(tzdb, zdt2018.to_string()).is_err());
Implementations§
§impl TimeZoneDatabase
impl TimeZoneDatabase
pub const fn none() -> TimeZoneDatabase
pub const fn none() -> TimeZoneDatabase
Returns a database for which all time zone lookups fail.
§Example
use jiff::tz::TimeZoneDatabase;
let db = TimeZoneDatabase::none();
assert_eq!(db.available().count(), 0);
pub fn from_env() -> TimeZoneDatabase
pub fn from_env() -> TimeZoneDatabase
Returns a time zone database initialized from the current environment.
This routine never fails, but it may not be able to find a copy of
your Time Zone Database. When this happens, log messages (with some
at least at the WARN
level) will be emitted. They can be viewed by
installing a log
compatible logger such as env_logger
.
Typically, one does not need to call this routine directly. Instead,
it’s done for you as part of jiff::tz::db
.
This does require Jiff’s std
feature to be enabled though. So for
example, you might use this constructor when the features alloc
and tzdb-bundle-always
are enabled to get access to a bundled
copy of the IANA time zone database. (Accessing the system copy at
/usr/share/zoneinfo
requires std
.)
Beware that calling this constructor will create a new distinct
handle from the one returned by jiff::tz::db
with its own cache.
§Platform behavior
When the TZDIR
environment variable is set, this will attempt to
open the Time Zone Database at the directory specified. Otherwise,
this will search a list of predefined directories for a system
installation of the Time Zone Database. Typically, it’s found at
/usr/share/zoneinfo
.
On Windows systems, under the default crate configuration, this will return an embedded copy of the Time Zone Database since Windows does not have a canonical installation of the Time Zone Database.
pub fn from_dir<P>(path: P) -> Result<TimeZoneDatabase, Error> ⓘ
pub fn from_dir<P>(path: P) -> Result<TimeZoneDatabase, Error> ⓘ
Returns a time zone database initialized from the given directory.
Unlike TimeZoneDatabase::from_env
, this always attempts to look for
a copy of the Time Zone Database at the directory given. And if it
fails to find one at that directory, then an error is returned.
Basically, you should use this when you need to use a specific
copy of the Time Zone Database, and use TimeZoneDatabase::from_env
when you just want Jiff to try and “do the right thing for you.”
§Errors
This returns an error if the given directory does not contain a valid copy of the Time Zone Database. Generally, this means a directory with at least one valid TZif file.
pub fn from_concatenated_path<P>(path: P) -> Result<TimeZoneDatabase, Error> ⓘ
pub fn from_concatenated_path<P>(path: P) -> Result<TimeZoneDatabase, Error> ⓘ
Returns a time zone database initialized from a path pointing to a
concatenated tzdata
file. This type of format is only known to be
found on Android environments. The specific format for this file isn’t
defined formally anywhere, but Jiff parses the same format supported
by the Android Platform.
Unlike TimeZoneDatabase::from_env
, this always attempts to look for
a copy of the Time Zone Database at the path given. And if it
fails to find one at that path, then an error is returned.
Basically, you should use this when you need to use a specific
copy of the Time Zone Database in its concatenated format, and use
TimeZoneDatabase::from_env
when you just want Jiff to try and “do the
right thing for you.” (TimeZoneDatabase::from_env
will attempt to
automatically detect the presence of a system concatenated tzdata
file on Android.)
§Errors
This returns an error if the given path does not contain a valid copy of the concatenated Time Zone Database.
pub fn get(&self, name: &str) -> Result<TimeZone, Error> ⓘ
pub fn get(&self, name: &str) -> Result<TimeZone, Error> ⓘ
Returns a TimeZone
corresponding to the IANA time zone identifier
given.
The lookup is performed without regard to ASCII case.
To see a list of all available time zone identifiers for this database,
use TimeZoneDatabase::available
.
§Example
use jiff::tz;
let tz = tz::db().get("america/NEW_YORK")?;
assert_eq!(tz.iana_name(), Some("America/New_York"));
pub fn available(&self) -> TimeZoneNameIter ⓘ
pub fn available(&self) -> TimeZoneNameIter ⓘ
Returns a list of all available time zone identifiers from this database.
Note that time zone identifiers are more of a machine readable abstraction and not an end user level abstraction. Still, users comfortable with configuring their system’s default time zone through IANA time zone identifiers are probably comfortable interacting with the identifiers returned here.
§Example
use jiff::tz;
for tzid in tz::db().available() {
println!("{tzid}");
}
pub fn reset(&self)
pub fn reset(&self)
Resets the internal cache of this database.
Subsequent interactions with this database will need to re-read time zone data from disk.
It might be useful to call this if you know the time zone database has changed on disk and want to force Jiff to re-load it immediately without spawning a new process or waiting for Jiff’s internal cache invalidation heuristics to kick in.
pub fn is_definitively_empty(&self) -> bool
pub fn is_definitively_empty(&self) -> bool
Returns true if it is known that this time zone database is empty.
When this returns true, it is guaranteed that all
TimeZoneDatabase::get
calls will fail, and that
TimeZoneDatabase::available
will always return an empty iterator.
Note that if this returns false, it is still possible for this database to be empty.
§Example
use jiff::tz::TimeZoneDatabase;
let db = TimeZoneDatabase::none();
assert!(db.is_definitively_empty());
Trait Implementations§
§impl Clone for TimeZoneDatabase
impl Clone for TimeZoneDatabase
§fn clone(&self) -> TimeZoneDatabase
fn clone(&self) -> TimeZoneDatabase
1.0.0 · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moreAuto Trait Implementations§
impl Freeze for TimeZoneDatabase
impl RefUnwindSafe for TimeZoneDatabase
impl Send for TimeZoneDatabase
impl Sync for TimeZoneDatabase
impl Unpin for TimeZoneDatabase
impl UnwindSafe for TimeZoneDatabase
Blanket Implementations§
§impl<T> ArchivePointee for T
impl<T> ArchivePointee for T
§type ArchivedMetadata = ()
type ArchivedMetadata = ()
§fn pointer_metadata(
_: &<T as ArchivePointee>::ArchivedMetadata,
) -> <T as Pointee>::Metadata
fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> ByteSized for T
impl<T> ByteSized for T
Source§const BYTE_ALIGN: usize = _
const BYTE_ALIGN: usize = _
Source§fn byte_align(&self) -> usize ⓘ
fn byte_align(&self) -> usize ⓘ
Source§fn ptr_size_ratio(&self) -> [usize; 2]
fn ptr_size_ratio(&self) -> [usize; 2]
Source§impl<T, R> Chain<R> for Twhere
T: ?Sized,
impl<T, R> Chain<R> for Twhere
T: ?Sized,
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> ExtAny for T
impl<T> ExtAny for T
Source§fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
fn as_any_mut(&mut self) -> &mut dyn Anywhere
Self: Sized,
Source§impl<T> ExtMem for Twhere
T: ?Sized,
impl<T> ExtMem for Twhere
T: ?Sized,
Source§const NEEDS_DROP: bool = _
const NEEDS_DROP: bool = _
Source§fn mem_align_of_val(&self) -> usize ⓘ
fn mem_align_of_val(&self) -> usize ⓘ
Source§fn mem_size_of_val(&self) -> usize ⓘ
fn mem_size_of_val(&self) -> usize ⓘ
Source§fn mem_needs_drop(&self) -> bool
fn mem_needs_drop(&self) -> bool
true
if dropping values of this type matters. Read moreSource§fn mem_forget(self)where
Self: Sized,
fn mem_forget(self)where
Self: Sized,
self
without running its destructor. Read moreSource§fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
fn mem_replace(&mut self, other: Self) -> Selfwhere
Self: Sized,
Source§unsafe fn mem_zeroed<T>() -> T
unsafe fn mem_zeroed<T>() -> T
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe fn mem_transmute_copy<Src, Dst>(src: &Src) -> Dst
unsafe_layout
only.T
represented by the all-zero byte-pattern. Read moreSource§fn mem_as_bytes(&self) -> &[u8] ⓘ
fn mem_as_bytes(&self) -> &[u8] ⓘ
unsafe_slice
only.§impl<S> FromSample<S> for S
impl<S> FromSample<S> for S
fn from_sample_(s: S) -> S
Source§impl<T> Hook for T
impl<T> Hook for T
§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
fn instrument(self, span: Span) -> Instrumented<Self> ⓘ
§fn in_current_span(self) -> Instrumented<Self> ⓘ
fn in_current_span(self) -> Instrumented<Self> ⓘ
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
fn into_either(self, into_left: bool) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left
is true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self> ⓘ
self
into a Left
variant of Either<Self, Self>
if into_left(&self)
returns true
.
Converts self
into a Right
variant of Either<Self, Self>
otherwise. Read more§impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
impl<F, T> IntoSample<T> for Fwhere
T: FromSample<F>,
fn into_sample(self) -> T
§impl<T> LayoutRaw for T
impl<T> LayoutRaw for T
§fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError> ⓘ
§impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
§unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool
§fn resolve_niched(out: Place<NichedOption<T, N1>>)
fn resolve_niched(out: Place<NichedOption<T, N1>>)
out
indicating that a T
is niched.