Skip to content

Fix: Support Unix millisecond timestamps for schedule-for-stop date parameter#1035

Open
ARCoder181105 wants to merge 6 commits into
OneBusAway:mainfrom
ARCoder181105:fix/schedule-stop-unix-date
Open

Fix: Support Unix millisecond timestamps for schedule-for-stop date parameter#1035
ARCoder181105 wants to merge 6 commits into
OneBusAway:mainfrom
ARCoder181105:fix/schedule-stop-unix-date

Conversation

@ARCoder181105

@ARCoder181105 ARCoder181105 commented Jun 6, 2026

Copy link
Copy Markdown
Collaborator

Description

Updates the schedule-for-stop endpoint to accept Unix millisecond integers for the date parameter, resolving an issue where only YYYY-MM-DD formatted strings were supported. This brings the endpoint into full compliance with the API specification.

Changes Made

  • Validation Update: Modified utils.ValidateDate to accept valid 64-bit integers (Unix milliseconds) in addition to the standard YYYY-MM-DD format.
  • Handler Update: Modified scheduleForStopHandler to parse the incoming integer timestamp, convert it to a timezone-aware date using the agency's location, and echo it back correctly in the response.
  • Testing: Added new unit tests in both validation_test.go and schedule_for_stop_handler_test.go to verify integer parsing, error handling for invalid strings, and correct JSON property mapping.

Closes #1029

Summary by CodeRabbit

  • New Features

    • The schedule-for-stop API now accepts the date parameter as either Unix milliseconds or a YYYY-MM-DD date string.
  • Bug Fixes / Validation

    • Improved validation with clearer error messages that state both accepted formats and return a specific error when a numeric timestamp is out of valid range.

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@ARCoder181105, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 49 minutes and 36 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f63e098f-f13a-45a9-8299-cd1d99bf8421

📥 Commits

Reviewing files that changed from the base of the PR and between 40c22f7 and a4a9c2f.

📒 Files selected for processing (1)
  • internal/restapi/schedule_for_stop_handler_test.go
📝 Walkthrough

Walkthrough

The PR makes date query parsing accept either a Unix-millisecond integer or a YYYY-MM-DD string by extending validation, updating the schedule-for-stop handler to handle both formats in agency time, and adding tests that assert returned date values for both formats.

Changes

Date Format Expansion

Layer / File(s) Summary
Date validation utility enhancement
internal/utils/validation.go, internal/utils/validation_test.go
ValidateDate now attempts to parse the input as a base-10 Unix millisecond integer (with min/max bounds) and falls back to YYYY-MM-DD parsing if that fails. Error messaging consolidated; tests add unix-ms cases and reuse a shared expected error message.
Schedule-for-stop handler integration
internal/restapi/schedule_for_stop_handler.go, internal/restapi/schedule_for_stop_handler_test.go
Handler parsing now accepts unix-ms or YYYY-MM-DD; unix-ms values are converted to agency-local time and decomposed to date/targetDate/weekday. Tests verify both formats and assert returned date equals the unix-ms timestamp.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • OneBusAway/maglev#911: Also extends schedule endpoint date parsing to accept epoch-milliseconds alongside YYYY-MM-DD.

Suggested reviewers

  • burma-shave
  • Ahmedhossamdev
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 28.57% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately summarizes the main change: adding Unix millisecond timestamp support to the schedule-for-stop date parameter.
Linked Issues check ✅ Passed The pull request fully addresses all coding requirements from issue #1029: accepts both YYYY-MM-DD strings and Unix milliseconds, maintains backward compatibility, and includes comprehensive unit tests.
Out of Scope Changes check ✅ Passed All changes are directly related to the objective of supporting Unix millisecond timestamps in the schedule-for-stop date parameter, with no unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
internal/utils/validation_test.go (1)

441-445: ⚡ Quick win

Add test cases for Unix timestamp edge cases.

While the valid Unix timestamp test is good, consider adding test cases for edge cases such as negative timestamps, extremely large values, and zero. This would ensure the validation properly handles out-of-range inputs.

📝 Suggested additional test cases
 		{
 			name:    "valid unix timestamp in milliseconds",
 			date:    "1749686400000",
 			wantErr: false,
 		},
+		{
+			name:    "negative unix timestamp",
+			date:    "-1000000000",
+			wantErr: true,
+			errMsg:  expectedErrMsg,
+		},
+		{
+			name:    "unix timestamp far in future",
+			date:    "9999999999999",
+			wantErr: true,
+			errMsg:  expectedErrMsg,
+		},
 		{
 			name:    "empty date is valid",
 			date:    "",
 			wantErr: false,
 		},
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/utils/validation_test.go` around lines 441 - 445, The existing test
case "valid unix timestamp in milliseconds" in validation_test.go lacks edge
coverage; add additional cases in the tests slice used by the Test... function
(the table-driven tests around name/date/wantErr) that include negative
timestamp (e.g., "-1000"), zero ("0"), and an extremely large value (e.g., a
value beyond int64 range or a very large millisecond value) with appropriate
expected wantErr booleans; update the test table entries so functions that
validate Unix timestamps (the test cases referencing the date field in the
table-driven test) exercise these edge cases to ensure out-of-range handling is
covered.
internal/restapi/schedule_for_stop_handler_test.go (1)

87-101: ⚡ Quick win

Strengthen test to validate actual date value for YYYY-MM-DD format.

The current test only checks assert.NotNil(entry["date"]) but doesn't validate that the date field contains the expected Unix millisecond value. Validating the actual value would catch bugs like incorrect date parsing or formatting issues (such as the variable shadowing issue identified in the handler).

📝 Proposed enhancement
 	t.Run("Valid date parameter in format YYYY-MM-DD", func(t *testing.T) {
 		// NOTE: Hardcoded date 2025-06-12 used for test consistency with GTFS data validity
 		endpoint := "/api/where/schedule-for-stop/" + stopID + ".json?key=TEST&date=2025-06-12"
 		resp, model := serveApiAndRetrieveEndpoint(t, api, endpoint)
 
 		assert.Equal(t, http.StatusOK, resp.StatusCode)
 		assert.Equal(t, http.StatusOK, model.Code)
 		assert.Equal(t, "OK", model.Text)
 
 		data, ok := model.Data.(map[string]any)
 		assert.True(t, ok)
 		entry, ok := data["entry"].(map[string]any)
 		assert.True(t, ok)
 		assert.NotNil(t, entry["date"])
+		// Validate that the date field contains the expected Unix millisecond timestamp
+		// 2025-06-12 00:00:00 in the agency timezone
+		assert.Equal(t, float64(1749686400000), entry["date"])
 	})
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/restapi/schedule_for_stop_handler_test.go` around lines 87 - 101,
Update the test to assert the actual Unix millisecond value for the date instead
of only checking non-nil: parse "2025-06-12" with time.Parse("2006-01-02",
"2025-06-12"), compute expectedMillis := parsedTime.UnixMilli(), extract the
returned entry map from model.Data (the same entry variable used in this test)
and compare entry["date"] (convert the JSON number to the appropriate numeric
type) to expectedMillis using assert.Equal so the test fails if the handler
returns an incorrectly parsed or formatted date.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@internal/restapi/schedule_for_stop_handler.go`:
- Line 66: Update the error message for the "date" field in the
schedule_for_stop_handler.go error map to exactly match the validation utility
string from utils.ValidateDate: "invalid date format, use YYYY-MM-DD or a Unix
millisecond integer" (note the lowercase 'i' and comma). Locate the map entry
that sets "date": {"Invalid date format. Use YYYY-MM-DD or a Unix millisecond
integer"} and replace its value with the exact text returned by
utils.ValidateDate so messages are consistent across ValidateDate and the
handler.
- Around line 54-76: The YYYY-MM-DD branch is shadowing parsedDate by using
"parsedDate, err := time.ParseInLocation(...)" which leaves the outer parsedDate
zero-valued; change that to assign to the existing variables (use "=" not ":=")
so the outer parsedDate and err are updated, ensuring subsequent uses
(targetDate = parsedDate.Format(...) and weekday =
strings.ToLower(parsedDate.Weekday().String())) use the correctly parsed date;
update the ParseInLocation call in schedule_for_stop_handler.go accordingly and
keep the existing handling of date and date = parsedDate.UnixMilli().

In `@internal/utils/validation.go`:
- Around line 110-113: The code currently accepts any int64 from
strconv.ParseInt(date, 10, 64) without range checks; change this to parse the
value into a variable (e.g., v, err := strconv.ParseInt(...)) then validate that
v is within reasonable Unix-millisecond bounds (for example minUnixMillis :=
int64(0) to disallow negative/pre-epoch values and maxUnixMillis :=
int64(32503680000000) which corresponds to year 3000) and return an error when v
< minUnixMillis or v > maxUnixMillis; add descriptive error text and consider
extracting the bounds as named constants to clarify intent.

---

Nitpick comments:
In `@internal/restapi/schedule_for_stop_handler_test.go`:
- Around line 87-101: Update the test to assert the actual Unix millisecond
value for the date instead of only checking non-nil: parse "2025-06-12" with
time.Parse("2006-01-02", "2025-06-12"), compute expectedMillis :=
parsedTime.UnixMilli(), extract the returned entry map from model.Data (the same
entry variable used in this test) and compare entry["date"] (convert the JSON
number to the appropriate numeric type) to expectedMillis using assert.Equal so
the test fails if the handler returns an incorrectly parsed or formatted date.

In `@internal/utils/validation_test.go`:
- Around line 441-445: The existing test case "valid unix timestamp in
milliseconds" in validation_test.go lacks edge coverage; add additional cases in
the tests slice used by the Test... function (the table-driven tests around
name/date/wantErr) that include negative timestamp (e.g., "-1000"), zero ("0"),
and an extremely large value (e.g., a value beyond int64 range or a very large
millisecond value) with appropriate expected wantErr booleans; update the test
table entries so functions that validate Unix timestamps (the test cases
referencing the date field in the table-driven test) exercise these edge cases
to ensure out-of-range handling is covered.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 5760160c-daa0-4e9a-ada5-0e95fe882817

📥 Commits

Reviewing files that changed from the base of the PR and between e99ee63 and c5d5f7c.

📒 Files selected for processing (4)
  • internal/restapi/schedule_for_stop_handler.go
  • internal/restapi/schedule_for_stop_handler_test.go
  • internal/utils/validation.go
  • internal/utils/validation_test.go

Comment thread internal/restapi/schedule_for_stop_handler.go
Comment thread internal/restapi/schedule_for_stop_handler.go Outdated
Comment thread internal/utils/validation.go
ARCoder181105 and others added 3 commits June 6, 2026 23:22
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@ARCoder181105

Copy link
Copy Markdown
Collaborator Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jun 6, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
internal/restapi/schedule_for_stop_handler_test.go (1)

71-74: 💤 Low value

Consider handling errors from time parsing for clearer test failures.

Lines 71-72 ignore errors from time.LoadLocation and time.ParseInLocation. While the test expects these to succeed, handling errors would provide clearer diagnostics if the test setup is incorrect.

🧪 Proposed improvement for error handling
-				loc, _ := time.LoadLocation(agencies[0].Timezone)
-				parsedTime, _ := time.ParseInLocation("2006-01-02", "2025-06-12", loc)
+				loc, err := time.LoadLocation(agencies[0].Timezone)
+				assert.NoError(t, err, "Should load agency timezone")
+				parsedTime, err := time.ParseInLocation("2006-01-02", "2025-06-12", loc)
+				assert.NoError(t, err, "Should parse test date")
 				expectedMillis := float64(parsedTime.UnixMilli())
 				assert.Equal(t, expectedMillis, entry["date"])
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/restapi/schedule_for_stop_handler_test.go` around lines 71 - 74, The
test currently ignores errors from time.LoadLocation and time.ParseInLocation
(variables loc and parsedTime) which can hide setup failures; update the test to
check and fail on those errors (e.g., use t.Fatalf or require.NoError) after
calling time.LoadLocation and time.ParseInLocation, then compute expectedMillis
from parsedTime and assert.Equal as before so failures show clear diagnostics.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@internal/restapi/schedule_for_stop_handler_test.go`:
- Around line 71-74: The test currently ignores errors from time.LoadLocation
and time.ParseInLocation (variables loc and parsedTime) which can hide setup
failures; update the test to check and fail on those errors (e.g., use t.Fatalf
or require.NoError) after calling time.LoadLocation and time.ParseInLocation,
then compute expectedMillis from parsedTime and assert.Equal as before so
failures show clear diagnostics.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: e035ee79-a2c4-447f-a486-aba5655da1bb

📥 Commits

Reviewing files that changed from the base of the PR and between e99ee63 and 40c22f7.

📒 Files selected for processing (4)
  • internal/restapi/schedule_for_stop_handler.go
  • internal/restapi/schedule_for_stop_handler_test.go
  • internal/utils/validation.go
  • internal/utils/validation_test.go

@sonarqubecloud

sonarqubecloud Bot commented Jun 6, 2026

Copy link
Copy Markdown

@ARCoder181105 ARCoder181105 requested a review from burma-shave June 6, 2026 19:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

schedule-for-stop: Missing Unix millisecond support for date parameter

1 participant