Skip to content

Add baseline ZoneInfo64 data provider#354

Closed
nekevss wants to merge 3 commits into
mainfrom
impl-zoneinfo64-provider
Closed

Add baseline ZoneInfo64 data provider#354
nekevss wants to merge 3 commits into
mainfrom
impl-zoneinfo64-provider

Conversation

@nekevss

@nekevss nekevss commented Jun 18, 2025

Copy link
Copy Markdown
Member

This adds a ZoneInfo64Provider that directly uses zoneinfo64.res bytes. This does not implement any resolution for now for the actual provider.

Ideally, long term, it may be best for this to take in bytes and complete some zerocopy deserialization, but there's some real difficulty around handling zoneinfo64's u16 strings that may require some custom types.

I think this may also require us to carry a Unicode license in the root for timezone_provider due to the res files. CC: @Manishearth for confirmation on that

This adds a ZoneInfo64Provider that directly uses zoneinfo64.res bytes. This
does not implement any resolution for now for the actual provider.

Ideally, long term, it may be best for this to take in bytes and complete
some zerocopy deserialization, but there's some real difficulty around
handling zoneinfo64's u16 strings that may require some custom types.

@HalidOdat HalidOdat left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good on my side, just some minor non-blocking nitpicks 😄

Comment thread provider/Cargo.toml
# ZoneInfo64 dependencies
resb = { git = "https://github.com/unicode-org/icu4x.git", optional = true }
rustc-hash = { workspace = true, optional = true }
writeable = { workspace = true, optional = true } No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whitespace 👮‍♂️

Suggested change
writeable = { workspace = true, optional = true }
writeable = { workspace = true, optional = true }

#[serde(borrow)]
pub final_rule: Option<ZoneInfo64String<'data>>,
pub final_raw: Option<i32>,
pub final_year: Option<i32>,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remark: Seems like from the data that the year can fit in a i16


#[derive(Debug, Clone)]
pub enum Zone<'data> {
Table(ZoneTable<'data>),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since ZoneTable is 108 bytes bigger than the Link variant maybe we should wrap it in a Box.

Suggested change
Table(ZoneTable<'data>),
Table(Box<ZoneTable<'data>>),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not useful if it's being zero-copy deserialized. Could be a Cow though.

@Manishearth

Copy link
Copy Markdown
Contributor

I think this may also require us to carry a Unicode license in the root for timezone_provider due to the res files. CC: @Manishearth for confirmation on that

Probably, yes. Make sure it's included in the published package!

@Manishearth Manishearth left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, looking at this ZeroVec won't help for the variable sized stuff (the three toplevel Vecs)

We can make it work by adding resb-specific Array, Array16, IntVector types and giving them custom from_bytes behavior.

Comment thread provider/Cargo.toml
serde_json = { version = "1.0.140", optional = true }

# ZoneInfo64 dependencies
resb = { git = "https://github.com/unicode-org/icu4x.git", optional = true }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should cut a release; make a PR to ICU4X that finalizes the resb Cargo.toml (make it publish = false), write a changelog entry, and ping me for a release.


#[derive(Debug, Clone)]
pub enum Zone<'data> {
Table(ZoneTable<'data>),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not useful if it's being zero-copy deserialized. Could be a Cow though.

@Manishearth

Copy link
Copy Markdown
Contributor

More thoughts on zerocopy stuff:

Really I think there's not as much benefit doing this through the serde model if you want to do it zerocopy, doing zerocopy in the serde model is easier if you control the data format itself, but here we do not. If we want to do 100% zerocopy stuff we should write a custom parser with the right intermediate types.

But it's not super necessary, a handful of allocations isn't a big deal here.

#[cfg(target_endian = "little")]
let bytes = include_bytes!("./data/zoneinfo64/2025b/le/zoneinfo64.res");
#[cfg(target_endian = "big")]
let bytes = include_bytes!("./data/zoneinfo64/2025b/be/zoneinfo64.res");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm. This won't actually work.

ZeroVec does two things: it allows data to be unaligned, and it consistently serializes in little-endian format. You only need the first one if your parsers are different for LE/BE.

Either the resb parser needs to be written to allow selecting endianness in the caller, OR you should exclusively access the ZeroVec data here in a way that inverts the numbers on BE.

Probably something to be fixed later.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I added it initially, and then realized the day after that the BE wouldn't work with ZeroVec. I just haven't gotten around to fixing it just yet.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the resb data that is available from platforms uses native endianness, the resb crate should just not use ZeroVec.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed. In this case, the zoneinfo file is provided, so the BE zoneinfo file just needs to be removed.

@nekevss nekevss added providers Related to time zone providers labels Jun 26, 2025

@robertbastian robertbastian left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to move some of the logic, and more importantly the data and tests into the resb crate? This should also solve the license problem as resb is already Unicode-licensed.

#[cfg(target_endian = "little")]
let bytes = include_bytes!("./data/zoneinfo64/2025b/le/zoneinfo64.res");
#[cfg(target_endian = "big")]
let bytes = include_bytes!("./data/zoneinfo64/2025b/be/zoneinfo64.res");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the resb data that is available from platforms uses native endianness, the resb crate should just not use ZeroVec.

@nekevss

nekevss commented Jun 27, 2025

Copy link
Copy Markdown
Member Author

Would it make sense to move some of the logic, and more importantly the data and tests into the resb crate

Yeah, I think there's a good argument here for moving it into the resb crate.

The only issue is that I'm not entirely convinced that the resb crate should own the zoneinfo64 structs and data. It could probably be feature flagged ... Or maybe an intermediate zoneinfo64 crate that reexports resb and zoneinfo64 data + structs?

@robertbastian

Copy link
Copy Markdown
Contributor

It should definitely be feature-flagged for the scenario where there's already a zoneinfo64 available from somewhere else.

@nekevss

nekevss commented Aug 26, 2025

Copy link
Copy Markdown
Member Author

Closing as this is being implemented in a different approach

@nekevss nekevss closed this Aug 26, 2025
@nekevss nekevss deleted the impl-zoneinfo64-provider branch September 2, 2025 00:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

providers Related to time zone providers

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants