gistools/readers/gtfs/schedule/
calendar_dates.rs

1use crate::{
2    readers::{csv::parse_csv_as_record, parse_gtfs_date},
3    util::Date,
4};
5use alloc::{collections::BTreeMap, string::String};
6use s2json::MValueCompatible;
7
8/// Describes whether service is added or removed on a specific date.
9/// 1 - Service added for this date.
10/// 2 - Service removed for this date.
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub enum GTFSExceptionType {
13    /// Service added for this date.
14    Added = 1,
15    /// Service removed for this date.
16    Removed = 2,
17}
18impl From<i8> for GTFSExceptionType {
19    fn from(s: i8) -> Self {
20        match s {
21            2 => GTFSExceptionType::Removed,
22            _ => GTFSExceptionType::Added,
23        }
24    }
25}
26
27/// # Calendar Dates
28///
29/// **Conditionally Required**
30/// Explicitly activates or disables service on particular dates.
31/// - If used with `calendar.txt`, it modifies the default service patterns.
32/// - If `calendar.txt` is omitted, all service dates must be listed here.
33#[derive(Debug, Default, Clone, PartialEq, MValueCompatible)]
34pub struct GTFSCalendarDate {
35    /// **Required**
36    /// Identifies a set of dates where service exception occurs.
37    /// References `calendar.service_id` if used with `calendar.txt`;
38    /// or acts as a standalone ID if `calendar.txt` is omitted.
39    pub service_id: String,
40    /// **Required**
41    /// Date of the service exception, parsed as a JavaScript Date.
42    /// Originally in GTFS as a YYYYMMDD string (no time component).
43    pub date: String,
44    /// **Required**
45    /// Indicates whether service is added (1) or removed (2) on this date.
46    pub exception_type: i8,
47}
48impl GTFSCalendarDate {
49    /// Create a new GTFSCalendarDate
50    pub fn new(source: &str) -> BTreeMap<String, GTFSCalendarDate> {
51        let mut res = BTreeMap::new();
52        for record in parse_csv_as_record::<GTFSCalendarDate>(source, None, None) {
53            res.insert(record.service_id.clone(), record);
54        }
55        res
56    }
57    /// Get the exception type
58    pub fn exception_type(&self) -> GTFSExceptionType {
59        self.exception_type.into()
60    }
61    /// Get the date
62    pub fn date(&self) -> Date {
63        parse_gtfs_date(&self.date).unwrap_or_default()
64    }
65}