fix: normalize timezone-aware cursor values to UTC before serializing state - #1077
Open
Mariano Benedettini (marianob-span1) wants to merge 1 commit into
Open
Conversation
… state DatetimeParser.format() and the concurrent state converters serialized a timezone-aware cursor datetime using its local wall-clock components, appending a literal `Z` without converting to UTC. A commit timestamp like 2026-07-23T21:59:38+05:30 was stored as 2026-07-23T21:59:38Z instead of the true 2026-07-23T16:29:38Z. For a stream using a global client-side incremental cursor (global_substream_cursor + is_client_side_incremental), this relabeled value wins the global-cursor max and is then used, minus the runtime lookback, as the client-side filter floor — silently dropping legitimate records whose true instant is earlier than the corrupted floor. Observed in source-gitlab's merge_request_commits stream. Fix: normalize datetime values to UTC before serialization in the state converters' output_format (CustomFormat and IsoMillis), treating naive datetimes as UTC to match the existing parse()/from_datetime() convention. This also makes the global-cursor string comparison chronologically correct for fixed-width UTC formats. Related: airbytehq#1014.
Contributor
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughDateTime state converters now serialize timestamps as UTC instants. Naive datetimes are treated as UTC, aware datetimes are converted to UTC, and tests cover both converter formats with positive and negative offsets. ChangesUTC state serialization
Estimated code review effort: 2 (Simple) | ~10 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
DatetimeParser.format() and the concurrent state converters serialized a timezone-aware cursor datetime using its local wall-clock components, appending a literal
Zwithout converting to UTC. A commit timestamp like2026-07-23T21:59:38+05:30was stored as2026-07-23T21:59:38Zinstead of the true2026-07-23T16:29:38Z.For a stream using a global client-side incremental cursor (
global_substream_cursor+is_client_side_incremental), this relabeled value wins the global-cursor max and is then used, minus the runtime lookback, as the client-side filter floor — silently dropping legitimate records whose true instant is earlier than the corrupted floor. Observed insource-gitlab'smerge_request_commitsstream.Fix
Normalize datetime values to UTC before serialization in the state converters'
output_format(CustomFormatConcurrentStreamStateConverterandIsoMillisConcurrentStreamStateConverter), treating naive datetimes as UTC to match the existingparse()/from_datetime()convention. This also makes the global-cursor string comparison chronologically correct for fixed-width UTC formats.Added regression test
test_output_format_normalizes_offset_aware_datetime_to_utccovering positive/negative offsets, UTC-unchanged, and naive-as-UTC cases. It fails without the fix (serializing+05:30/-05:00values as wall-clockZ).Summary by CodeRabbit