Skip to content

Commit e9ceb1d

Browse files
committed
Fix OpenHarmony's local timezone fetching and tzdata parsing
1 parent 39fb201 commit e9ceb1d

7 files changed

Lines changed: 299 additions & 63 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ alloc = []
2323
libc = []
2424
winapi = ["windows-link"]
2525
std = ["alloc"]
26-
clock = ["winapi", "iana-time-zone", "android-tzdata", "now"]
26+
clock = ["winapi", "iana-time-zone", "now"]
2727
now = ["std"]
2828
oldtime = []
2929
wasmbind = ["wasm-bindgen", "js-sys"]
@@ -57,9 +57,6 @@ windows-bindgen = { version = "0.60" } # MSRV is 1.74
5757
[target.'cfg(unix)'.dependencies]
5858
iana-time-zone = { version = "0.1.45", optional = true, features = ["fallback"] }
5959

60-
[target.'cfg(target_os = "android")'.dependencies]
61-
android-tzdata = { version = "0.1.1", optional = true }
62-
6360
[dev-dependencies]
6461
serde_json = { version = "1" }
6562
serde_derive = { version = "1", default-features = false }

src/offset/local/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,11 @@ mod inner;
2828
#[allow(unreachable_pub)]
2929
mod win_bindings;
3030

31+
#[cfg(all(any(target_os = "android", target_env = "ohos"), feature = "clock"))]
32+
#[allow(dead_code)]
33+
#[allow(unreachable_pub)]
34+
pub(crate) mod tzdata;
35+
3136
#[cfg(all(
3237
not(unix),
3338
not(windows),

src/offset/local/tz_info/timezone.rs

Lines changed: 8 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ use std::{cmp::Ordering, fmt, str};
88
use super::rule::{AlternateTime, TransitionRule};
99
use super::{DAYS_PER_WEEK, Error, SECONDS_PER_DAY, parser};
1010
use crate::NaiveDateTime;
11-
#[cfg(target_env = "ohos")]
12-
use crate::offset::local::tz_info::parser::Cursor;
1311

1412
/// Time zone
1513
#[derive(Debug, Clone, Eq, PartialEq)]
@@ -48,15 +46,21 @@ impl TimeZone {
4846
// attributes are not allowed on if blocks in Rust 1.38
4947
#[cfg(target_os = "android")]
5048
{
51-
if let Ok(bytes) = android_tzdata::find_tz_data(tz_string) {
49+
if let Ok(Some(bytes)) =
50+
crate::offset::local::tzdata::find_tz_data_android_from_fs(tz_string)
51+
{
5252
return Self::from_tz_data(&bytes);
5353
}
5454
}
5555

5656
// ohos merge all file into tzdata since ver35
5757
#[cfg(target_env = "ohos")]
5858
{
59-
return Self::from_tz_data(&find_ohos_tz_data(tz_string)?);
59+
if let Ok(Some(bytes)) =
60+
crate::offset::local::tzdata::find_tz_data_ohos_from_fs(tz_string)
61+
{
62+
return Self::from_tz_data(&bytes);
63+
}
6064
}
6165

6266
let mut chars = tz_string.chars();
@@ -635,58 +639,6 @@ fn find_tz_file(path: impl AsRef<Path>) -> Result<File, Error> {
635639
}
636640
}
637641

638-
#[cfg(target_env = "ohos")]
639-
fn from_tzdata_bytes(bytes: &mut Vec<u8>, tz_string: &str) -> Result<Vec<u8>, Error> {
640-
const VERSION_SIZE: usize = 12;
641-
const OFFSET_SIZE: usize = 4;
642-
const INDEX_CHUNK_SIZE: usize = 48;
643-
const ZONENAME_SIZE: usize = 40;
644-
645-
let mut cursor = Cursor::new(&bytes);
646-
// version head
647-
let _ = cursor.read_exact(VERSION_SIZE)?;
648-
let index_offset_offset = cursor.read_be_u32()?;
649-
let data_offset_offset = cursor.read_be_u32()?;
650-
// final offset
651-
let _ = cursor.read_be_u32()?;
652-
653-
cursor.seek_after(index_offset_offset as usize)?;
654-
let mut idx = index_offset_offset;
655-
while idx < data_offset_offset {
656-
let index_buf = cursor.read_exact(ZONENAME_SIZE)?;
657-
let offset = cursor.read_be_u32()?;
658-
let length = cursor.read_be_u32()?;
659-
let zone_name = str::from_utf8(index_buf)?.trim_end_matches('\0');
660-
if zone_name != tz_string {
661-
idx += INDEX_CHUNK_SIZE as u32;
662-
continue;
663-
}
664-
cursor.seek_after((data_offset_offset + offset) as usize)?;
665-
return match cursor.read_exact(length as usize) {
666-
Ok(result) => Ok(result.to_vec()),
667-
Err(_err) => Err(Error::InvalidTzFile("invalid ohos tzdata chunk")),
668-
};
669-
}
670-
671-
Err(Error::InvalidTzString("cannot find tz string within tzdata"))
672-
}
673-
674-
#[cfg(target_env = "ohos")]
675-
fn from_tzdata_file(file: &mut File, tz_string: &str) -> Result<Vec<u8>, Error> {
676-
let mut bytes = Vec::new();
677-
file.read_to_end(&mut bytes)?;
678-
from_tzdata_bytes(&mut bytes, tz_string)
679-
}
680-
681-
#[cfg(target_env = "ohos")]
682-
fn find_ohos_tz_data(tz_string: &str) -> Result<Vec<u8>, Error> {
683-
const TZDATA_PATH: &str = "/system/etc/zoneinfo/tzdata";
684-
match File::open(TZDATA_PATH) {
685-
Ok(mut file) => from_tzdata_file(&mut file, tz_string),
686-
Err(err) => Err(err.into()),
687-
}
688-
}
689-
690642
// Possible system timezone directories
691643
#[cfg(unix)]
692644
const ZONE_INFO_DIRECTORIES: [&str; 4] =

0 commit comments

Comments
 (0)