Time-aware list slicing with datetime and calendar-period bounds
Project description
tals — Time-Aware List Slicer
tals makes time-based slicing as natural as ordinary indexing. It extends Python's [start:end] syntax with datetime and calendar-period bounds, and works on any list of objects — it only needs to know which attribute holds the timestamp.
from tals import slice_objects
# Last 7 days
slice_objects(entries, "-7d:", "created_at", reference_dt)
# This calendar month, excluding the last entry
slice_objects(entries, "0M:-1", "created_at", reference_dt)
# February only
slice_objects(entries, "-1M:0M", "created_at", reference_dt)
Installation
pip install tals
Overview
tals extends Python's familiar [start:end] slice syntax with two additional bound types:
- Time-delta bounds — relative to a reference datetime:
-7d,+2h,-30m - Calendar-period bounds — snapped to period boundaries:
0M,-1W,0Y
The library has no domain knowledge. It works on any list of objects and only needs the name of the attribute that holds each object's timestamp.
API
def slice_objects(
objects: list[Any],
position: str,
timestamp_key: str,
reference_dt: datetime,
week_start: int = 0,
) -> Any | list[Any]:
| Parameter | Description |
|---|---|
objects |
List of arbitrary objects in any order |
position |
Slice expression string (see syntax below) |
timestamp_key |
Attribute name holding each object's datetime value |
reference_dt |
The "now" anchor for all relative expressions — the library never calls datetime.now() itself |
week_start |
First day of the week: 0 = Monday (default), 6 = Sunday |
Return value: a single-index expression returns one object (or None if out of bounds); a slice expression returns a list (possibly empty).
The list is stable-sorted ascending by timestamp_key before slicing. All indices operate on this sorted list.
Syntax
[index]
[start:end]
[start:]
[:end]
[:]
Bound types
| Form | Description | Example |
|---|---|---|
0, 1, -1 |
Integer index — same semantics as Python | [-1] → last object |
-7d, +2h, -30m |
Time-delta — relative to reference_dt |
[-7d:] → last 7 days |
0M, -1M, +1M |
Calendar month — start of the Nth month | [0M:] → this month onward |
0W, -1W |
Calendar week — start of the Nth week | [-1W:0W] → last week |
0Y, -1Y |
Calendar year — Jan 1 of the Nth year | [0Y:] → this year onward |
Period 0 is the period containing reference_dt; -1 is the previous period; +1 is the next.
Calendar bounds are not valid as a single index — they only make sense in a slice.
Inclusivity
All bounds follow Python's convention: start is inclusive, end is exclusive.
| Expression | Meaning |
|---|---|
[-7d:] |
timestamp >= reference_dt − 7 days |
[:-7d] |
timestamp < reference_dt − 7 days |
[-1M:0M] |
timestamp >= start of last month and < start of this month |
Mixed bounds
A slice can mix bound types. Time/calendar bounds are resolved to datetime thresholds first, the list is filtered, then integer bounds are applied to the filtered result.
# March entries, excluding the last one
slice_objects(entries, "0M:-1", "created_at", reference_dt)
# → filter to [Mar 1, Apr 1), then apply [:-1]
# From 7 days ago, drop the trailing entry
slice_objects(entries, "-7d:-1", "created_at", reference_dt)
Examples
Given four objects with a start attribute and reference_dt = 2026-03-10:
| Object | start |
|---|---|
| A | 2026-01-10 |
| B | 2026-02-05 |
| C | 2026-03-01 |
| D | 2026-03-10 |
slice_objects(objs, "[-1]", "start", ref) # → D
slice_objects(objs, "[0]", "start", ref) # → A
slice_objects(objs, "[:]", "start", ref) # → [A, B, C, D]
slice_objects(objs, "[:-1]", "start", ref) # → [A, B, C]
slice_objects(objs, "[0M:]", "start", ref) # → [C, D] (March)
slice_objects(objs, "[-1M:0M]", "start", ref) # → [B] (February)
slice_objects(objs, "[-1M:]", "start", ref) # → [B, C, D] (Feb 1 onward)
slice_objects(objs, "[0Y:]", "start", ref) # → [A, B, C, D] (all of 2026)
slice_objects(objs, "[0M:-1]", "start", ref) # → [C] (March, drop last)
Timezone handling
reference_dt and all object timestamps must be either all timezone-aware or all timezone-naive — mixing the two raises TypeError. Objects in different (but both aware) timezones are compared correctly by Python and are fully supported.
Calendar boundaries are computed in the timezone of reference_dt, so 0M on a UTC+02:00 reference resolves to midnight of the 1st in that timezone.
Out of scope
tals is a pure slicing primitive. The following are the caller's responsibility:
- Pre-filtering — pass only the subset of objects that should be considered
- Field extraction — read attributes from the returned objects
- Fallback values — convert
Noneor[]to domain-specific defaults
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file tals-0.1.0.tar.gz.
File metadata
- Download URL: tals-0.1.0.tar.gz
- Upload date:
- Size: 8.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cd76cb98a08d7c25d0e6a22a64985d138a5957cdd3c5798204535cc85f7d033d
|
|
| MD5 |
1d115d3f64f474a3fa544fca7c35a972
|
|
| BLAKE2b-256 |
00fb4d1d69e773a3e37eeb77ab44e22d457674f814744dbf716329d842c01238
|
File details
Details for the file tals-0.1.0-py3-none-any.whl.
File metadata
- Download URL: tals-0.1.0-py3-none-any.whl
- Upload date:
- Size: 6.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dff5f5051dedf9c5d62a132e6c7ba54c712af4b18d362b988f3ae73d3ec587ee
|
|
| MD5 |
7e727db56a4b53b2238226651ad9cd38
|
|
| BLAKE2b-256 |
0368d9fcf813db7de9b4fc3d8bcc8c112a367eafd69e878489fb3d44555227f3
|