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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use crate::ical;
use std::ffi::{CStr, CString};
use std::ops::Deref;
use super::IcalTime;
use crate::utils::dateutil;
/// A type representing a timezone.
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::*;
#[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);
}
}
|