Coverage Report

Created: 2026-08-05 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/jiff-0.2.35/src/tz/mod.rs
Line
Count
Source
1
/*!
2
Routines for interacting with time zones and the zoneinfo database.
3
4
The main type in this module is [`TimeZone`]. For most use cases, you may not
5
even need to interact with this type at all. For example, this code snippet
6
converts a civil datetime to a zone aware datetime:
7
8
```
9
use jiff::civil::date;
10
11
let zdt = date(2024, 7, 10).at(20, 48, 0, 0).in_tz("America/New_York")?;
12
assert_eq!(zdt.to_string(), "2024-07-10T20:48:00-04:00[America/New_York]");
13
14
# Ok::<(), Box<dyn std::error::Error>>(())
15
```
16
17
And this example parses a zone aware datetime from a string:
18
19
```
20
use jiff::Zoned;
21
22
let zdt: Zoned = "2024-07-10 20:48[america/new_york]".parse()?;
23
assert_eq!(zdt.year(), 2024);
24
assert_eq!(zdt.month(), 7);
25
assert_eq!(zdt.day(), 10);
26
assert_eq!(zdt.hour(), 20);
27
assert_eq!(zdt.minute(), 48);
28
assert_eq!(zdt.offset().seconds(), -4 * 60 * 60);
29
assert_eq!(zdt.time_zone().iana_name(), Some("America/New_York"));
30
31
# Ok::<(), Box<dyn std::error::Error>>(())
32
```
33
34
Yet, neither of the above examples require uttering [`TimeZone`]. This is
35
because the datetime types in this crate provide higher level abstractions for
36
working with time zone identifiers. Nevertheless, sometimes it is useful to
37
work with a `TimeZone` directly. For example, if one has a `TimeZone`, then
38
conversion from a [`Timestamp`](crate::Timestamp) to a [`Zoned`](crate::Zoned)
39
is infallible:
40
41
```
42
use jiff::{tz::TimeZone, Timestamp};
43
44
let tz = TimeZone::get("America/New_York")?;
45
let ts = Timestamp::UNIX_EPOCH;
46
let zdt = ts.to_zoned(tz);
47
assert_eq!(zdt.to_string(), "1969-12-31T19:00:00-05:00[America/New_York]");
48
49
# Ok::<(), Box<dyn std::error::Error>>(())
50
```
51
52
# The [IANA Time Zone Database]
53
54
Since a time zone is a set of rules for determining the civil time, via an
55
offset from UTC, in a particular geographic region, a database is required to
56
represent the full complexity of these rules in practice. The standard database
57
is widespread use is the [IANA Time Zone Database]. On Unix systems, this is
58
typically found at `/usr/share/zoneinfo`, and Jiff will read it automatically.
59
On Windows systems, there is no canonical Time Zone Database installation, and
60
so Jiff embeds it into the compiled artifact. (This does not happen on Unix
61
by default.)
62
63
See the [`TimeZoneDatabase`] for more information.
64
65
# The system or "local" time zone
66
67
In many cases, the operating system manages a "default" time zone. It might,
68
for example, be how the `date` program converts a Unix timestamp to a time that
69
is "local" to you.
70
71
Unfortunately, there is no universal approach to discovering a system's default
72
time zone. Instead, Jiff uses heuristics like reading `/etc/localtime` on Unix,
73
and calling [`GetDynamicTimeZoneInformation`] on Windows. But in all cases,
74
Jiff will always use the IANA Time Zone Database for implementing time zone
75
transition rules. (For example, Windows specific APIs for time zone transitions
76
are not supported by Jiff.)
77
78
Moreover, Jiff supports reading the `TZ` environment variable, as specified
79
by POSIX, on all systems.
80
81
To get the system's default time zone, use [`TimeZone::system`].
82
83
# Core-only environments
84
85
By default, Jiff attempts to read time zone rules from `/usr/share/zoneinfo`
86
on Unix and a bundled database on other platforms (like on Windows). This happens
87
at runtime, and aside from requiring APIs to interact with the file system
88
on Unix, it also requires dynamic memory allocation.
89
90
For core-only environments that don't have file system APIs or dynamic
91
memory allocation, Jiff provides a way to construct `TimeZone` values at
92
compile time by compiling time zone rules into your binary. This does mean
93
that your program will need to be re-compiled if the time zone rules change
94
(in contrast to Jiff's default behavior of reading `/usr/share/zoneinfo` at
95
runtime on Unix), but sometimes there isn't a practical alternative.
96
97
With the `static` crate feature enabled, the [`jiff::tz::get`](crate::tz::get)
98
macro becomes available in this module. This example shows how use it to build
99
a `TimeZone` at compile time. Here, we find the next DST transition from a
100
particular timestamp in `Europe/Zurich`, and then print that in local time for
101
Zurich:
102
103
```
104
use jiff::{tz::{self, TimeZone}, Timestamp};
105
106
static TZ: TimeZone = tz::get!("Europe/Zurich");
107
108
let ts: Timestamp = "2025-02-25T00:00Z".parse()?;
109
let Some(next_transition) = TZ.following(ts).next() else {
110
    return Err("no time zone transitions".into());
111
};
112
let zdt = next_transition.timestamp().to_zoned(TZ.clone());
113
assert_eq!(zdt.to_string(), "2025-03-30T03:00:00+02:00[Europe/Zurich]");
114
115
# Ok::<(), Box<dyn std::error::Error>>(())
116
```
117
118
The above example does not require dynamic memory allocation or access to file
119
system APIs. It also _only_ embeds the `Europe/Zurich` time zone into your
120
compiled binary.
121
122
[IANA Time Zone Database]: https://en.wikipedia.org/wiki/Tz_database
123
[`GetDynamicTimeZoneInformation`]: https://learn.microsoft.com/en-us/windows/win32/api/timezoneapi/nf-timezoneapi-getdynamictimezoneinformation
124
*/
125
126
pub use self::{
127
    ambiguous::{
128
        AmbiguousOffset, AmbiguousTimestamp, AmbiguousZoned, Disambiguation,
129
    },
130
    db::{db, TimeZoneDatabase, TimeZoneName, TimeZoneNameIter},
131
    offset::{Dst, Offset, OffsetArithmetic, OffsetConflict, OffsetRound},
132
    timezone::{
133
        TimeZone, TimeZoneFollowingTransitions, TimeZoneOffsetInfo,
134
        TimeZonePrecedingTransitions, TimeZoneTransition,
135
    },
136
};
137
138
mod ambiguous;
139
#[cfg(feature = "tzdb-concatenated")]
140
mod concatenated;
141
mod db;
142
mod offset;
143
pub(crate) mod posix;
144
#[cfg(feature = "tz-system")]
145
mod system;
146
#[cfg(all(test, feature = "alloc"))]
147
pub(crate) mod testdata;
148
mod timezone;
149
mod tzif;
150
// See module comment for WIP status. :-(
151
#[cfg(all(test, feature = "alloc"))]
152
mod zic;
153
154
/// Create a `TimeZone` value from TZif data in [`jiff-tzdb`] at compile time.
155
///
156
/// This reads the data for the time zone with the IANA identifier given from
157
/// [`jiff-tzdb`], parses it as TZif specified by [RFC 9636], and constructs a
158
/// `TimeZone` value for use in a `const` context. This enables using IANA time
159
/// zones with Jiff in core-only environments. No dynamic memory allocation is
160
/// used.
161
///
162
/// # Input
163
///
164
/// This macro takes one positional parameter that must be a literal string.
165
/// The string should be an IANA time zone identifier, e.g.,
166
/// `America/New_York`.
167
///
168
/// # Return type
169
///
170
/// This macro returns a value with type `TimeZone`. To get a `&'static
171
/// TimeZone`, simply use `&get!("...")`.
172
///
173
/// # Usage
174
///
175
/// Callers should only call this macro once for each unique IANA time zone
176
/// identifier you need. Otherwise, multiple copies of the same embedded
177
/// time zone data could appear in your binary. There are no correctness
178
/// issues with this, but it could make your binary bigger than it needs to be.
179
///
180
/// # When should I use this?
181
///
182
/// Users should only use this macro if they have a _specific need_ for it
183
/// (like using a time zone on an embedded device). In particular, this will
184
/// embed the time zone transition rules into your binary. If the time zone
185
/// rules change, your program will need to be re-compiled.
186
///
187
/// In contrast, Jiff's default configuration on Unix is to read from
188
/// `/usr/share/zoneinfo` at runtime. This means your application will
189
/// automatically use time zone updates and doesn't need to be re-compiled.
190
///
191
/// Using a static `TimeZone` may also be faster in some cases. In particular,
192
/// a `TimeZone` created at runtime from a `/usr/share/zoneinfo` uses
193
/// automatic reference counting internally. In contrast, a `TimeZone` created
194
/// with this macro does not.
195
///
196
/// # Example
197
///
198
/// This example shows how to find the next DST transition from a particular
199
/// timestamp in `Europe/Zurich`, and then print that in local time for Zurich:
200
///
201
/// ```
202
/// use jiff::{tz::{self, TimeZone}, Timestamp};
203
///
204
/// static TZ: TimeZone = tz::get!("Europe/Zurich");
205
///
206
/// let ts: Timestamp = "2025-02-25T00:00Z".parse()?;
207
/// let Some(next_transition) = TZ.following(ts).next() else {
208
///     return Err("no time zone transitions".into());
209
/// };
210
/// let zdt = next_transition.timestamp().to_zoned(TZ.clone());
211
/// assert_eq!(zdt.to_string(), "2025-03-30T03:00:00+02:00[Europe/Zurich]");
212
///
213
/// # Ok::<(), Box<dyn std::error::Error>>(())
214
/// ```
215
///
216
/// [RFC 9636]: https://datatracker.ietf.org/doc/rfc9636/
217
/// [`jiff-tzdb`]: https://docs.rs/jiff-tzdb
218
#[cfg(feature = "static")]
219
pub use jiff_static::get;
220
221
/// Create a `TimeZone` value from TZif data in a file at compile time.
222
///
223
/// This reads the data in the file path given, parses it as TZif specified by
224
/// [RFC 9636], and constructs a `TimeZone` value for use in a `const` context.
225
/// This enables using IANA time zones with Jiff in core-only environments. No
226
/// dynamic memory allocation is used.
227
///
228
/// Unlike [`jiff::tz::get`](get), this reads TZif data from a file.
229
/// `jiff::tz::get`, in contrast, reads TZif data from the [`jiff-tzdb`] crate.
230
/// `jiff::tz::get` is more convenient and doesn't require managing your own
231
/// TZif files, but it comes at the cost of a compile-time dependency on
232
/// `jiff-tzdb` and being forced to use whatever data is in `jiff-tzdb`.
233
///
234
/// # Input
235
///
236
/// This macro takes two positional parameters that must be literal strings.
237
///
238
/// The first is required and is a path to a file containing TZif data. For
239
/// example, `/usr/share/zoneinfo/America/New_York`.
240
///
241
/// The second parameter is an IANA time zone identifier, e.g.,
242
/// `America/New_York`, and is required only when an IANA time zone identifier
243
/// could not be determined from the file path. The macro will automatically
244
/// infer an IANA time zone identifier as anything after the last occurrence
245
/// of the literal `zoneinfo/` in the file path.
246
///
247
/// # Return type
248
///
249
/// This macro returns a value with type `TimeZone`. To get a `&'static
250
/// TimeZone`, simply use `&include!("...")`.
251
///
252
/// # Usage
253
///
254
/// Callers should only call this macro once for each unique IANA time zone
255
/// identifier you need. Otherwise, multiple copies of the same embedded
256
/// time zone data could appear in your binary. There are no correctness
257
/// issues with this, but it could make your binary bigger than it needs to be.
258
///
259
/// # When should I use this?
260
///
261
/// Users should only use this macro if they have a _specific need_ for it
262
/// (like using a time zone on an embedded device). In particular, this will
263
/// embed the time zone transition rules into your binary. If the time zone
264
/// rules change, your program will need to be re-compiled.
265
///
266
/// In contrast, Jiff's default configuration on Unix is to read from
267
/// `/usr/share/zoneinfo` at runtime. This means your application will
268
/// automatically use time zone updates and doesn't need to be re-compiled.
269
///
270
/// Using a static `TimeZone` may also be faster in some cases. In particular,
271
/// a `TimeZone` created at runtime from a `/usr/share/zoneinfo` uses
272
/// automatic reference counting internally. In contrast, a `TimeZone` created
273
/// with this macro does not.
274
///
275
/// # Example
276
///
277
/// This example shows how to find the next DST transition from a particular
278
/// timestamp in `Europe/Zurich`, and then print that in local time for Zurich:
279
///
280
/// ```ignore
281
/// use jiff::{tz::{self, TimeZone}, Timestamp};
282
///
283
/// static TZ: TimeZone = tz::include!("/usr/share/zoneinfo/Europe/Zurich");
284
///
285
/// let ts: Timestamp = "2025-02-25T00:00Z".parse()?;
286
/// let Some(next_transition) = TZ.following(ts).next() else {
287
///     return Err("no time zone transitions".into());
288
/// };
289
/// let zdt = next_transition.timestamp().to_zoned(TZ.clone());
290
/// assert_eq!(zdt.to_string(), "2025-03-30T03:00:00+02:00[Europe/Zurich]");
291
///
292
/// # Ok::<(), Box<dyn std::error::Error>>(())
293
/// ```
294
///
295
/// # Example: using `/etc/localtime`
296
///
297
/// On most Unix systems, `/etc/localtime` is a symbolic link to a file in
298
/// your `/usr/share/zoneinfo` directory. This means it is a valid input to
299
/// this macro. However, Jiff currently does not detect the IANA time zone
300
/// identifier, so you'll need to provide it yourself:
301
///
302
/// ```ignore
303
/// use jiff::{tz::{self, TimeZone}, Timestamp};
304
///
305
/// static TZ: TimeZone = tz::include!("/etc/localtime", "America/New_York");
306
///
307
/// let ts: Timestamp = "2025-02-25T00:00Z".parse()?;
308
/// let zdt = ts.to_zoned(TZ.clone());
309
/// assert_eq!(zdt.to_string(), "2025-02-24T19:00:00-05:00[America/New_York]");
310
///
311
/// # Ok::<(), Box<dyn std::error::Error>>(())
312
/// ```
313
///
314
/// Note that this is reading `/etc/localtime` _at compile time_, which means
315
/// that the program will only use the time zone on the system in which it
316
/// was compiled. It will _not_ use the time zone of the system running it.
317
///
318
/// [RFC 9636]: https://datatracker.ietf.org/doc/rfc9636/
319
/// [`jiff-tzdb`]: https://docs.rs/jiff-tzdb
320
#[cfg(feature = "static-tz")]
321
pub use jiff_static::include;
322
323
/// Creates a new time zone offset in a `const` context from a given number
324
/// of hours.
325
///
326
/// Negative offsets correspond to time zones west of the prime meridian,
327
/// while positive offsets correspond to time zones east of the prime
328
/// meridian. Equivalently, in all cases, `civil-time - offset = UTC`.
329
///
330
/// The fallible non-const version of this constructor is
331
/// [`Offset::from_hours`].
332
///
333
/// This is a convenience free function for [`Offset::constant`]. It is
334
/// intended to provide a terse syntax for constructing `Offset` values from
335
/// a value that is known to be valid.
336
///
337
/// # Panics
338
///
339
/// This routine panics when the given number of hours is out of range.
340
/// Namely, `hours` must be in the range `-25..=25`.
341
///
342
/// Similarly, when used in a const context, an out of bounds hour will prevent
343
/// your Rust program from compiling.
344
///
345
/// # Example
346
///
347
/// ```
348
/// use jiff::tz::offset;
349
///
350
/// let o = offset(-5);
351
/// assert_eq!(o.seconds(), -18_000);
352
/// let o = offset(5);
353
/// assert_eq!(o.seconds(), 18_000);
354
/// ```
355
#[inline]
356
0
pub const fn offset(hours: i8) -> Offset {
357
0
    Offset::constant(hours)
358
0
}