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.
Common errors
-
Failed building wheel for cftime
cause This error typically occurs during installation on Linux systems when the required C/C++ compilers (like gcc) and Python development headers are missing, which are necessary to compile `cftime`'s C extensions.fixInstall the necessary build tools and Python development headers. For Debian/Ubuntu-based systems: `sudo apt-get update && sudo apt-get install python3-dev gcc`. For systems using Anaconda/Miniconda, use `conda install cftime` which provides pre-compiled binaries. -
TypeError: unsupported operand type(s) for +: 'cftime._cftime.DatetimeNoLeap' and 'datetime.timedelta'
cause Direct arithmetic operations with `datetime.timedelta` are not universally supported by all `cftime.datetime` calendar types, especially non-standard ones, as `datetime.timedelta` assumes a standard Gregorian-like calendar system. The `cftime.datetime` instances are calendar-aware and require specific methods for time arithmetic.fixFor standard calendar types, ensure the `cftime.datetime` object is calendar-aware and try `cftime.datetime`'s own arithmetic or conversion methods. For non-standard calendars, it's often best to convert the `cftime.datetime` object to a numerical representation (e.g., days/seconds since an epoch) for arithmetic operations, and then convert back to a `cftime.datetime` object. -
TypeError: <class 'cftime._cftime.Datetime360Day'> is not convertible to datetime
cause Python's native `datetime.datetime` objects only support standard Gregorian and Julian calendars. `cftime.datetime` instances representing non-standard calendars (like '360_day', 'noleap', '365_day') cannot be directly converted to `datetime.datetime` because the native Python object lacks the capability to represent these calendar systems.fixIf a native `datetime.datetime` object is absolutely required, you must first convert the `cftime.datetime` object to a compatible calendar (e.g., 'standard' or 'proleptic_gregorian') if the conversion is meaningful for your data, or manually extract its components (year, month, day, etc.) and handle them separately. The `cftime.num2pydate` function can convert `cftime.datetime` objects to Python `datetime` objects if the calendar is compatible. -
ValueError: given calendar 'invalid_calendar_name' is not a supported calendar
cause This error occurs when the `calendar` argument provided to `cftime.datetime` or related functions does not match one of the predefined and supported CF-compliant calendar strings.fixUse one of the valid CF-compliant calendar strings. The supported calendars are: `'standard'`, `'gregorian'`, `'proleptic_gregorian'`, `'noleap'`, `'365_day'`, `'360_day'`, `'julian'`, `'all_leap'`, `'366_day'`.
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 num2date; # if expecting python datetime objects
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}")