Skip to content

utils

Shared utility functions for timestamp extraction, geometry hashing, temporal grouping, and file filtering.

utils

Shared utility functions for the traffic congestion pipeline.

Covers timestamp extraction, geometry hashing, temporal grouping, day-type filtering, and file-range selection.

extract_timestamp

extract_timestamp(filepath)

Extract a timezone-aware timestamp from a traffic GeoPackage filename.

Expected pattern: *_YYYYMMDD_HHMMSS.gpkg

Returns:

Type Description
datetime

Localized to :data:trafficpipeline.config.TIMEZONE (GMT+7).

Source code in src/trafficpipeline/utils.py
def extract_timestamp(filepath: str | Path) -> datetime:
    """Extract a timezone-aware timestamp from a traffic GeoPackage filename.

    Expected pattern: ``*_YYYYMMDD_HHMMSS.gpkg``

    Returns
    -------
    datetime
        Localized to :data:`trafficpipeline.config.TIMEZONE` (GMT+7).
    """
    filename = Path(filepath).name
    match = _TS_RE.search(filename)
    if not match:
        raise ValueError(f"Cannot extract timestamp from '{filename}'")
    dt = datetime.strptime(f"{match.group(1)}_{match.group(2)}", "%Y%m%d_%H%M%S")
    return pytz.timezone(TIMEZONE).localize(dt)

geometry_hash

geometry_hash(geometry, precision=6)

Return an MD5 hex-digest of geometry with coordinates rounded.

Works for any Shapely geometry type (Point, LineString, MultiLineString, etc.).

Source code in src/trafficpipeline/utils.py
def geometry_hash(geometry, precision: int = 6) -> str:
    """Return an MD5 hex-digest of *geometry* with coordinates rounded.

    Works for any Shapely geometry type (Point, LineString,
    MultiLineString, etc.).
    """
    from shapely.wkt import loads

    if isinstance(geometry, str):
        geometry = loads(geometry)

    def _round(m: re.Match) -> str:
        return f"{float(m.group()):.{precision}f}"

    rounded = _NUM_RE.sub(_round, geometry.wkt)
    return hashlib.md5(rounded.encode()).hexdigest()

is_weekday

is_weekday(ts)

True if ts is Monday-Friday.

Source code in src/trafficpipeline/utils.py
def is_weekday(ts: datetime) -> bool:
    """True if *ts* is Monday-Friday."""
    return ts.weekday() < 5

is_weekend

is_weekend(ts)

True if ts is Saturday or Sunday.

Source code in src/trafficpipeline/utils.py
def is_weekend(ts: datetime) -> bool:
    """True if *ts* is Saturday or Sunday."""
    return ts.weekday() >= 5

matches_day_type

matches_day_type(ts, day_type)

Check whether ts matches day_type ('all', 'weekday', or 'weekend').

Source code in src/trafficpipeline/utils.py
def matches_day_type(ts: datetime, day_type: str) -> bool:
    """Check whether *ts* matches *day_type* (``'all'``, ``'weekday'``, or ``'weekend'``)."""
    if day_type == "all":
        return True
    if day_type == "weekday":
        return is_weekday(ts)
    if day_type == "weekend":
        return is_weekend(ts)
    raise ValueError(f"Unknown day_type: {day_type!r}")

temporal_group_key

temporal_group_key(ts, grouping)

Classify ts into a temporal group label.

Parameters:

Name Type Description Default
grouping str

One of 'daily', 'weekly', 'monthly', 'quarterly', 'yearly', 'all'.

required
Source code in src/trafficpipeline/utils.py
def temporal_group_key(ts: datetime, grouping: str) -> str:
    """Classify *ts* into a temporal group label.

    Parameters
    ----------
    grouping : str
        One of ``'daily'``, ``'weekly'``, ``'monthly'``,
        ``'quarterly'``, ``'yearly'``, ``'all'``.
    """
    if grouping == "daily":
        return ts.strftime("%Y-%m-%d")
    if grouping == "weekly":
        iso = ts.isocalendar()
        return f"{iso[0]}-W{iso[1]:02d}"
    if grouping == "monthly":
        return f"{ts.year}-{ts.month:02d}"
    if grouping == "quarterly":
        return f"{ts.year}-Q{(ts.month - 1) // 3 + 1}"
    if grouping == "yearly":
        return str(ts.year)
    if grouping == "all":
        return "all_time"
    raise ValueError(f"Unknown grouping: {grouping!r}")

filter_files_by_date_range

filter_files_by_date_range(file_list, start_date, end_date)

Keep only files whose embedded timestamp falls in [start_date, end_date].

Dates are strings in YYYY-MM-DD format.

Source code in src/trafficpipeline/utils.py
def filter_files_by_date_range(
    file_list: list[str | Path],
    start_date: str,
    end_date: str,
) -> list[Path]:
    """Keep only files whose embedded timestamp falls in [*start_date*, *end_date*].

    Dates are strings in ``YYYY-MM-DD`` format.
    """
    tz = pytz.timezone(TIMEZONE)
    start = tz.localize(datetime.strptime(start_date, "%Y-%m-%d"))
    end = tz.localize(
        datetime.strptime(end_date, "%Y-%m-%d").replace(hour=23, minute=59, second=59)
    )
    result: list[Path] = []
    for fp in file_list:
        try:
            ts = extract_timestamp(fp)
        except ValueError:
            continue
        if start <= ts <= end:
            result.append(Path(fp))
    return result

composite_osm_id

composite_osm_id(osmid, u, v, key)

Create a composite string ID from OSM edge attributes.

Source code in src/trafficpipeline/utils.py
def composite_osm_id(osmid, u, v, key) -> str:
    """Create a composite string ID from OSM edge attributes."""
    return f"{osmid}_{u}_{v}_{key}"

synthetic_id

synthetic_id(index, start=9000000000)

Create a synthetic ID for an unmatched traffic segment.

Source code in src/trafficpipeline/utils.py
def synthetic_id(index: int, start: int = 9_000_000_000) -> str:
    """Create a synthetic ID for an unmatched traffic segment."""
    return f"SYNTHETIC_{start + index}"