1use errors::*;
2use scanlex::{Scanner, Token};
3use types::*;
4
5#[derive(Clone, Copy, Debug)]
7enum TimeKind {
8 Formal,
9 Informal,
10 AmPm(bool),
11 Unknown,
12}
13
14pub struct DateParser<'a> {
15 s: Scanner<'a>,
16 direct: Direction,
17 maybe_time: Option<(u32, TimeKind)>,
18 pub american: bool, }
20
21impl<'a> DateParser<'a> {
22 pub fn new(text: &'a str) -> DateParser<'a> {
23 DateParser {
24 s: Scanner::new(text).no_float(),
25 direct: Direction::Here,
26 maybe_time: None,
27 american: false,
28 }
29 }
30
31 pub fn american_date(mut self) -> DateParser<'a> {
32 self.american = true;
33 self
34 }
35
36 fn iso_date(&mut self, y: u32) -> DateResult<DateSpec> {
37 let month = self.s.get_int::<u32>()?;
38 self.s.get_ch_matching(&['-'])?;
39 let day = self.s.get_int::<u32>()?;
40 Ok(DateSpec::absolute(y, month, day))
41 }
42
43 fn informal_date(&mut self, day_or_month: u32) -> DateResult<DateSpec> {
44 let month_or_day = self.s.get_int::<u32>()?;
45 let (d, m) = if self.american {
46 (month_or_day, day_or_month)
47 } else {
48 (day_or_month, month_or_day)
49 };
50 Ok(if self.s.peek() == '/' {
51 self.s.get();
52 let y = self.s.get_int::<u32>()?;
53 let y = if y < 100 {
54 if y > 40 {
56 1900 + y
57 } else {
58 2000 + y
59 }
60 } else {
61 y
62 };
63 DateSpec::absolute(y, m, d)
64 } else {
65 DateSpec::FromName(ByName::from_day_month(d, m, self.direct))
66 })
67 }
68
69 fn parse_date(&mut self) -> DateResult<Option<DateSpec>> {
70 let mut t = self.s.next().or_err("empty date string")?;
71
72 let sign = if t.is_char() && t.as_char().unwrap() == '-' {
73 true
74 } else {
75 false
76 };
77 if sign {
78 t = self.s.next().or_err("nothing after '-'")?;
79 }
80 if let Some(name) = t.as_iden() {
81 let shortcut = match name {
82 "now" => Some(0),
83 "today" => Some(0),
84 "yesterday" => Some(-1),
85 "tomorrow" => Some(1),
86 _ => None,
87 };
88 if let Some(skip) = shortcut {
89 return Ok(Some(DateSpec::skip(time_unit("day").unwrap(), skip)));
90 } else
91 if let Some(d) = Direction::from_name(&name) {
93 self.direct = d;
94 }
95 }
96 if self.direct != Direction::Here {
97 t = self.s.next().or_err("nothing after last/next")?;
98 }
99 Ok(match t {
100 Token::Iden(ref name) => {
101 let name = name.to_lowercase();
102 if let Some(by_name) = ByName::from_name(&name, self.direct) {
104 if let Some(month) = by_name.as_month() {
106 let t = self.s.get();
107 if t.is_integer() {
108 let day = t.to_int_result::<u32>()?;
109 return Ok(Some(if self.s.peek() == ',' {
110 self.s.get_char()?; let year = self.s.get_int::<u32>()?;
112 DateSpec::absolute(year, month, day)
113 } else {
114 DateSpec::from_day_month(day, month, self.direct)
116 }));
117 }
118 }
119 Some(DateSpec::FromName(by_name))
120 } else {
121 return date_result("expected week day or month name");
122 }
123 }
124 Token::Int(_) => {
125 let n = t.to_int_result::<u32>()?;
126 let t = self.s.get();
127 if t.finished() {
128 return Ok(Some(DateSpec::absolute(n, 1, 1)));
130 }
131 match t {
132 Token::Iden(ref name) => {
133 let day = n;
134 let name = name.to_lowercase();
135 if let Some(month) = month_name(&name) {
136 if let Ok(year) = self.s.get_int::<u32>() {
137 Some(DateSpec::absolute(year, month, day))
139 } else {
140 Some(DateSpec::from_day_month(day, month, self.direct))
142 }
143 } else if let Some(u) = time_unit(&name) {
144 let mut n = n as i32;
146 if sign {
147 n = -n;
148 } else {
149 let t = self.s.get();
150 let got_ago = if let Some(name) = t.as_iden() {
151 if name == "ago" {
152 n = -n;
153 true
154 } else {
155 return date_result("only expected 'ago'");
156 }
157 } else {
158 false
159 };
160 if !got_ago {
161 if let Some(h) = t.to_integer() {
162 self.maybe_time = Some((h as u32, TimeKind::Unknown));
163 }
164 }
165 }
166 Some(DateSpec::skip(u, n))
167 } else if name == "am" || name == "pm" {
168 self.maybe_time = Some((n, TimeKind::AmPm(name == "pm")));
169 None
170 } else {
171 return date_result("expected month or time unit");
172 }
173 }
174 Token::Char(ch) => match ch {
175 '-' => Some(self.iso_date(n)?),
176 '/' => Some(self.informal_date(n)?),
177 ':' | '.' => {
178 let kind = if ch == ':' {
179 TimeKind::Formal
180 } else {
181 TimeKind::Informal
182 };
183 self.maybe_time = Some((n, kind));
184 None
185 }
186 _ => return date_result(&format!("unexpected char {:?}", ch)),
187 },
188 _ => return date_result(&format!("unexpected token {:?}", t)),
189 }
190 }
191 _ => return date_result(&format!("not expected token {:?}", t)),
192 })
193 }
194
195 fn formal_time(&mut self, hour: u32) -> DateResult<TimeSpec> {
196 let min = self.s.get_int::<u32>()?;
197 let mut tnext = None;
199 let sec = if let Some(t) = self.s.next() {
200 if let Some(ch) = t.as_char() {
201 if ch != ':' {
202 return date_result("expecting ':'");
203 }
204 self.s.get_int::<u32>()?
205 } else {
206 tnext = Some(t);
207 0
208 }
209 } else {
210 0
211 };
212 if tnext.is_none() {
214 tnext = self.s.next();
215 }
216 let micros = if let Some(Some('.')) = tnext.as_ref().map(|t| t.as_char()) {
217 let frac = self.s.grab_while(char::is_numeric);
218 if frac.is_empty() {
219 return date_result("expected fractional second after '.'");
220 }
221 let frac = "0.".to_owned() + &frac;
222 let micros_f = frac.parse::<f64>().unwrap() * 1.0e6;
223 tnext = self.s.next();
224 micros_f as u32
225 } else {
226 0
227 };
228 if tnext.is_none() {
229 Ok(TimeSpec::new(hour, min, sec, micros))
230 } else {
231 let tok = tnext.as_ref().unwrap();
232 if let Some(ch) = tok.as_char() {
233 let expecting_offset = match ch {
234 '+' | '-' => true,
235 _ => return date_result("expected +/- before timezone"),
236 };
237 let offset = if expecting_offset {
238 let h = self.s.get_int::<u32>()?;
239 let (h, m) = if self.s.peek() == ':' {
240 self.s.nextch();
242 (h, self.s.get_int::<u32>()?)
243 } else {
244 let hh = h;
246 let h = hh / 100;
247 let m = hh % 100;
248 (h, m)
249 };
250 let res = 60 * (m + 60 * h);
251 (res as i64) * if ch == '-' { -1 } else { 1 }
252 } else {
253 0
254 };
255 Ok(TimeSpec::new_with_offset(hour, min, sec, offset, micros))
256 } else if let Some(id) = tok.as_iden() {
257 if id == "Z" {
258 Ok(TimeSpec::new_with_offset(hour, min, sec, 0, micros))
259 } else {
260 let hour = DateParser::am_pm(&id, hour)?;
262 Ok(TimeSpec::new(hour, min, sec, micros))
263 }
264 } else {
265 Ok(TimeSpec::new(hour, min, sec, micros))
266 }
267 }
268 }
269
270 fn informal_time(&mut self, hour: u32) -> DateResult<TimeSpec> {
271 let min = self.s.get_int::<u32>()?;
272 let hour = if let Some(t) = self.s.next() {
273 let name = t.to_iden_result()?;
274 DateParser::am_pm(&name, hour)?
275 } else {
276 hour
277 };
278 Ok(TimeSpec::new(hour, min, 0, 0))
279 }
280
281 fn am_pm(name: &str, mut hour: u32) -> DateResult<u32> {
282 if name == "pm" {
283 hour += 12;
284 } else if name != "am" {
285 return date_result("expected am or pm");
286 }
287 Ok(hour)
288 }
289
290 fn hour_time(name: &str, hour: u32) -> DateResult<TimeSpec> {
291 Ok(TimeSpec::new(DateParser::am_pm(name, hour)?, 0, 0, 0))
292 }
293
294 fn parse_time(&mut self) -> DateResult<Option<TimeSpec>> {
295 if let Some(hour_sep) = self.maybe_time {
297 let (h, mut kind) = hour_sep;
299 if let TimeKind::Unknown = kind {
300 kind = match self.s.get_char()? {
301 ':' => TimeKind::Formal,
302 '.' => TimeKind::Informal,
303 ch => return date_result(&format!("expected : or ., not {}", ch)),
304 };
305 }
306 Ok(Some(match kind {
307 TimeKind::Formal => self.formal_time(h)?,
308 TimeKind::Informal => self.informal_time(h)?,
309 TimeKind::AmPm(is_pm) => DateParser::hour_time(if is_pm { "pm" } else { "am" }, h)?,
310 TimeKind::Unknown => unreachable!(),
311 }))
312 } else {
313 if self.s.peek() == 'T' {
315 self.s.nextch();
316 }
317 let t = self.s.get();
318 if t.finished() {
319 return Ok(None);
320 }
321
322 let hour = t.to_int_result::<u32>()?;
323 Ok(Some(match self.s.get() {
324 Token::Char(ch) => match ch {
325 ':' => self.formal_time(hour)?,
326 '.' => self.informal_time(hour)?,
327 ch => return date_result(&format!("unexpected char {:?}", ch)),
328 },
329 Token::Iden(name) => DateParser::hour_time(&name, hour)?,
330 t => return date_result(&format!("unexpected token {:?}", t)),
331 }))
332 }
333 }
334
335 pub fn parse(&mut self) -> DateResult<DateTimeSpec> {
336 let date = self.parse_date()?;
337 let time = self.parse_time()?;
338 Ok(DateTimeSpec {
339 date: date,
340 time: time,
341 })
342 }
343}