Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rewite caching in local::unix module #1457

Draft
wants to merge 17 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 1 addition & 102 deletions src/offset/local/tz_info/timezone.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
//! Types related to a time zone.

use std::fs::{self, File};
use std::io::{self, Read};
use std::path::{Path, PathBuf};
use std::{cmp::Ordering, fmt, str};

use super::rule::{AlternateTime, TransitionRule};
Expand All @@ -22,43 +19,8 @@
}

impl TimeZone {
/// Returns local time zone.
///
/// This method in not supported on non-UNIX platforms, and returns the UTC time zone instead.
pub(crate) fn local(env_tz: Option<&str>) -> Result<Self, Error> {
match env_tz {
Some(tz) => Self::from_posix_tz(tz),
None => Self::from_posix_tz("localtime"),
}
}

/// Construct a time zone from a POSIX TZ string, as described in [the POSIX documentation of the `TZ` environment variable](https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html).
fn from_posix_tz(tz_string: &str) -> Result<Self, Error> {
if tz_string.is_empty() {
return Err(Error::InvalidTzString("empty TZ string"));
}

if tz_string == "localtime" {
return Self::from_tz_data(&fs::read("/etc/localtime")?);
}

// attributes are not allowed on if blocks in Rust 1.38
#[cfg(target_os = "android")]
{
if let Ok(bytes) = android_tzdata::find_tz_data(tz_string) {
return Self::from_tz_data(&bytes);
}
}

let mut chars = tz_string.chars();
if chars.next() == Some(':') {
return Self::from_file(&mut find_tz_file(chars.as_str())?);
}

if let Ok(mut file) = find_tz_file(tz_string) {
return Self::from_file(&mut file);
}

pub(crate) fn from_tz_string(tz_string: &str) -> Result<Self, Error> {

Check warning on line 23 in src/offset/local/tz_info/timezone.rs

View check run for this annotation

Codecov / codecov/patch

src/offset/local/tz_info/timezone.rs#L23

Added line #L23 was not covered by tests
// TZ string extensions are not allowed
let tz_string = tz_string.trim_matches(|c: char| c.is_ascii_whitespace());
let rule = TransitionRule::from_tz_string(tz_string.as_bytes(), false)?;
Expand All @@ -85,13 +47,6 @@
Ok(new)
}

/// Construct a time zone from the contents of a time zone file
fn from_file(file: &mut File) -> Result<Self, Error> {
let mut bytes = Vec::new();
file.read_to_end(&mut bytes)?;
Self::from_tz_data(&bytes)
}

/// Construct a time zone from the contents of a time zone file
///
/// Parse TZif data as described in [RFC 8536](https://datatracker.ietf.org/doc/html/rfc8536).
Expand Down Expand Up @@ -606,34 +561,6 @@
pub(super) const UTC: LocalTimeType = Self { ut_offset: 0, is_dst: false, name: None };
}

/// Open the TZif file corresponding to a TZ string
fn find_tz_file(path: impl AsRef<Path>) -> Result<File, Error> {
// Don't check system timezone directories on non-UNIX platforms
#[cfg(not(unix))]
return Ok(File::open(path)?);

#[cfg(unix)]
{
let path = path.as_ref();
if path.is_absolute() {
return Ok(File::open(path)?);
}

for folder in &ZONE_INFO_DIRECTORIES {
if let Ok(file) = File::open(PathBuf::from(folder).join(path)) {
return Ok(file);
}
}

Err(Error::Io(io::ErrorKind::NotFound.into()))
}
}

// Possible system timezone directories
#[cfg(unix)]
const ZONE_INFO_DIRECTORIES: [&str; 4] =
["/usr/share/zoneinfo", "/share/zoneinfo", "/etc/zoneinfo", "/usr/share/lib/zoneinfo"];

/// Number of seconds in one week
pub(crate) const SECONDS_PER_WEEK: i64 = SECONDS_PER_DAY * DAYS_PER_WEEK;
/// Number of seconds in 28 days
Expand Down Expand Up @@ -844,34 +771,6 @@
Ok(())
}

#[test]
fn test_time_zone_from_posix_tz() -> Result<(), Error> {
#[cfg(unix)]
{
// if the TZ var is set, this essentially _overrides_ the
// time set by the localtime symlink
// so just ensure that ::local() acts as expected
// in this case
if let Ok(tz) = std::env::var("TZ") {
let time_zone_local = TimeZone::local(Some(tz.as_str()))?;
let time_zone_local_1 = TimeZone::from_posix_tz(&tz)?;
assert_eq!(time_zone_local, time_zone_local_1);
}

// `TimeZone::from_posix_tz("UTC")` will return `Error` if the environment does not have
// a time zone database, like for example some docker containers.
// In that case skip the test.
if let Ok(time_zone_utc) = TimeZone::from_posix_tz("UTC") {
assert_eq!(time_zone_utc.find_local_time_type(0)?.offset(), 0);
}
}

assert!(TimeZone::from_posix_tz("EST5EDT,0/0,J365/25").is_err());
assert!(TimeZone::from_posix_tz("").is_err());

Ok(())
}

#[test]
fn test_leap_seconds() -> Result<(), Error> {
let time_zone = TimeZone::new(
Expand Down