Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion provider/src/experimental_tzif/datagen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ impl From<&zoneinfo_rs::tzif::LocalTimeRecord> for LocalTimeRecord {
fn from(value: &zoneinfo_rs::tzif::LocalTimeRecord) -> Self {
Self {
offset: value.offset,
is_dst: value.is_dst,
index: value.index,
}
}
}
Expand All @@ -22,14 +24,15 @@ impl ZeroTzif<'_> {
let mapped_local_records: Vec<LocalTimeRecord> =
tzif.local_time_types.iter().map(Into::into).collect();
let types = ZeroVec::alloc_from_slice(&mapped_local_records);
// TODO: handle this much better.
let posix = PosixZone::from(&data.posix_time_zone);
let designations = ZeroVec::alloc_from_slice(&tzif.designations);

Self {
transitions,
transition_types,
types,
posix,
designations,
}
}
}
Expand Down
14 changes: 13 additions & 1 deletion provider/src/experimental_tzif/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ impl ZoneInfoProvider<'_> {
}
}

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

#[zerovec::make_ule(LocalTimeRecordULE)]
Expand All @@ -62,5 +69,10 @@ pub struct ZeroTzif<'data> {
)]
#[cfg_attr(feature = "datagen", databake(path = timezone_provider::experimental_tzif))]
pub struct LocalTimeRecord {
/// The offset from UTC in seconds
pub offset: i64,
/// Whether the current local time type is considered DST or not
pub(crate) is_dst: bool,
/// The index into the designations array.
pub index: u8,
}
64 changes: 59 additions & 5 deletions zoneinfo/src/tzif.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,37 +19,51 @@ pub struct TzifBlockV2 {
pub transition_times: Vec<i64>,
pub transition_types: Vec<u8>,
pub local_time_types: Vec<LocalTimeRecord>, // TODO: Add other fields as needed
pub designations: Vec<char>,
}

impl TzifBlockV2 {
pub fn from_transition_data(data: &CompiledTransitions) -> Self {
let mut local_time_set = IndexSet::new();
let mut designation_set = DesignationSet::default();

let index = designation_set
.insert_and_retrieve_index(data.initial_record.designation.chars().collect());
local_time_set.insert(LocalTimeRecord {
offset: data.initial_record.offset,
is_dst: data.initial_record.saving.as_secs() != 0,
index: index as u8,
});
let mut transition_times = Vec::default();
let mut transition_types = Vec::default();
for transition in &data.transitions {
let _ = local_time_set.insert(LocalTimeRecord {
let index =
designation_set.insert_and_retrieve_index(transition.format.chars().collect());
let local_time_record = LocalTimeRecord {
offset: transition.offset,
is_dst: transition.dst,
});
index: index as u8,
};

transition_times.push(transition.at_time);
for (index, time_type) in local_time_set.iter().enumerate() {
if time_type.offset == transition.offset {
transition_types.push(index as u8);
match local_time_set.get_index_of(&local_time_record) {
Some(i) => transition_types.push(i as u8),
None => {
let _ = local_time_set.insert(local_time_record);
transition_types.push(local_time_set.len() as u8 - 1);
}
}
}

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

let designations = designation_set.to_vec();

Self {
transition_times,
transition_types,
local_time_types,
designations,
}
}
}
Expand All @@ -59,4 +73,44 @@ impl TzifBlockV2 {
pub struct LocalTimeRecord {
pub offset: i64,
pub is_dst: bool,
pub index: u8,
}

#[derive(Debug, Default, Clone)]
pub struct DesignationSet {
pub designations: IndexSet<Vec<char>>,
pub indices: Vec<usize>,
pub next_index: usize,
}

impl DesignationSet {
// Inserts the a designation if it doesn't exist, returns the designation index.
pub fn insert_and_retrieve_index(&mut self, mut designation: Vec<char>) -> usize {
// Add a null character
designation.push('\0');
// Check if the designation already exists.
let Some(index) = self.designations.get_index_of(&designation) else {
let designation_len = designation.len();

// Insert the new designation into the set
let _ = self.designations.insert(designation);

// Get the designation index and cache it.
let designation_index = self.next_index;
self.indices.push(designation_index);

// Calculate the next index to give out.
self.next_index += designation_len;

return designation_index;
};
self.indices[index]
}

pub fn to_vec(self) -> Vec<char> {
self.designations
.into_iter()
.collect::<Vec<Vec<char>>>()
.concat()
}
}