Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix calendar generating start_date > end_date #78

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions src/gtfs/native/Association.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,25 +51,33 @@ export class Association implements OverlayRecord {
*/
public apply(base: Schedule, assoc: Schedule, idGenerator: IdGenerator): Schedule[] {
const assocCalendar = this.dateIndicator === DateIndicator.Next ? this.calendar.shiftForward() : this.calendar;
const schedules = [this.mergeSchedules(base, assoc)];
const mergedBase = this.mergeSchedules(base, assoc);
const schedules = mergedBase !== null ? [mergedBase] : [];

// if the associated train starts running before the association, clone the associated schedule for those dates
if (assoc.calendar.runsFrom.isBefore(assocCalendar.runsFrom)) {
const before = assoc.calendar.clone(assoc.calendar.runsFrom, assocCalendar.runsFrom.clone().subtract(1, "days"));

schedules.push(assoc.clone(before, idGenerator.next().value));
if (before !== null) {
schedules.push(assoc.clone(before, idGenerator.next().value));
}
}

// if the associated train runs after the association has finished, clone the associated schedule for those dates
if (assoc.calendar.runsTo.isAfter(assocCalendar.runsTo)) {
const after = assoc.calendar.clone(assocCalendar.runsTo.clone().add(1, "days"), assoc.calendar.runsTo);

schedules.push(assoc.clone(after, idGenerator.next().value));
if (after !== null) {
schedules.push(assoc.clone(after, idGenerator.next().value));
}
}

// for each exclude day of the association
for (const excludeDay of Object.values(assocCalendar.excludeDays)) {
schedules.push(assoc.clone(assoc.calendar.clone(excludeDay, excludeDay), idGenerator.next().value));
const excludeCalendar = assoc.calendar.clone(excludeDay, excludeDay);
if (excludeCalendar !== null) {
schedules.push(assoc.clone(excludeCalendar, idGenerator.next().value));
}
}

return schedules;
Expand All @@ -78,7 +86,7 @@ export class Association implements OverlayRecord {
/**
* Apply the split or join to the given schedules
*/
private mergeSchedules(base: Schedule, assoc: Schedule): Schedule {
private mergeSchedules(base: Schedule, assoc: Schedule): Schedule | null {
let tuid: TUID;
let start: StopTime[];
let assocStop: StopTime;
Expand Down Expand Up @@ -117,16 +125,17 @@ export class Association implements OverlayRecord {

const calendar = this.dateIndicator === DateIndicator.Next ? assoc.calendar.shiftBackward() : assoc.calendar;

return new Schedule(
const newCalendar = calendar.clone(
moment.max(this.calendar.runsFrom, calendar.runsFrom),
moment.min(this.calendar.runsTo, calendar.runsTo)
);
return newCalendar === null ? null : new Schedule(
assoc.id,
stops,
tuid,
assoc.rsid,
// only take the part of the schedule that the association applies to
calendar.clone(
moment.max(this.calendar.runsFrom, calendar.runsFrom),
moment.min(this.calendar.runsTo, calendar.runsTo)
),
newCalendar,
assoc.mode,
assoc.operator,
assoc.stp,
Expand Down
12 changes: 7 additions & 5 deletions src/gtfs/native/ScheduleCalendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ export class ScheduleCalendar {

const calendar = this.clone(this.runsFrom, this.runsTo, NO_DAYS, excludeDays);

return calendar.runsFrom.isSameOrBefore(calendar.runsTo) ? [calendar] : [];
return calendar !== null ? [calendar] : [];
}

/**
Expand All @@ -83,7 +83,7 @@ export class ScheduleCalendar {
* Remove the given date range from this schedule and return one or two calendars
*/
public divideAround(calendar: ScheduleCalendar): ScheduleCalendar[] {
const calendars: ScheduleCalendar[] = [
const calendars: (ScheduleCalendar|null)[] = [
this.clone(this.runsFrom.clone(), calendar.runsFrom.clone().subtract(1, "days")),
this.clone(calendar.runsTo.clone().add(1, "days"), this.runsTo.clone())
];
Expand All @@ -98,7 +98,7 @@ export class ScheduleCalendar {
));
}

return calendars.filter(c => c.runsFrom.isSameOrBefore(c.runsTo));
return calendars.filter((c) : c is ScheduleCalendar => c !== null);
}

/**
Expand All @@ -107,9 +107,11 @@ export class ScheduleCalendar {
public clone(start: Moment,
end: Moment,
removeDays: Days = NO_DAYS,
excludeDays: ExcludeDays = this.excludeDays): ScheduleCalendar {
excludeDays: ExcludeDays = this.excludeDays): ScheduleCalendar | null {

const days = this.removeDays(removeDays);
start = start.clone();
end = end.clone();

// skip forward to the first day the schedule is operating
while (days[start.day()] === 0 || excludeDays[start.format("YYYYMMDD")] && start.isSameOrBefore(end)) {
Expand All @@ -126,7 +128,7 @@ export class ScheduleCalendar {
.filter(d => d.isBetween(start, end, "days", "[]"))
.reduce((days: ExcludeDays, day: Moment) => { days[day.format("YYYYMMDD")] = day; return days; }, {});

return new ScheduleCalendar(start, end, days, newExcludes);
return start.isSameOrBefore(end) ? new ScheduleCalendar(start, end, days, newExcludes) : null;
}

private removeDays(days: Days): Days {
Expand Down