1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
// Copyright (c) 2022, Yuri6037
//
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of time-tz nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use crate::timezones::get_by_name;
use crate::Tz;
use thiserror::Error;
#[derive(Debug, Error)]
pub enum Error {
/// An IO error has occurred.
#[error("io error: {0}")]
Io(std::io::Error),
/// An OS level error has occurred (can only happen on Windows).
#[error("low-level os error")]
Os,
/// The timezone is undetermined (means the timezone is not defined or that the system
/// itself doesn't know the its timezone).
#[error("undefined timezone")]
Undetermined,
/// Somehow the read timezone name contains non unicode...
#[error("timezone name is not unicode")]
Unicode,
/// The timezone doesn't exist in the crate's database.
#[error("unknown timezone name")]
Unknown,
}
pub fn get_timezone() -> Result<&'static Tz, Error> {
cfg_if::cfg_if! {
if #[cfg(unix)] {
use std::path::Path;
let path = Path::new("/etc/localtime");
let realpath = std::fs::read_link(path).map_err(Error::Io)?;
// The part of the path we're interested in cannot contain non unicode characters.
if let Some(iana) = realpath.to_str().ok_or(Error::Unicode)?.split("/zoneinfo/").last() {
let tz = get_by_name(iana).ok_or(Error::Unknown)?;
Ok(tz)
} else {
Err(Error::Undetermined)
}
} else {
unsafe {
use windows_sys::Win32::System::Time::GetDynamicTimeZoneInformation;
use windows_sys::Win32::System::Time::DYNAMIC_TIME_ZONE_INFORMATION;
let mut data: DYNAMIC_TIME_ZONE_INFORMATION = std::mem::zeroed();
let res = GetDynamicTimeZoneInformation(&mut data as _);
if res > 2 {
return Err(Error::Os);
} else {
let win_name_utf16 = &data.TimeZoneKeyName;
let mut len: usize = 0;
while win_name_utf16[len] != 0x0 {
len += 1;
}
if len == 0 {
return Err(Error::Undetermined);
}
let win_tz = String::from_utf16(&win_name_utf16[..len]).map_err(|_| Error::Unicode)?;
let tz = get_by_name(&win_tz).ok_or(Error::Unknown)?;
Ok(tz)
}
}
}
}
}
#[cfg(test)]
mod tests {
#[test]
fn get_timezone() {
let tz = super::get_timezone();
assert!(tz.is_ok());
}
}