Skip to content

Commit

Permalink
Merge branch 'main' into export-tzoffset
Browse files Browse the repository at this point in the history
  • Loading branch information
pitdicker authored Apr 5, 2024
2 parents 4825f6d + 6987cd6 commit f03cf8e
Show file tree
Hide file tree
Showing 18 changed files with 298 additions and 222 deletions.
42 changes: 0 additions & 42 deletions .github/bin/update-tz.sh

This file was deleted.

16 changes: 16 additions & 0 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,22 @@ jobs:
cargo clean
cargo build --features case-insensitive
- name: Verify cargo publish includes all files needed to build
run: |
cargo vendor
cargo package -p chrono-tz-build
cargo package -p chrono-tz --no-verify
for crate in target/package/*.crate
do
name=$(basename "$crate" .crate)
tar xvfz "$crate" -C vendor/
# Crates in the vendor directory require a checksum file, but it
# doesn't matter if it is empty.
echo '{"files":{}}' > vendor/$name/.cargo-checksum.json
done
cargo package --config "source.vendored-sources.directory = 'vendor'" \
--config "source.crates-io.replace-with = 'vendored-sources'"
lint:
runs-on: ubuntu-latest

Expand Down
22 changes: 0 additions & 22 deletions .github/workflows/update-tz.yml

This file was deleted.

10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,16 @@
Chrono-tz Changelog
===================

## 0.8.2

* **tzdb** Update tzdb from 2022f to 2023c. All changes in 2023b have been
reverted back to 2023a. The full list of changes can be found
[here](https://mm.icann.org/pipermail/tz-announce/2023-March/000079.html)

## 0.8.1

* **tzdb** Update tzdb from 2022f to 2022g.

## 0.8.0

* **tzdb** Update tzdb from 2022e to 2022f. Some timezones have been removed. For
Expand Down
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
[workspace]
members = ["chrono-tz", "chrono-tz-build"]
resolver = "2"
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ include all the zones that are linked, such as "America/Denver", not just "US/Mo
[IANA database]: http://www.iana.org/time-zones
[wiki-list]: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

## Developing

`chrono-tz` uses git submodules, so in order to build locally you will need to
run `git submodule init` and `git submodule update`.

## Future Improvements

- Handle leap seconds
Expand Down
2 changes: 1 addition & 1 deletion bin/test-regex-filtering.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
set -euxo pipefail

export RUST_BACKTRACE=1
export CHRONO_TZ_TIMEZONE_FILTER='(Europe/London|GMT)'
export CHRONO_TZ_TIMEZONE_FILTER='(Europe/London|GMT|UTC)'

cd chrono-tz/tests/check-regex-filtering

Expand Down
9 changes: 7 additions & 2 deletions chrono-tz-build/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
[package]
name = "chrono-tz-build"
version = "0.1.0"
edition = "2018"
version = "0.3.0"
edition = "2021"
rust-version = "1.60"
description = "internal build script for chrono-tz"
readme = "README.md"
license = "MIT OR Apache-2.0"
keywords = ["script", "chrono-tz", "timezone", "iana"]
categories = ["development-tools::build-utils"]
repository = "https://github.com/chronotope/chrono-tz"
documentation = "https://docs.rs/chrono-tz-build"

[features]
filter-by-regex = ["regex"]
case-insensitive = ["uncased", "phf/uncased"]
regex = ["dep:regex"]

[dependencies]
parse-zoneinfo = { version = "0.3" }
Expand Down
1 change: 1 addition & 0 deletions chrono-tz-build/LICENSE
84 changes: 56 additions & 28 deletions chrono-tz-build/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,12 @@ fn format_rest(rest: Vec<(i64, FixedTimespan)>) -> String {
// it's a hyphen, in which case remove it. This is so the names can be used
// as rust identifiers.
fn convert_bad_chars(name: &str) -> String {
let name = name.replace("/", "__").replace("+", "Plus");
let name = name.replace('/', "__").replace('+', "Plus");
if let Some(pos) = name.find('-') {
if name[pos + 1..].chars().next().map(char::is_numeric).unwrap_or(false) {
name.replace("-", "Minus")
name.replace('-', "Minus")
} else {
name.replace("-", "")
name.replace('-', "")
}
} else {
name
Expand All @@ -72,7 +72,7 @@ fn write_timezone_file(timezone_file: &mut File, table: &Table) -> io::Result<()
writeln!(timezone_file, "use core::str::FromStr;\n",)?;
writeln!(
timezone_file,
"use ::timezone_impl::{{TimeSpans, FixedTimespanSet, FixedTimespan}};\n",
"use crate::timezone_impl::{{TimeSpans, FixedTimespanSet, FixedTimespan}};\n",
)?;
writeln!(
timezone_file,
Expand All @@ -82,7 +82,9 @@ fn write_timezone_file(timezone_file: &mut File, table: &Table) -> io::Result<()
/// construct chrono's DateTime type. See the root module documentation
/// for details."
)?;
writeln!(timezone_file, "#[derive(Clone, Copy, PartialEq, Eq, Hash)]\npub enum Tz {{")?;
writeln!(timezone_file, "#[derive(Clone, Copy, PartialEq, Eq, Hash)]")?;
writeln!(timezone_file, r#"#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]"#)?;
writeln!(timezone_file, "pub enum Tz {{")?;
for zone in &zones {
let zone_name = convert_bad_chars(zone);
writeln!(
Expand Down Expand Up @@ -117,20 +119,25 @@ fn write_timezone_file(timezone_file: &mut File, table: &Table) -> io::Result<()

writeln!(
timezone_file,
"#[cfg(feature = \"std\")]
pub type ParseError = String;
#[cfg(not(feature = \"std\"))]
pub type ParseError = &'static str;
r#"#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct ParseError(());
impl Display for ParseError {{
fn fmt(&self, f: &mut Formatter) -> fmt::Result {{
f.write_str("failed to parse timezone")
}}
}}
#[cfg(feature = "std")]
impl std::error::Error for ParseError {{}}
impl FromStr for Tz {{
type Err = ParseError;
fn from_str(s: &str) -> Result<Self, Self::Err> {{
#[cfg(feature = \"std\")]
return TIMEZONES.get(s).cloned().ok_or_else(|| format!(\"'{{}}' is not a valid timezone\", s));
#[cfg(not(feature = \"std\"))]
return TIMEZONES.get(s).cloned().ok_or(\"received invalid timezone\");
return TIMEZONES.get(s).cloned().ok_or(ParseError(()));
}}
}}\n"
}}
"#
)?;

writeln!(
Expand Down Expand Up @@ -162,10 +169,7 @@ impl FromStr for Tz {{
#[cfg(feature = "case-insensitive")]
/// Parses a timezone string in a case-insensitive way
pub fn from_str_insensitive(s: &str) -> Result<Self, ParseError> {{
#[cfg(feature = "std")]
return TIMEZONES_UNCASED.get(s.into()).cloned().ok_or_else(|| format!("'{{}}' is not a valid timezone", s));
#[cfg(not(feature = "std"))]
return TIMEZONES_UNCASED.get(s.into()).cloned().ok_or("received invalid timezone");
return TIMEZONES_UNCASED.get(s.into()).cloned().ok_or(ParseError(()));
}}"#
)?;
}
Expand Down Expand Up @@ -195,7 +199,7 @@ impl FromStr for Tz {{
match *self {{"
)?;
for zone in &zones {
let timespans = table.timespans(&zone).unwrap();
let timespans = table.timespans(zone).unwrap();
let zone_name = convert_bad_chars(zone);
writeln!(
timezone_file,
Expand Down Expand Up @@ -246,9 +250,11 @@ pub static TZ_VARIANTS: [Tz; {num}] = [

// Create a file containing nice-looking re-exports such as Europe::London
// instead of having to use chrono_tz::timezones::Europe__London
fn write_directory_file(directory_file: &mut File, table: &Table) -> io::Result<()> {
// add the `loose' zone definitions first at the top of the file
writeln!(directory_file, "use timezones::Tz;\n")?;
fn write_directory_file(directory_file: &mut File, table: &Table, version: &str) -> io::Result<()> {
// expose the underlying IANA TZDB version
writeln!(directory_file, "pub const IANA_TZDB_VERSION : &str = \"{version}\";\n")?;
// add the `loose' zone definitions first
writeln!(directory_file, "use crate::timezones::Tz;\n")?;
let zones = table
.zonesets
.keys()
Expand All @@ -268,13 +274,13 @@ fn write_directory_file(directory_file: &mut File, table: &Table) -> io::Result<
}
let module_name = convert_bad_chars(entry.name);
writeln!(directory_file, "pub mod {name} {{", name = module_name)?;
writeln!(directory_file, " use timezones::Tz;\n",)?;
writeln!(directory_file, " use crate::timezones::Tz;\n",)?;
for child in entry.children {
match child {
Child::Submodule(name) => {
let submodule_name = convert_bad_chars(name);
writeln!(directory_file, " pub mod {name} {{", name = submodule_name)?;
writeln!(directory_file, " use timezones::Tz;\n",)?;
writeln!(directory_file, " use crate::timezones::Tz;\n",)?;
let full_name = entry.name.to_string() + "/" + name;
for entry in table.structure() {
if entry.name == full_name {
Expand Down Expand Up @@ -424,10 +430,31 @@ mod filter {

table
.zonesets
.retain(|k, _| filter_regex.is_match(&k) || keep.iter().any(|s| k.starts_with(s)));
.retain(|k, _| filter_regex.is_match(k) || keep.iter().any(|s| k.starts_with(s)));
}
}

fn detect_iana_db_version() -> String {
let root = env::var("CARGO_MANIFEST_DIR").expect("no Cargo build context");
let path = Path::new(&root).join(Path::new("tz/NEWS"));
let file = File::open(path).expect("failed to open file");

let mut lines = BufReader::new(file).lines();
while let Some(Ok(line)) = lines.next() {
let line = match line.strip_prefix("Release ") {
Some(line) => line,
_ => continue,
};

match line.split_once(" - ") {
Some((version, _)) => return version.to_owned(),
_ => continue,
}
}

unreachable!("no version found")
}

pub fn main() {
println!("cargo:rerun-if-env-changed={}", FILTER_ENV_VAR_NAME);

Expand Down Expand Up @@ -474,10 +501,11 @@ pub fn main() {
filter::maybe_filter_timezone_table(&mut table);

let timezone_path = Path::new(&env::var("OUT_DIR").unwrap()).join("timezones.rs");
let mut timezone_file = File::create(&timezone_path).unwrap();
let mut timezone_file = File::create(timezone_path).unwrap();
write_timezone_file(&mut timezone_file, &table).unwrap();

let directory_path = Path::new(&env::var("OUT_DIR").unwrap()).join("directory.rs");
let mut directory_file = File::create(&directory_path).unwrap();
write_directory_file(&mut directory_file, &table).unwrap();
let mut directory_file = File::create(directory_path).unwrap();
let version = detect_iana_db_version();
write_directory_file(&mut directory_file, &table, &version).unwrap();
}
37 changes: 31 additions & 6 deletions chrono-tz/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,29 +1,54 @@
[package]
name = "chrono-tz"
version = "0.8.0"
version = "0.9.0"
edition = "2021"
rust-version = "1.60"
build = "build.rs"
description = "TimeZone implementations for chrono from the IANA database"
keywords = ["date", "time", "timezone", "zone", "calendar"]
keywords = ["date", "time", "timezone", "zone", "iana"]
categories = ["date-and-time"]
repository = "https://github.com/chronotope/chrono-tz"
documentation = "https://docs.rs/chrono-tz"
readme = "../README.md"
license = "MIT OR Apache-2.0"
include = [
"src/*.rs",
"tests/*.rs",
"build.rs",
"LICENSE",
"tz/africa",
"tz/antarctica",
"tz/asia",
"tz/australasia",
"tz/backward",
"tz/etcetera",
"tz/europe",
"tz/northamerica",
"tz/southamerica",
"tz/NEWS",
]

[dependencies]
chrono = { version = "0.4", default-features = false }
serde = { version = "1", optional = true, default-features = false }
arbitrary = { version = "1.2", optional = true, features = ["derive"] }
chrono = { version = "0.4.25", default-features = false }
serde = { version = "1.0.99", optional = true, default-features = false }
phf = { version = "0.11", default-features = false }
uncased = { version = "0.9", optional = true, default-features = false }

[features]
default = ["std"]
std = []
serde = ["dep:serde"]
filter-by-regex = ["chrono-tz-build/filter-by-regex"]
case-insensitive = ["uncased", "chrono-tz-build/case-insensitive", "phf/uncased"]
case-insensitive = ["dep:uncased", "chrono-tz-build/case-insensitive", "phf/uncased"]

[build-dependencies]
chrono-tz-build = { path = "../chrono-tz-build", version = "0.1" }
chrono-tz-build = { path = "../chrono-tz-build", version = "0.3" }

[dev-dependencies]
serde_test = "1"
chrono = { version = "0.4", default-features = false, features = ["alloc"] }

[package.metadata.docs.rs]
all-features = true
rustdoc-args = ["--cfg", "docsrs"]
1 change: 1 addition & 0 deletions chrono-tz/LICENSE
Loading

0 comments on commit f03cf8e

Please sign in to comment.