cftime - CF-Compliant Time Handling
cftime is a Python library providing functionality for decoding time units and variable values in netCDF files that conform to the Climate and Forecasting (CF) conventions. It extends Python's standard datetime module to support various non-standard calendars commonly used in climate science, such as 'noleap', '365_day', '360_day', and 'julian'. The current version is 1.6.5, and the library maintains an active development and release cadence.
Warnings
- breaking Since `cftime` v1.1.0, `cftime.num2date` defaults to returning `cftime.datetime` instances for all calendars. Previously, it would return standard `python datetime` objects when possible.
- breaking In `cftime` v1.2.0, the default `calendar` argument for `cftime.date2num` changed from `'standard'` to `None`. This means the calendar is now inferred from the input `datetime` object(s).
- breaking The legacy functions `cftime.utime`, `cftime.JulianDayFromDate`, and `cftime.DateFromJulianDay` were removed in v1.5.0.
- deprecated The direct use of calendar-specific subclasses (e.g., `cftime.DatetimeNoLeap`) in operations like `cftime.num2date`, `cftime.datetime.__add__`, and `cftime.datetime.__sub__` is deprecated and will be removed in a future release.
- gotcha Performance may degrade when performing calculations with `cftime.datetime` instances that represent dates extremely far from the 1970-01-01 reference date. This is due to the complex leap year calculations across various supported calendars.
- gotcha The 'standard' calendar explicitly marks dates between October 5 and October 14, 1582, as invalid. These dates are skipped to account for the historical Julian-to-Gregorian calendar transition.
Install
-
pip install cftime
Imports
- datetime
from cftime import datetime
- num2date
from cftime import num2date
- date2num
from cftime import date2num
- num2pydate
from cftime import num2pydate
Quickstart
import cftime
import numpy as np
# Create a cftime.datetime object with a specific calendar
date_obj = cftime.datetime(2000, 2, 29, 12, 0, 0, calendar='gregorian')
print(f"Created cftime.datetime (Gregorian): {date_obj}")
# Convert to a numeric representation (e.g., 'days since 2000-01-01')
units = "days since 2000-01-01"
numeric_time = cftime.date2num(date_obj, units=units, calendar=date_obj.calendar)
print(f"Numeric time ({units}): {numeric_time}")
# Convert back to a cftime.datetime object
reconstructed_date = cftime.num2date(numeric_time, units=units, calendar=date_obj.calendar)
print(f"Reconstructed cftime.datetime: {reconstructed_date}")
# Example with a non-standard calendar (360_day has Feb 30)
date_360_day = cftime.datetime(2000, 2, 30, calendar='360_day')
print(f"360-day calendar date: {date_360_day}")