{"record":{"id":"f09c59c58df6342d","repo":"NickvisionApps/Parabolic","slug":"end-time-must-be-greater-than-or-equal-to-start-time","errorCode":null,"errorMessage":"End time must be greater than or equal to start time.","messagePattern":"End time must be greater than or equal to start time\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Nickvision.Parabolic.Shared/Models/TimeFrame.cs","lineNumber":20,"sourceCode":"\nnamespace Nickvision.Parabolic.Shared.Models;\n\npublic class TimeFrame : IEquatable<TimeFrame>\n{\n    public TimeSpan Start { get; }\n    public TimeSpan End { get; }\n\n    public string StartString => $\"{Start:c}\";\n    public string EndString => $\"{End:c}\";\n    public TimeSpan Duration => End - Start;\n\n    public TimeFrame(TimeSpan start, TimeSpan end)\n    {\n        Start = start;\n        End = end;\n        if (End < Start)\n        {\n            throw new ArgumentException(\"End time must be greater than or equal to start time.\");\n        }\n        if (Start.Milliseconds > 0)\n        {\n            Start = new TimeSpan(Start.Hours, Start.Minutes, Start.Seconds);\n        }\n        if (End.Milliseconds > 0)\n        {\n            End = new TimeSpan(End.Hours, End.Minutes, End.Seconds);\n        }\n    }\n\n    public static TimeFrame? Parse(string start, string end, TimeSpan duration)\n    {\n        if (string.IsNullOrEmpty(start) || string.IsNullOrEmpty(end) || duration.TotalSeconds <= 0)\n        {\n            return null;\n        }\n        var startParts = start.Split(':');","sourceCodeStart":2,"sourceCodeEnd":38,"githubUrl":"https://github.com/NickvisionApps/Parabolic/blob/1118e6a3abbf5ffc1f764c4c9781f98d4c0482d4/Nickvision.Parabolic.Shared/Models/TimeFrame.cs#L2-L38","documentation":"The TimeFrame constructor throws ArgumentException when the supplied end TimeSpan is earlier than the start TimeSpan. A TimeFrame represents a time interval, so a negative or backwards interval is meaningless and is rejected at construction time. It also silently truncates millisecond components from both bounds, but only after the ordering check.","triggerScenarios":"Calling new TimeFrame(start, end) with end < Start, e.g. TimeFrame(new TimeSpan(10,0,0), new TimeSpan(9,0,0)). Also triggered when computed end values (start plus a negative duration, or values parsed from config/user input in the wrong order) are passed in unvalidated.","commonSituations":"Scheduling download time frames from user input where the user enters start/stop times in the wrong order; timezone or 12h/24h parsing mistakes that swap AM/PM; computing end = start - offset instead of plus.","solutions":["Validate before constructing: ensure end >= start, swapping or normalizing the pair if needed.","Parse user-supplied times consistently (same format/culture/timezone) so ordering comparisons are correct.","If the interval is derived from a duration, construct end as start + duration and assert duration >= TimeSpan.Zero.","Catch ArgumentException at the boundary and surface a user-facing message asking to correct the time range."],"exampleFix":"// before\nvar frame = new TimeFrame(new TimeSpan(endHour, 0, 0), new TimeSpan(startHour, 0, 0));\n// after\nvar start = new TimeSpan(startHour, 0, 0);\nvar end = new TimeSpan(endHour, 0, 0);\nif (end < start) (start, end) = (end, start);\nvar frame = new TimeFrame(start, end);","handlingStrategy":"validation","validationCode":"bool IsValidTimeFrame(TimeSpan start, TimeSpan end) => end >= start;\n// call: if (!IsValidTimeFrame(s, e)) throw new ArgumentException(\"end must be >= start\");","typeGuard":"bool HasValidOrder(TimeSpan start, TimeSpan end) => end >= start;","tryCatchPattern":"try { var frame = new TimeFrame(start, end); }\ncatch (ArgumentException ex) { /* prompt user to fix start/end order */ }","preventionTips":["Normalize or swap start/end before constructing TimeFrame.","Parse times with a single consistent format and culture.","Add a unit test covering equal, ordered, and reversed bounds."],"tags":["argument-validation","timespan","scheduling"],"backgroundTag":"invalid-argument-value","analyzedSha":"1118e6a3abbf5ffc1f764c4c9781f98d4c0482d4","analyzedAt":"2026-09-15T05:27:17.985Z","contentChangedAt":"2026-09-15T05:27:17.985Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}