Repository navigation
Conversation
|
Hey, thanks for picking up the issue I opened. I ran its reproduction against this PR's current head (Dask offline store, three host time zones), and with
Passing a naive Tested with Python 3.11, pandas 2.3.3, pyarrow 25.0.1 and dask 2026.8.0 on 2026-10-24. |
|
Thanks for verifying the fix across all three host time zones — that table matches exactly what the change is meant to do, and thanks for catching that a naive Yes, please do share the unit test asserting the |
When entity_df is None, end_date defaulted to datetime.now(), a naive host-local wall-clock timestamp. Offline stores interpret naive datetimes as UTC, so the retrieval window shifts by the host's UTC offset (rows missing west of UTC, future rows returned east of it). Default to datetime.now(tz=_timezone.utc), matching the existing usage of the same expression in this file. Signed-off-by: NUAAwqy <146524024+NUAAwqy@users.noreply.github.com>
72a1784 to
95391a6
Compare
|
Thanks. Here it is, written for def test_get_historical_features_non_entity_default_end_date_is_utc(tmp_path):
"""With entity_df=None and no end_date, the end bound handed to the provider
must be the current time in UTC. Offline stores read a naive datetime as UTC
(utils.make_tzaware), so a naive local value shifts the window by the host offset."""
from datetime import datetime, timedelta, timezone
from feast import Entity, FeatureView, Field, FileSource
from feast.infra.offline_stores.dask import DaskOfflineStoreConfig
from feast.infra.online_stores.sqlite import SqliteOnlineStoreConfig
from feast.repo_config import RepoConfig
from feast.types import Int64
store = FeatureStore(
config=RepoConfig(
project="non_entity_default_end_date",
registry=str(tmp_path / "registry.db"),
provider="local",
entity_key_serialization_version=3,
offline_store=DaskOfflineStoreConfig(),
online_store=SqliteOnlineStoreConfig(path=str(tmp_path / "online.db")),
)
)
driver = Entity(name="driver", join_keys=["driver_id"])
driver_stats = FeatureView(
name="driver_stats",
entities=[driver],
ttl=timedelta(days=1),
schema=[Field(name="driver_id", dtype=Int64), Field(name="value", dtype=Int64)],
source=FileSource(
path=str(tmp_path / "driver_stats.parquet"),
timestamp_field="event_timestamp",
),
)
store.apply([driver, driver_stats])
provider = MagicMock()
before = datetime.now(timezone.utc)
with patch.object(FeatureStore, "_get_provider", return_value=provider):
store.get_historical_features(entity_df=None, features=["driver_stats:value"])
after = datetime.now(timezone.utc)
end_date = provider.get_historical_features.call_args.kwargs["end_date"]
assert end_date.utcoffset() == timedelta(0)
assert before <= utils.make_tzaware(end_date) <= aftercd sdk/python && TZ=America/Sao_Paulo python -m pytest tests/unit/test_unit_feature_store.py -k default_end_date_is_utcOn master it fails with |
95391a6 to
07d7792
Compare
Problem
get_historical_featureswithentity_df=Nonedefaultsend_datetodatetime.now()— naive host-local wall-clock time. Offline stores read naive datetimes as UTC, so the retrieval window shifts by the host's UTC offset. Repro table in #7036: underTZ=Asia/Tokyoomittingend_datereturns a row stamped 1h in the future; underTZ=America/Sao_Pauloit misses the newest row.Fix
One line in
sdk/python/feast/feature_store.py:This makes the default equal to passing
end_date=datetime.now(timezone.utc)(the documented behavior, "defaults to the current time"), and matches the existing precedent in this same file:now_ts.FromDatetime(datetime.now(tz=_timezone.utc)).fixes #7036
Disclosure: this change was prepared with AI assistance; the defect analysis and the fix were verified by hand against the current source.