private static void StopTimeTest(IGTFSDataSource source) { IGTFSFeed feed = new LenientGTFSFeed(source); var stopTimes = feed.StopTimes; var tripsByRouteService = feed.Trips.GroupBy(tp => (tp.RouteID, tp.ServiceID)); var timesByTrip = stopTimes.GroupBy(stm => stm.TripID).ToDictionary(stm => stm.Key, stm => new { start = stm.Min(x => x.DepartureTime), end = stm.Max(x => x.ArrivalTime) }); DurationPattern ptn = DurationPattern.CreateWithInvariantCulture("H:mm:ss"); foreach (var group in tripsByRouteService) { var rt = feed.Routes[group.Key.RouteID]; var cal = feed.Calendars[group.Key.ServiceID].Item1; string header = $"{rt.Type} {rt.ShortName} {rt.LongName} - {DayMasks.Get(cal.Mask)}"; Duration min = Duration.MaxValue; Duration max = Duration.MinValue; foreach (var trip in group) { var times = timesByTrip[trip.ID]; min = Duration.Min(times.start.Value, min); max = Duration.Max(times.end.Value, max); } string timeStr = $"{ptn.Format(min)} - {ptn.Format(max)}"; Console.WriteLine($"{header}: {timeStr}"); } }
private static void ProcessEntry(List <LogEntry> entries, int index) { LogEntry entry = entries[index]; // Ignore any "end" actions. Assume they've already been handled (or are useless if they're orphans) if (entry.Action.StartsWith(EndPrefix)) { return; } // If we have a "start" action, find the next matching "start" or "end", and handle appropriately if (entry.Action.StartsWith(StartPrefix)) { string unprefixedAction = entry.Action.Substring(StartPrefix.Length); string expectedEndAction = EndPrefix + unprefixedAction; // Note: in theory we should probably do this by index rather than timing, but it's very unlikely // to cause issues. var nextStart = entries.Skip(index + 1).FirstOrDefault(e => e.Action.StartsWith(entry.Action)); var nextEnd = entries.Skip(index + 1).FirstOrDefault(e => e.Action.StartsWith(expectedEndAction)); if (nextEnd == null) { PrintEntry(entry.Timestamp, null, $"No matching end: {unprefixedAction}"); return; } if (nextStart != null && nextStart.Timestamp < nextEnd.Timestamp) { PrintEntry(entry.Timestamp, null, $"Matching start before end: {unprefixedAction}"); return; } // We report the action in parentheses as a simple indication that it's a compound action. PrintEntry(entry.Timestamp, nextEnd.Timestamp, $"({unprefixedAction})"); return; } // Simple case: just one line for this action, and we're not at the end. Use the next entry. if (index < entries.Count - 1) { PrintEntry(entry.Timestamp, entries[index + 1].Timestamp, entry.Action); } // We only have one line for the action, but it's also the last line of the file. We have a start // but no end, so we can't work out the duration. else { PrintEntry(entry.Timestamp, null, $"Final line of file: {entry.Action}"); } void PrintEntry(Instant start, Instant?end, string action) { string formattedDuration = end != null ? s_durationPattern.Format(end.Value - start) : NoDurationText; Console.WriteLine($"{InstantPattern.General.Format(start)} {formattedDuration} {action}"); } }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { if (value is Duration) { return(hm.Format((Duration)value)); } else { return(value.ToString()); } }
/// <inheritdoc /> public override string ConvertToString(object value, IWriterRow row, MemberMapData memberMapData) { if (value == null) { return(string.Empty); } var duration = (Duration)value; return(DurationPattern.Format(duration)); }
public static string FormatHMS(this Duration duration) { return(hms.Format(duration)); }