Processor: TimeSlice
Registry key: time_slice | Priority: 150 | Category: Temporal Processing
Subset climate data by date range and optional seasonal filters. Apply calendar-based temporal windowing to extract specific time periods or seasons from multi-year datasets.
Algorithm
flowchart TD
Start([Input: xr.Dataset<br/>or dict/list]) --> CheckType{Input type?}
CheckType -->|dict| DictPath["Iterate over dict items"]
CheckType -->|Dataset| SinglePath["Process single dataset"]
CheckType -->|list/tuple| ListPath["Iterate over sequence"]
DictPath --> CoerceTime["Coerce dates to Timestamp"]
SinglePath --> CoerceTime
ListPath --> CoerceTime
CoerceTime --> TimeSlice["Slice time dimension<br/>data.sel(time=slice start:end)"]
TimeSlice --> HasSeasons{Seasons<br/>specified?}
HasSeasons -->|Yes| FilterSeasons["Filter by season<br/>where dt.season.isin()"]
HasSeasons -->|No| UpdateCtx["Update context metadata"]
FilterSeasons --> UpdateCtx
UpdateCtx --> Return{Return<br/>collection?}
Return -->|dict| ReturnDict["Return dict of datasets"]
Return -->|Dataset| ReturnDS["Return single dataset"]
Return -->|list/tuple| ReturnList["Return same collection type"]
ReturnDict --> End([Output: transformed data])
ReturnDS --> End
ReturnList --> End
click DictPath "https://github.com/cal-adapt/climakitae/blob/main/climakitae/new_core/processors/time_slice.py#L109" "Iterate over dict items"
click SinglePath "https://github.com/cal-adapt/climakitae/blob/main/climakitae/new_core/processors/time_slice.py#L116" "Process single dataset"
click ListPath "https://github.com/cal-adapt/climakitae/blob/main/climakitae/new_core/processors/time_slice.py#L120" "Iterate over sequence"
click CoerceTime "https://github.com/cal-adapt/climakitae/blob/main/climakitae/new_core/processors/time_slice.py#L71" "Coerce dates to Timestamp (call site in __init__)"
click TimeSlice "https://github.com/cal-adapt/climakitae/blob/main/climakitae/new_core/processors/time_slice.py#L162" "Slice time dimension"
click FilterSeasons "https://github.com/cal-adapt/climakitae/blob/main/climakitae/new_core/processors/time_slice.py#L164" "Filter by season"
click UpdateCtx "https://github.com/cal-adapt/climakitae/blob/main/climakitae/new_core/processors/time_slice.py#L131" "Update context metadata"
Execution Flow
- Initialization (lines 52–73): Parse dates parameter (tuple or dict), coerce to pandas Timestamps via
_coerce_to_dates, store optional seasons - Input Routing (lines 108–129):
matchstatement dispatches ondict/xr.Dataset|DataArray/list|tuple; unsupported types log a warning at line 127 - Time Slicing (line 162):
obj.sel(time=slice(self.value[0], self.value[1])) - Season Filtering (lines 163–164): If
self.seasons is not UNSET, applywhere(obj.time.dt.season.isin(self.seasons), drop=True) - Context Update (lines 131–151):
update_contextrecords the operation undercontext["new_attrs"]["time_slice"] - Return: Same container type as input (dict / Dataset|DataArray / list|tuple)
Parameters
| Parameter | Type | Required | Default | Description | Constraints |
|---|---|---|---|---|---|
value |
tuple or dict | ✓ | — | Date range specification | See examples below |
dates |
(date_like, date_like) | ✓ (if dict) | — | Start and end dates for slice | Timestamps, date strings, or year integers |
seasons |
str or list | UNSET | Season(s) to filter | "DJF", "MAM", "JJA", "SON" or list thereof |
Date Formats
Accepted date formats (coerced to pandas Timestamp):
# Year only — interpreted as Jan 1 to Dec 31
("2015", "2015") # Full year 2015
# Year-month
("2015-01", "2015-12") # Jan 2015 to Dec 2015
# Full ISO date
("2015-01-01", "2015-12-31") # Exact range
# Pandas Timestamp objects
(pd.Timestamp("2015-01-01"), pd.Timestamp("2015-12-31"))
# Mixed formats
("2015", "2015-06-30") # Jan 1, 2015 to June 30, 2015
Seasons
Valid season codes (climatological):
- DJF — December, January, February (winter)
- MAM — March, April, May (spring)
- JJA — June, July, August (summer)
- SON — September, October, November (fall)
Code References
| Method | Lines | Purpose |
|---|---|---|
__init__ |
52–73 | Parse and normalize value/dates/seasons |
execute |
76–129 | Route by input type and apply slicing |
update_context |
131–151 | Record operation metadata |
set_data_accessor |
153–155 | No-op placeholder (interface compliance) |
_subset_time_and_season |
157–165 | Core xarray .sel + season .where logic |
Examples
Basic Time Slice (Date Range)
from climakitae.new_core.user_interface import ClimateData
# Full year 2015
data = (ClimateData()
.catalog("cadcat")
.activity_id("WRF")
.variable("t2max")
.table_id("day")
.grid_label("d03")
.processes({
"time_slice": ("2015-01-01", "2015-12-31")
})
.get())
With Seasonal Filter
# Extract summer (JJA) from 2015
data = (ClimateData()
.catalog("cadcat")
.activity_id("WRF")
.variable("t2max")
.table_id("day")
.grid_label("d03")
.processes({
"time_slice": {
"dates": ("2015-01-01", "2015-12-31"),
"seasons": "JJA"
}
})
.get())
Multiple Seasons
# Extract shoulder seasons (spring + fall) from 2010–2020
data = (ClimateData()
.catalog("cadcat")
.activity_id("WRF")
.variable("pr")
.table_id("mon")
.grid_label("d02")
.processes({
"time_slice": {
"dates": ("2010-01-01", "2020-12-31"),
"seasons": ["MAM", "SON"] # Spring and fall only
}
})
.get())
Chained with Other Processors
# Full pipeline: subset time + clip region + export
data = (ClimateData()
.catalog("cadcat")
.activity_id("WRF")
.variable("t2max")
.table_id("day")
.grid_label("d03")
.processes({
"time_slice": ("2020-06-01", "2020-08-31"), # Summer only
"clip": "Los Angeles County",
"export": {
"filename": "la_summer_2020",
"file_format": "NetCDF"
}
})
.get())
Implementation Details
Data Type Handling
TimeSlice handles three input patterns:
-
Single Dataset: Direct slicing and return
-
Dict (from
separatedclipping): Slice each value, preserve keys -
List/Tuple (multi-point outputs): Slice each item, preserve container type
Date Coercion
The _coerce_to_dates() helper (imported from param_validation) handles flexible date input:
- Parses strings using pandas datetime parser (ISO 8601 support)
- Converts year-only inputs to full calendar year (e.g., "2015" → "2015-01-01")
- Validates start ≤ end
Season Filtering
Seasons use xarray's built-in dt.season accessor:
The drop=True removes any time steps outside the selected seasons.
Lazy Evaluation
TimeSlice preserves dask lazy evaluation — the .sel() and .where() operations are lazy and computed only when .compute() is called or data is exported.
Context Metadata
Operation is recorded with full parameter details:
{
"new_attrs": {
"time_slice": "Process 'time_slice' applied to the data. Slicing was done using the following value: (Timestamp('2015-01-01 00:00:00'), Timestamp('2015-12-31 00:00:00'))."
}
}
This is attached to result.attrs["history"] or similar in exported files.
Common Patterns
Extract Specific Months
# January through March (Q1)
data = (ClimateData()
.catalog("cadcat")
.activity_id("WRF")
.variable("pr")
.table_id("day")
.grid_label("d03")
.processes({
"time_slice": {
"dates": ("2020-01-01", "2020-03-31")
}
})
.get())
Annual Trend Analysis
# Loop over multiple years
years = range(2000, 2021)
datasets = {}
for year in years:
start = f"{year}-01-01"
end = f"{year}-12-31"
datasets[year] = (ClimateData()
.catalog("cadcat")
.activity_id("WRF")
.variable("t2max")
.table_id("mon")
.grid_label("d03")
.processes({"time_slice": (start, end)})
.get())
Interannual Variability (Same Season, Multiple Years)
# Summer temperature anomaly: JJA from 2010–2020
data = (ClimateData()
.catalog("cadcat")
.activity_id("WRF")
.variable("t2max")
.table_id("day")
.grid_label("d02")
.processes({
"time_slice": {
"dates": ("2010-01-01", "2020-12-31"),
"seasons": "JJA"
}
})
.get())
# Now data contains only June-August data from 2010–2020
# Group and compute anomalies
anomaly = data.groupby("time.year").mean("time")
See Also
- Processor Index
- Warming Level Processor — Alternative temporal subsetting by climate scenario
- Architecture → Extension Guide
- How-To Guides → Time-Based Queries