Skip to content

Option expirations read as midnight in the server's time zone, not US/Eastern: Carbon::parse without a zone #103

Open

Description

@MarketDataDev02

What happens

An option expiration comes back as midnight in the server's PHP time zone instead of midnight in US/Eastern. With the default date.timezone (UTC), the expiration 2026-09-23 is 2026-09-23 00:00:00 UTC, which is 2026-09-22 20:00 -04:00 in New York: the evening before. On a server set to another zone it is yet another instant, so the value depends on the host.

The same expiration under dateformat=unix is 1790136000, 2026-09-23 04:00:00 UTC: midnight in New York. The two readings are four hours apart (five in winter).

Why

The API writes a date as %Y-%m-%d, meaning that calendar day in US/Eastern (marketDataApi/common/util/date_helper.py::DateHelper.format_date). JSON requests from this SDK send no dateformat (DateFormat applies to CSV only), and on the default format the API sends the expirations of options/expirations as dates. Measured live on 2026-09-22: GET /v1/options/expirations/AAPL/ returned "expirations": ["2026-09-23", …] beside a Unix updated.

Expirations builds each value with Carbon::parse($expiration) and no time zone (L75 for the human-readable format, L85 for the regular one, at ec5181b). A string without a zone takes date_default_timezone_get(). tests/Unit/Options/ExpirationsTest.php compares the result with Carbon::parse('2022-09-23') in that same default zone, so it cannot see the difference.

date_default_timezone_set('UTC');
$expiration = Carbon\Carbon::parse('2026-09-23');
echo $expiration->setTimezone('America/New_York')->toIso8601String(); // 2026-09-22T20:00:00-04:00

Candles, earnings, news, market status and fund candles read their dates with the same Carbon::parse call, so any date-only value they receive reads the same way. Those were not measured here.

Definition of done

  • A date the API sends without a time is midnight America/New_York of that date, whatever the server's date.timezone.
  • Tests that set a default zone other than US/Eastern and assert the wall-clock time and the offset, not equality with another Carbon::parse.

Found while fixing the same defect in the C# SDK (MarketDataApp/sdk-csharp#111, fixed in MarketDataApp/sdk-csharp#114). The Python SDK tracks it in MarketDataApp/sdk-py#143.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

No labels
No labels

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions