summaryrefslogtreecommitdiffstats
path: root/src/timezone.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/timezone.rs')
-rw-r--r--src/timezone.rs134
1 files changed, 134 insertions, 0 deletions
diff --git a/src/timezone.rs b/src/timezone.rs
new file mode 100644
index 0000000..0d76e50
--- /dev/null
+++ b/src/timezone.rs
@@ -0,0 +1,134 @@
+use std::ops::Deref;
+use std::ffi::{CString,CStr};
+use crate::ical;
+
+use crate::utils::dateutil;
+use super::IcalTime;
+
+pub struct IcalTimeZone {
+ timezone: *mut ical::icaltimezone,
+}
+
+impl Deref for IcalTimeZone {
+ type Target = *mut ical::icaltimezone;
+
+ fn deref(&self) -> &*mut ical::icaltimezone {
+ &self.timezone
+ }
+}
+
+
+impl IcalTimeZone {
+ pub fn from_ptr_copy(ptr: *const ical::icaltimezone) -> Self {
+ let timezone = unsafe {
+ // unsafe, but we know icaltimezone_copy doesn't actually mutate
+ ical::icaltimezone_copy(ptr as *mut ical::icaltimezone)
+ };
+ IcalTimeZone{ timezone }
+ }
+
+ pub fn from_name(tz_name: &str) -> Result<Self,String> {
+ let tz_cstr = CString::new(tz_name).unwrap();
+ let builtin = unsafe { ical::icaltimezone_get_builtin_timezone(tz_cstr.as_ptr()) };
+ if !builtin.is_null() {
+ // need to copy here to guarantee we don't touch the builtin zones
+ let timezone = unsafe { ical::icaltimezone_copy(builtin) };
+ Ok(IcalTimeZone{ timezone })
+ } else {
+ Err(format!("Unknown timezone: {}", tz_name))
+ }
+ }
+
+ pub fn local() -> Self {
+ let tz_name = dateutil::find_local_timezone();
+ IcalTimeZone::from_name(&tz_name).unwrap()
+ }
+
+ pub fn utc() -> Self {
+ let timezone = unsafe { ical::icaltimezone_get_utc_timezone() };
+ IcalTimeZone{ timezone }
+ }
+
+ pub fn get_name(&self) -> String {
+ unsafe {
+ let name = ical::icaltimezone_get_display_name(self.timezone);
+ CStr::from_ptr(name).to_string_lossy().trim().to_string()
+ }
+ }
+
+ pub fn get_offset_at_time(&self, time: &IcalTime) -> i32 {
+ let mut icaltime = **time;
+ let mut is_dst = 0;
+ unsafe {
+ ical::icaltimezone_get_utc_offset(self.timezone, &mut icaltime , &mut is_dst)
+ }
+ }
+
+ pub fn ymd(&self, year: i32, month: i32, day: i32) -> IcalTime {
+ IcalTime::floating_ymd(year, month, day).with_timezone(&self)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use crate::testdata;
+
+ #[test]
+ fn test_utc() {
+ let tz = IcalTimeZone::utc();
+ assert_eq!("UTC", tz.get_name());
+ }
+
+ #[test]
+ fn test_get_offset_utc() {
+ let tz = IcalTimeZone::utc();
+ let time = IcalTime::utc();
+
+ let offset = tz.get_offset_at_time(&time);
+
+ assert_eq!(0, offset);
+ }
+
+ #[test]
+ fn test_ymd() {
+ let tz = IcalTimeZone::from_name("US/Eastern").unwrap();
+ let date = tz.ymd(2014,3,1);
+ assert_eq!(IcalTime::floating_ymd(2014,3,1), date);
+ assert_eq!(1393650000, date.timestamp());
+ assert_eq!("US/Eastern", date.get_timezone().unwrap().get_name());
+ }
+
+ #[test]
+ fn test_ymd_and_hms() {
+ let tz = IcalTimeZone::from_name("US/Eastern").unwrap();
+ let date = tz.ymd(2014,3,1).and_hms(17, 20, 0);
+ assert_eq!(IcalTime::floating_ymd(2014,3,1).and_hms(17, 20, 0), date);
+ assert_eq!(1393712400, date.timestamp());
+ assert_eq!("US/Eastern", date.get_timezone().unwrap().get_name());
+ }
+
+ #[test]
+ fn test_from_name() {
+ let tz = IcalTimeZone::from_name("US/Eastern").unwrap();
+ assert_eq!("US/Eastern", tz.get_name());
+ }
+
+ #[test]
+ fn test_from_name_fail() {
+ let tz = IcalTimeZone::from_name("lulz");
+ assert!(tz.is_err());
+ }
+
+ #[test]
+ fn test_get_offset_eastern() {
+ let time = IcalTime::utc();
+ let tz = IcalTimeZone::from_name("US/Eastern").unwrap();
+
+ let offset = tz.get_offset_at_time(&time);
+
+ assert_eq!(-5*60*60, offset);
+ }
+
+}