1use std::error;
2use std::fmt;
3use std::str::{self, FromStr};
4
5#[cfg(feature = "serde")]
6use serde::{de, ser};
7
8#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
81pub struct Datetime {
82 pub date: Option<Date>,
85
86 pub time: Option<Time>,
89
90 pub offset: Option<Offset>,
93}
94
95#[derive(Debug, Clone)]
97pub struct DatetimeParseError {
98 _private: (),
99}
100
101#[doc(hidden)]
108#[cfg(feature = "serde")]
109pub const FIELD: &str = "$__toml_private_datetime";
110#[doc(hidden)]
111#[cfg(feature = "serde")]
112pub const NAME: &str = "$__toml_private_Datetime";
113
114#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
129pub struct Date {
130 pub year: u16,
132 pub month: u8,
134 pub day: u8,
136}
137
138#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
159pub struct Time {
160 pub hour: u8,
162 pub minute: u8,
164 pub second: u8,
166 pub nanosecond: u32,
168}
169
170#[derive(PartialEq, Eq, PartialOrd, Ord, Copy, Clone, Debug)]
173pub enum Offset {
174 Z,
180
181 Custom {
183 hours: i8,
185
186 minutes: u8,
188 },
189}
190
191impl From<Date> for Datetime {
192 fn from(other: Date) -> Self {
193 Datetime {
194 date: Some(other),
195 time: None,
196 offset: None,
197 }
198 }
199}
200
201impl From<Time> for Datetime {
202 fn from(other: Time) -> Self {
203 Datetime {
204 date: None,
205 time: Some(other),
206 offset: None,
207 }
208 }
209}
210
211impl fmt::Display for Datetime {
212 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
213 if let Some(ref date) = self.date {
214 write!(f, "{}", date)?;
215 }
216 if let Some(ref time) = self.time {
217 if self.date.is_some() {
218 write!(f, "T")?;
219 }
220 write!(f, "{}", time)?;
221 }
222 if let Some(ref offset) = self.offset {
223 write!(f, "{}", offset)?;
224 }
225 Ok(())
226 }
227}
228
229impl fmt::Display for Date {
230 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
231 write!(f, "{:04}-{:02}-{:02}", self.year, self.month, self.day)
232 }
233}
234
235impl fmt::Display for Time {
236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
237 write!(f, "{:02}:{:02}:{:02}", self.hour, self.minute, self.second)?;
238 if self.nanosecond != 0 {
239 let s = format!("{:09}", self.nanosecond);
240 write!(f, ".{}", s.trim_end_matches('0'))?;
241 }
242 Ok(())
243 }
244}
245
246impl fmt::Display for Offset {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 match *self {
249 Offset::Z => write!(f, "Z"),
250 Offset::Custom { hours, minutes } => write!(f, "{:+03}:{:02}", hours, minutes),
251 }
252 }
253}
254
255impl FromStr for Datetime {
256 type Err = DatetimeParseError;
257
258 fn from_str(date: &str) -> Result<Datetime, DatetimeParseError> {
259 if date.len() < 3 {
266 return Err(DatetimeParseError { _private: () });
267 }
268 let mut offset_allowed = true;
269 let mut chars = date.chars();
270
271 let full_date = if chars.clone().nth(2) == Some(':') {
273 offset_allowed = false;
274 None
275 } else {
276 let y1 = u16::from(digit(&mut chars)?);
277 let y2 = u16::from(digit(&mut chars)?);
278 let y3 = u16::from(digit(&mut chars)?);
279 let y4 = u16::from(digit(&mut chars)?);
280
281 match chars.next() {
282 Some('-') => {}
283 _ => return Err(DatetimeParseError { _private: () }),
284 }
285
286 let m1 = digit(&mut chars)?;
287 let m2 = digit(&mut chars)?;
288
289 match chars.next() {
290 Some('-') => {}
291 _ => return Err(DatetimeParseError { _private: () }),
292 }
293
294 let d1 = digit(&mut chars)?;
295 let d2 = digit(&mut chars)?;
296
297 let date = Date {
298 year: y1 * 1000 + y2 * 100 + y3 * 10 + y4,
299 month: m1 * 10 + m2,
300 day: d1 * 10 + d2,
301 };
302
303 if date.month < 1 || date.month > 12 {
304 return Err(DatetimeParseError { _private: () });
305 }
306 if date.day < 1 || date.day > 31 {
307 return Err(DatetimeParseError { _private: () });
308 }
309
310 Some(date)
311 };
312
313 let next = chars.clone().next();
315 let partial_time = if full_date.is_some()
316 && (next == Some('T') || next == Some('t') || next == Some(' '))
317 {
318 chars.next();
319 true
320 } else {
321 full_date.is_none()
322 };
323
324 let time = if partial_time {
325 let h1 = digit(&mut chars)?;
326 let h2 = digit(&mut chars)?;
327 match chars.next() {
328 Some(':') => {}
329 _ => return Err(DatetimeParseError { _private: () }),
330 }
331 let m1 = digit(&mut chars)?;
332 let m2 = digit(&mut chars)?;
333 match chars.next() {
334 Some(':') => {}
335 _ => return Err(DatetimeParseError { _private: () }),
336 }
337 let s1 = digit(&mut chars)?;
338 let s2 = digit(&mut chars)?;
339
340 let mut nanosecond = 0;
341 if chars.clone().next() == Some('.') {
342 chars.next();
343 let whole = chars.as_str();
344
345 let mut end = whole.len();
346 for (i, byte) in whole.bytes().enumerate() {
347 match byte {
348 b'0'..=b'9' => {
349 if i < 9 {
350 let p = 10_u32.pow(8 - i as u32);
351 nanosecond += p * u32::from(byte - b'0');
352 }
353 }
354 _ => {
355 end = i;
356 break;
357 }
358 }
359 }
360 if end == 0 {
361 return Err(DatetimeParseError { _private: () });
362 }
363 chars = whole[end..].chars();
364 }
365
366 let time = Time {
367 hour: h1 * 10 + h2,
368 minute: m1 * 10 + m2,
369 second: s1 * 10 + s2,
370 nanosecond,
371 };
372
373 if time.hour > 24 {
374 return Err(DatetimeParseError { _private: () });
375 }
376 if time.minute > 59 {
377 return Err(DatetimeParseError { _private: () });
378 }
379 if time.second > 59 {
380 return Err(DatetimeParseError { _private: () });
381 }
382 if time.nanosecond > 999_999_999 {
383 return Err(DatetimeParseError { _private: () });
384 }
385
386 Some(time)
387 } else {
388 offset_allowed = false;
389 None
390 };
391
392 let offset = if offset_allowed {
394 let next = chars.clone().next();
395 if next == Some('Z') || next == Some('z') {
396 chars.next();
397 Some(Offset::Z)
398 } else if next.is_none() {
399 None
400 } else {
401 let sign = match next {
402 Some('+') => 1,
403 Some('-') => -1,
404 _ => return Err(DatetimeParseError { _private: () }),
405 };
406 chars.next();
407 let h1 = digit(&mut chars)? as i8;
408 let h2 = digit(&mut chars)? as i8;
409 match chars.next() {
410 Some(':') => {}
411 _ => return Err(DatetimeParseError { _private: () }),
412 }
413 let m1 = digit(&mut chars)?;
414 let m2 = digit(&mut chars)?;
415
416 Some(Offset::Custom {
417 hours: sign * (h1 * 10 + h2),
418 minutes: m1 * 10 + m2,
419 })
420 }
421 } else {
422 None
423 };
424
425 if chars.next().is_some() {
428 return Err(DatetimeParseError { _private: () });
429 }
430
431 Ok(Datetime {
432 date: full_date,
433 time,
434 offset,
435 })
436 }
437}
438
439fn digit(chars: &mut str::Chars<'_>) -> Result<u8, DatetimeParseError> {
440 match chars.next() {
441 Some(c) if ('0'..='9').contains(&c) => Ok(c as u8 - b'0'),
442 _ => Err(DatetimeParseError { _private: () }),
443 }
444}
445
446#[cfg(feature = "serde")]
447impl ser::Serialize for Datetime {
448 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
449 where
450 S: ser::Serializer,
451 {
452 use serde::ser::SerializeStruct;
453
454 let mut s = serializer.serialize_struct(NAME, 1)?;
455 s.serialize_field(FIELD, &self.to_string())?;
456 s.end()
457 }
458}
459
460#[cfg(feature = "serde")]
461impl<'de> de::Deserialize<'de> for Datetime {
462 fn deserialize<D>(deserializer: D) -> Result<Datetime, D::Error>
463 where
464 D: de::Deserializer<'de>,
465 {
466 struct DatetimeVisitor;
467
468 impl<'de> de::Visitor<'de> for DatetimeVisitor {
469 type Value = Datetime;
470
471 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
472 formatter.write_str("a TOML datetime")
473 }
474
475 fn visit_map<V>(self, mut visitor: V) -> Result<Datetime, V::Error>
476 where
477 V: de::MapAccess<'de>,
478 {
479 let value = visitor.next_key::<DatetimeKey>()?;
480 if value.is_none() {
481 return Err(de::Error::custom("datetime key not found"));
482 }
483 let v: DatetimeFromString = visitor.next_value()?;
484 Ok(v.value)
485 }
486 }
487
488 static FIELDS: [&str; 1] = [FIELD];
489 deserializer.deserialize_struct(NAME, &FIELDS, DatetimeVisitor)
490 }
491}
492
493#[cfg(feature = "serde")]
494struct DatetimeKey;
495
496#[cfg(feature = "serde")]
497impl<'de> de::Deserialize<'de> for DatetimeKey {
498 fn deserialize<D>(deserializer: D) -> Result<DatetimeKey, D::Error>
499 where
500 D: de::Deserializer<'de>,
501 {
502 struct FieldVisitor;
503
504 impl<'de> de::Visitor<'de> for FieldVisitor {
505 type Value = ();
506
507 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
508 formatter.write_str("a valid datetime field")
509 }
510
511 fn visit_str<E>(self, s: &str) -> Result<(), E>
512 where
513 E: de::Error,
514 {
515 if s == FIELD {
516 Ok(())
517 } else {
518 Err(de::Error::custom("expected field with custom name"))
519 }
520 }
521 }
522
523 deserializer.deserialize_identifier(FieldVisitor)?;
524 Ok(DatetimeKey)
525 }
526}
527
528#[doc(hidden)]
529#[cfg(feature = "serde")]
530pub struct DatetimeFromString {
531 pub value: Datetime,
532}
533
534#[cfg(feature = "serde")]
535impl<'de> de::Deserialize<'de> for DatetimeFromString {
536 fn deserialize<D>(deserializer: D) -> Result<DatetimeFromString, D::Error>
537 where
538 D: de::Deserializer<'de>,
539 {
540 struct Visitor;
541
542 impl<'de> de::Visitor<'de> for Visitor {
543 type Value = DatetimeFromString;
544
545 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
546 formatter.write_str("string containing a datetime")
547 }
548
549 fn visit_str<E>(self, s: &str) -> Result<DatetimeFromString, E>
550 where
551 E: de::Error,
552 {
553 match s.parse() {
554 Ok(date) => Ok(DatetimeFromString { value: date }),
555 Err(e) => Err(de::Error::custom(e)),
556 }
557 }
558 }
559
560 deserializer.deserialize_str(Visitor)
561 }
562}
563
564impl fmt::Display for DatetimeParseError {
565 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
566 "failed to parse datetime".fmt(f)
567 }
568}
569
570impl error::Error for DatetimeParseError {}