Skip to content

Commit 598e7f4

Browse files
authored
Add support for time zone designations (#659)
This adds support for the time zone designations. This fixes an issue when data packaging, where we were not aligning with the appropriate data. It's also a more complete TZif representation, so that's a benefit as well.
1 parent 22b1ce8 commit 598e7f4

3 files changed

Lines changed: 76 additions & 7 deletions

File tree

provider/src/experimental_tzif/datagen.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ impl From<&zoneinfo_rs::tzif::LocalTimeRecord> for LocalTimeRecord {
1010
fn from(value: &zoneinfo_rs::tzif::LocalTimeRecord) -> Self {
1111
Self {
1212
offset: value.offset,
13+
is_dst: value.is_dst,
14+
index: value.index,
1315
}
1416
}
1517
}
@@ -22,14 +24,15 @@ impl ZeroTzif<'_> {
2224
let mapped_local_records: Vec<LocalTimeRecord> =
2325
tzif.local_time_types.iter().map(Into::into).collect();
2426
let types = ZeroVec::alloc_from_slice(&mapped_local_records);
25-
// TODO: handle this much better.
2627
let posix = PosixZone::from(&data.posix_time_zone);
28+
let designations = ZeroVec::alloc_from_slice(&tzif.designations);
2729

2830
Self {
2931
transitions,
3032
transition_types,
3133
types,
3234
posix,
35+
designations,
3336
}
3437
}
3538
}

provider/src/experimental_tzif/mod.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ impl ZoneInfoProvider<'_> {
3636
}
3737
}
3838

39+
/// A zero-copy TZif data struct for time zone data provided by IANA's tzdb (also known
40+
/// as the Olsen database).
3941
#[zerovec::make_varule(ZeroTzifULE)]
4042
#[derive(PartialEq, Debug, Clone)]
4143
#[zerovec::skip_derive(Ord)]
@@ -47,11 +49,16 @@ impl ZoneInfoProvider<'_> {
4749
#[cfg_attr(feature = "datagen", zerovec::derive(Serialize))]
4850
#[cfg_attr(feature = "datagen", databake(path = timezone_provider::experimental_tzif))]
4951
pub struct ZeroTzif<'data> {
52+
/// The time in UTC epoch seconds where a transition occurs.
5053
pub transitions: ZeroVec<'data, i64>,
54+
/// An index identify the local time type for the corresponding transition.
5155
pub transition_types: ZeroVec<'data, u8>,
52-
// NOTE: zoneinfo64 does a fun little bitmap str
56+
/// The available local time types
5357
pub types: ZeroVec<'data, LocalTimeRecord>,
58+
/// The POSIX time zone data for this TZif
5459
pub posix: PosixZone,
60+
/// The available time zone designations.
61+
pub designations: ZeroVec<'data, char>,
5562
}
5663

5764
#[zerovec::make_ule(LocalTimeRecordULE)]
@@ -62,5 +69,10 @@ pub struct ZeroTzif<'data> {
6269
)]
6370
#[cfg_attr(feature = "datagen", databake(path = timezone_provider::experimental_tzif))]
6471
pub struct LocalTimeRecord {
72+
/// The offset from UTC in seconds
6573
pub offset: i64,
74+
/// Whether the current local time type is considered DST or not
75+
pub(crate) is_dst: bool,
76+
/// The index into the designations array.
77+
pub index: u8,
6678
}

zoneinfo/src/tzif.rs

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,37 +19,51 @@ pub struct TzifBlockV2 {
1919
pub transition_times: Vec<i64>,
2020
pub transition_types: Vec<u8>,
2121
pub local_time_types: Vec<LocalTimeRecord>, // TODO: Add other fields as needed
22+
pub designations: Vec<char>,
2223
}
2324

2425
impl TzifBlockV2 {
2526
pub fn from_transition_data(data: &CompiledTransitions) -> Self {
2627
let mut local_time_set = IndexSet::new();
28+
let mut designation_set = DesignationSet::default();
29+
30+
let index = designation_set
31+
.insert_and_retrieve_index(data.initial_record.designation.chars().collect());
2732
local_time_set.insert(LocalTimeRecord {
2833
offset: data.initial_record.offset,
2934
is_dst: data.initial_record.saving.as_secs() != 0,
35+
index: index as u8,
3036
});
3137
let mut transition_times = Vec::default();
3238
let mut transition_types = Vec::default();
3339
for transition in &data.transitions {
34-
let _ = local_time_set.insert(LocalTimeRecord {
40+
let index =
41+
designation_set.insert_and_retrieve_index(transition.format.chars().collect());
42+
let local_time_record = LocalTimeRecord {
3543
offset: transition.offset,
3644
is_dst: transition.dst,
37-
});
45+
index: index as u8,
46+
};
3847

3948
transition_times.push(transition.at_time);
40-
for (index, time_type) in local_time_set.iter().enumerate() {
41-
if time_type.offset == transition.offset {
42-
transition_types.push(index as u8);
49+
match local_time_set.get_index_of(&local_time_record) {
50+
Some(i) => transition_types.push(i as u8),
51+
None => {
52+
let _ = local_time_set.insert(local_time_record);
53+
transition_types.push(local_time_set.len() as u8 - 1);
4354
}
4455
}
4556
}
4657

4758
let local_time_types = local_time_set.into_iter().collect::<Vec<LocalTimeRecord>>();
4859

60+
let designations = designation_set.to_vec();
61+
4962
Self {
5063
transition_times,
5164
transition_types,
5265
local_time_types,
66+
designations,
5367
}
5468
}
5569
}
@@ -59,4 +73,44 @@ impl TzifBlockV2 {
5973
pub struct LocalTimeRecord {
6074
pub offset: i64,
6175
pub is_dst: bool,
76+
pub index: u8,
77+
}
78+
79+
#[derive(Debug, Default, Clone)]
80+
pub struct DesignationSet {
81+
pub designations: IndexSet<Vec<char>>,
82+
pub indices: Vec<usize>,
83+
pub next_index: usize,
84+
}
85+
86+
impl DesignationSet {
87+
// Inserts the a designation if it doesn't exist, returns the designation index.
88+
pub fn insert_and_retrieve_index(&mut self, mut designation: Vec<char>) -> usize {
89+
// Add a null character
90+
designation.push('\0');
91+
// Check if the designation already exists.
92+
let Some(index) = self.designations.get_index_of(&designation) else {
93+
let designation_len = designation.len();
94+
95+
// Insert the new designation into the set
96+
let _ = self.designations.insert(designation);
97+
98+
// Get the designation index and cache it.
99+
let designation_index = self.next_index;
100+
self.indices.push(designation_index);
101+
102+
// Calculate the next index to give out.
103+
self.next_index += designation_len;
104+
105+
return designation_index;
106+
};
107+
self.indices[index]
108+
}
109+
110+
pub fn to_vec(self) -> Vec<char> {
111+
self.designations
112+
.into_iter()
113+
.collect::<Vec<Vec<char>>>()
114+
.concat()
115+
}
62116
}

0 commit comments

Comments
 (0)