Repository navigation
fix(calendar): decode bare year ipoDate as a year across all SDKs - #395
Merged
Merged
Conversation
Add a `DateOrYear` codec that keeps a bare `YYYY` year as a year and never widens it to a date. It parses, serialises, and deserialises the two documented forms, exposes `as_date` / `as_year` to report which arrived, and rejects malformed input without echoing the offending value. Record the decision in ADR 0034 and reference it from the shared wire type, Go SDK, and design docs so Python (`datetime.date | int`) and Go (`fmp.DateOrYear`) mappings stay aligned.
Introduce a DateOrYear type that represents a member documented as a "YYYY-MM-DD" date but sometimes sent by the provider as a bare "YYYY" year. It mirrors the DateOrYear type in the Rust crate: a year stays a year and is never widened to a date, and the zero value holds neither form and cannot be encoded. **New capability:** * Added `ParseDateOrYear` accepting exactly a "YYYY-MM-DD" date or four ASCII digits, the same two shapes the Rust crate accepts. * Added `Date`, `Year`, `IsZero`, and `String` accessors that report the form that arrived and return the exact wire text. * Added text and JSON encoding via `MarshalText`, `UnmarshalText`, `MarshalJSONTo`, and `UnmarshalJSONFrom`, rejecting the zero value and any non-string JSON kind including null. **Testing:** * Added tests verifying the parsed form is preserved, invalid shapes are rejected, JSON round-trips are byte-identical, and errors do not echo the offending value.
The provider sometimes sends `ipoDate` as a bare year (e.g. `"2020"`) instead of a full date on IPO prospectus rows, which previously failed to decode. Introduce a `DateOrYear` type across all three SDKs so a full date stays a date and a bare year is preserved as a year. **Response decoding:** * Change `IpoProspectus.ipo_date` in `libfmp` from `Date` to the new `DateOrYear` codec, which decodes either a full date or a bare year and re-encodes it in the shape it was received. **Python bindings:** * Add a `DateOrYear` PyO3 enum exposing the member as `datetime.date | int`, wire it into the `IpoProspectus` model and stub, and support it in `to_dict` and pickling. **Go SDK:** * Change `IPOProspectus.IPODate` to `DateOrYear`, exposing `.Date()` and `.Year()` accessors. **Tests:** * Add Rust, Python, and Go tests covering a year-only `ipoDate`, a full date, and an invalid value that must not echo the raw input in its error. Closes #379 BREAKING CHANGE: IpoProspectus.ipo_date is now DateOrYear in Rust (match Date or Year, or use as_date/as_year), datetime.date | int in Python (a bare year is an int), and fmp.DateOrYear in Go (use .Date() / .Year()). close #379
benbenbang
enabled auto-merge (rebase)
September 30, 2026 14:53
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.
The provider sometimes sends
ipoDateon IPO prospectus rows as a bare year (e.g."2020") instead of a fullYYYY-MM-DDdate, which previously failed to decode. This introduces a shared DateOrYear type across the Rust, Python, and Go SDKs so a full date stays a date, a bare year is preserved as a year, and each is re-encoded in the shape it was received.What changed:
DateOrYearcodec in libfmp that parses, serialises, and deserialises both the date and bare-year forms, reports which arrived viaas_date/as_year, and rejects malformed input without echoing the offending value.IpoProspectus.ipo_datefromDatetoDateOrYearand mapped it consistently:datetime.date | intin Python (withto_dictand pickling support) andfmp.DateOrYearin Go with.Date()/.Year()accessors.DateOrYeartemporal type mirroring the Rust crate, with parsing, accessors, and text/JSON encoding that rejects the zero value and non-string JSON.Closes #379
BREAKING CHANGE: IpoProspectus.ipo_date is now DateOrYear in Rust (match Date or Year, or use as_date/as_year), datetime.date | int in Python (a bare year is an int), and fmp.DateOrYear in Go (use .Date() / .Year()).
close #379