How Herbie Handles Time Zone Conversions and Datetimes for Forecasts
Herbie normalizes all model run times and forecast-valid times to naïve UTC timestamps internally, stripping timezone information to ensure consistent arithmetic while allowing users to localize results as needed.
The blaylockbk/herbie repository provides a Python interface for downloading numerical weather prediction data. Understanding how Herbie handles time zone conversions and datetimes for forecasts is essential for accurate data retrieval, as the library enforces a strict UTC-only internal representation to avoid ambiguity across global model sources.
Internal UTC Normalization in Herbie
Converting User Input to Naïve UTC
When instantiating a Herbie object, any supplied date or valid_date parameter is processed through pandas.to_datetime in src/herbie/core.py. The library intentionally removes timezone awareness to create a consistent baseline.
self.date = pd.to_datetime(date) # ← naïve UTC
self.valid_date = pd.to_datetime(valid_date) # ← naïve UTC
This conversion occurs at lines 36-44 of src/herbie/core.py, ensuring that regardless of whether the user passes a string, a datetime object, or a timezone-aware timestamp, the internal representation remains a naïve UTC timestamp.
Validating Run Times Against UTC Now
Herbie validates that requested model runs are not in the future by comparing against the current UTC time. The code explicitly strips timezone information from the current timestamp to maintain consistency with the internal naïve representation:
assert self.date < pd.Timestamp.utcnow().tz_localize(None)
This validation appears at lines 390-392 of src/herbie/core.py, preventing users from requesting forecasts that have not yet been initialized.
How Herbie Latest and Wait Functions Handle Time Zones
HerbieLatest and UTC Timestamp Generation
The HerbieLatest class and related helper functions in src/herbie/latest.py and src/herbie/fast.py automatically generate candidate run times using UTC timestamps, then explicitly remove timezone awareness before passing values to the core Herbie class.
# From src/herbie/latest.py
pd.Timestamp.utcnow().floor(freq).tz_localize(None)
# From src/herbie/fast.py
pd.Timestamp.now("utc").tz_localize(None).floor(freq)
These patterns ensure that even when searching for the most recent available model run, the resulting Herbie object maintains the expected naïve UTC timestamp in its date attribute.
HerbieWait and Polling Intervals
The HerbieWait function extends this pattern by waiting for future model runs to become available. It generates target times using UTC references:
pd.Timestamp("now", tz="utc").floor('1h').replace(tzinfo=None)
This approach allows the polling mechanism to check remote data sources using consistent UTC-based filenames and directory structures while maintaining internal consistency with the naïve timestamp requirement.
Working with Herbie Datetimes in Local Time Zones
While Herbie enforces naïve UTC internally, you can convert output timestamps to localized time zones for display or analysis. Use pytz or zoneinfo to attach timezone information after retrieval:
import pytz
from herbie import Herbie
h = Herbie(date="2024-04-15 12:00", model="gfs")
utc_ts = h.date # Naïve UTC timestamp
# Convert to local time zone
local_ts = utc_ts.tz_localize(pytz.UTC).astimezone(pytz.timezone("America/Chicago"))
print(local_ts) # 2024-04-15 07:00:00-05:00
This pattern preserves Herbie's internal consistency while allowing integration with timezone-aware applications.
Key Source Files for Time Zone Handling
src/herbie/core.py– CentralHerbieclass that parses, validates, and stores run/valid datetimes as naïve UTC (lines 36-44, 390-392).src/herbie/latest.py– ImplementsHerbieLatestandHerbieWaitfunctions that generate UTC timestamps and strip timezone info before instantiation.src/herbie/fast.py– Fast-lookup versionHerbie_latestusingpd.Timestamp.now("utc").tz_localize(None)for UTC normalization.tests/util.py– Containsis_time_betweenutility that works with timezone-awaredatetime.now()but normalizes to naïvetimeobjects for comparison.
Summary
- Herbie converts all user-supplied dates to naïve UTC timestamps using
pandas.to_datetime, removing any timezone awareness. - The library validates model run times against
pd.Timestamp.utcnow().tz_localize(None)to prevent future-date requests. - Helper functions like
HerbieLatestandHerbieWaitgenerate candidate times from UTC sources, then explicitly strip timezone info before passing to the core class. - Users must manually localize timestamps after retrieval if local time zone display is required, using
tz_localize()andastimezone().
Frequently Asked Questions
Does Herbie support timezone-aware datetime objects?
Herbie accepts timezone-aware datetimes as input but immediately converts them to naïve UTC timestamps internally. The pandas.to_datetime call in src/herbie/core.py strips timezone information, ensuring consistent internal representation regardless of input format.
How do I convert Herbie's naïve UTC timestamps to my local time zone?
Attach UTC timezone information using tz_localize('UTC') or pytz.UTC, then convert to your target zone with astimezone(). For example: h.date.tz_localize('UTC').astimezone('America/Denver') returns a timezone-aware datetime in Mountain Time.
What happens if I pass a future date to Herbie?
Herbie raises an AssertionError if the requested model run time is not earlier than the current UTC moment. The validation at lines 390-392 of src/herbie/core.py compares self.date against pd.Timestamp.utcnow().tz_localize(None) to prevent requests for forecasts that do not yet exist.
Which Herbie functions automatically generate UTC timestamps?
The HerbieLatest, Herbie_latest, and HerbieWait functions automatically generate candidate run times using pd.Timestamp.utcnow() or pd.Timestamp.now("utc"), then strip timezone awareness with .tz_localize(None) or .replace(tzinfo=None) before instantiating the core Herbie class.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →