Skip to content

Commit e0aac18

Browse files
feat: add robust datetime parsing fallback to DatetimeBasedCursor
- Add ab_datetime_try_parse as fallback when expected formats fail - Maintain backward compatibility by trying expected formats first - Update schema documentation to reflect new fallback behavior - Update test to use truly unparseable string for error case - Preserve original cursor value format in state storage - Eliminate parsing errors for ISO8601/RFC3339 compliant datetimes Co-Authored-By: AJ Steers <[email protected]>
1 parent eca065f commit e0aac18

File tree

3 files changed

+10
-2
lines changed

3 files changed

+10
-2
lines changed

airbyte_cdk/sources/declarative/declarative_component_schema.yaml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -944,7 +944,9 @@ definitions:
944944
items:
945945
type: string
946946
description: |
947-
The possible formats for the cursor field, in order of preference. The first format that matches the cursor field value will be used to parse it. If not provided, the Outgoing Datetime Format will be used.
947+
The possible formats for the cursor field, in order of preference. The first format that matches the cursor field value will be used to parse it.
948+
If none of the specified formats match, the system will attempt to parse the value using robust datetime parsing that handles most ISO8601/RFC3339 compliant formats.
949+
If not provided, the Outgoing Datetime Format will be used as the first attempt.
948950
Use placeholders starting with "%" to describe the format the API is using. The following placeholders are available:
949951
* **%s**: Epoch unix timestamp - `1686218963`
950952
* **%s_as_float**: Epoch unix timestamp in seconds as float with microsecond precision - `1686218963.123456`

airbyte_cdk/sources/declarative/incremental/datetime_based_cursor.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
)
2222
from airbyte_cdk.sources.message import MessageRepository
2323
from airbyte_cdk.sources.types import Config, Record, StreamSlice, StreamState
24+
from airbyte_cdk.utils.datetime_helpers import ab_datetime_format, ab_datetime_try_parse
2425
from airbyte_cdk.utils.mapping_helpers import _validate_component_request_option_paths
2526

2627

@@ -313,6 +314,11 @@ def parse_date(self, date: str) -> datetime.datetime:
313314
return self._parser.parse(date, datetime_format)
314315
except ValueError:
315316
pass
317+
318+
parsed_dt = ab_datetime_try_parse(date)
319+
if parsed_dt:
320+
return parsed_dt
321+
316322
raise ValueError(f"No format in {self.cursor_datetime_formats} matching {date}")
317323

318324
@classmethod

unit_tests/sources/declarative/incremental/test_datetime_based_cursor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1021,7 +1021,7 @@ def test_given_unknown_format_when_parse_date_then_raise_error():
10211021
parameters={},
10221022
)
10231023
with pytest.raises(ValueError):
1024-
slicer.parse_date("2021-01-01T00:00:00.000000+0000")
1024+
slicer.parse_date("not-a-valid-datetime-string")
10251025

10261026

10271027
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)