helpers

Shared helper functions used across rivia subpackages.

rivia.utils.helpers.check_sim_date(date)[source]

Raise ValueError if date is not in DDMONYYYY format.

The month abbreviation is case-insensitive (e.g. "01jan2020" is valid).

Return type:

None

Parameters:

date (str)

rivia.utils.helpers.check_sim_time(time_str)[source]

Raise ValueError if time_str is not HHMM or HHMMSS with HH <= 24.

Return type:

None

Parameters:

time_str (str)

rivia.utils.helpers.ensure_dir(filepath)[source]

Ensure the parent directory of filepath exists, creating it if needed.

Returns the resolved absolute path as a string, suitable for passing to COM methods that expect a plain string path.

Return type:

str

Parameters:

filepath (str | Path)

rivia.utils.helpers.fix_ras_dates(dates)[source]

Convert HEC-RAS date serial numbers to datetime objects.

HEC-RAS uses an Excel-style 1900 epoch with a -2 day adjustment.

Return type:

list[datetime]

Parameters:

dates (list)

rivia.utils.helpers.format_hec_datetime(d)[source]

Format a datetime.datetime as a HEC-RAS "DDMONYYYY HH:MM:SS" string.

This is the canonical format used in HEC-RAS HDF5 attributes and runtime log timestamps (space separator, colon-separated 24-hour time, uppercase month abbreviation).

Parameters:

d (datetime.datetime)

Returns:

e.g. "01OCT2024 00:00:02"

Return type:

str

Examples

>>> import datetime as dt
>>> format_hec_datetime(dt.datetime(2024, 10, 1, 0, 0, 2))
'01OCT2024 00:00:02'
rivia.utils.helpers.log_call(level=20)[source]

Decorator that logs when a function is called.

Parameters:

level (int) – logging level constant (e.g. logging.INFO, logging.DEBUG). Defaults to logging.INFO.

Examples

>>> from rivia.utils import log_call
>>> import logging
>>> @log_call(logging.INFO)
... def my_func(): ...
rivia.utils.helpers.normalize_sim_end_time(date, time)[source]

Normalize a HEC-RAS simulation end (date, time) pair.

HEC-RAS represents midnight as "2400" on the ending day, but can also produce "0000" on the following day for the same instant. Restart filenames always use the "2400" form, so when time is "0000" this function rolls the date back by one day and substitutes "2400".

Parameters:
  • date (str) – Simulation date in DDMONYYYY format (e.g. "02JAN2026").

  • time (str) – Simulation time in HHMM format (e.g. "0000" or "1200").

Returns:

(date, time) — adjusted when time is "0000", unchanged otherwise.

Return type:

tuple[str, str]

Examples

>>> normalize_sim_end_time("02JAN2026", "0000")
('01JAN2026', '2400')
>>> normalize_sim_end_time("02JAN2026", "1200")
('02JAN2026', '1200')
>>> normalize_sim_end_time("01JAN2026", "2400")
('01JAN2026', '2400')
rivia.utils.helpers.normalize_sim_start_time(date, time)[source]

Normalize a HEC-RAS simulation start (date, time) pair.

HEC-RAS represents midnight as "2400" on the ending day, but the same instant used as a start time should be expressed as "0000" on the following day. When time is "2400" this function advances the date by one day and substitutes "0000".

Parameters:
  • date (str) – Simulation date in DDMONYYYY format (e.g. "01JAN2026").

  • time (str) – Simulation time in HHMM format (e.g. "2400" or "1200").

Returns:

(date, time) — adjusted when time is "2400", unchanged otherwise.

Return type:

tuple[str, str]

Examples

>>> normalize_sim_start_time("01JAN2026", "2400")
('02JAN2026', '0000')
>>> normalize_sim_start_time("01JAN2026", "1200")
('01JAN2026', '1200')
>>> normalize_sim_start_time("01JAN2026", "0000")
('01JAN2026', '0000')
rivia.utils.helpers.parse_hec_datetime(text, fmt=None)[source]

Parse any HEC-RAS combined datetime string.

The date part is always DDMONYYYY (9 characters), followed by a separator (space or comma), then a time part in one of the supported variants:

  • HH:MM:SS — 24-hour with colons (HDF timestamps, runtime log lines)

  • HH:MM:SS AM/PM — 12-hour with colons (Simulation started at: lines)

  • HHMMSS — 6-digit, no colons (space or comma separator)

  • HHMM — 4-digit, no colons (space or comma separator)

HH=24 is handled in all variants: treated as 00:XX:XX on the following day, matching HEC-RAS end-of-day midnight convention.

Parameters:
  • text (str) – HEC-RAS datetime string in any supported format.

  • fmt (str, optional) – strptime format string. When provided, skips auto-detection and uses this format directly. HH=24 is still handled unconditionally because the hour always occupies positions 10–11 in the raw string.

Return type:

datetime.datetime

Raises:

ValueError – If the string is too short, has an unsupported separator, or uses an unrecognised time variant (auto-detect path only).

Examples

>>> parse_hec_datetime("01OCT2024 00:00:02")
datetime.datetime(2024, 10, 1, 0, 0, 2)
>>> parse_hec_datetime("01JAN2026 24:00:00")
datetime.datetime(2026, 1, 2, 0, 0)
>>> parse_hec_datetime("01JAN2026,2400")
datetime.datetime(2026, 1, 2, 0, 0)
>>> parse_hec_datetime("01JAN2026 0002", fmt="%d%b%Y %H%M")
datetime.datetime(2026, 1, 1, 0, 2)
rivia.utils.helpers.parse_interval(text)[source]

Parse a HEC-RAS interval string and return a datetime.timedelta.

HEC-RAS writes interval strings as a number immediately followed by a unit abbreviation, with optional whitespace between them, e.g. '20SEC', '5MIN', '1HR', '1HOUR', '1DAY', '2WEEK'.

Supported units (case-insensitive):

Unit

Timedelta

SEC

timedelta(seconds=n)

MIN

timedelta(minutes=n)

HR

timedelta(hours=n)

HOUR

timedelta(hours=n)

DAY

timedelta(days=n)

WEEK

timedelta(weeks=n)

MONTH

timedelta(days=n*30) (approximate)

YEAR

timedelta(days=n*365) (approximate)

Parameters:

text (str | bytes) – Raw interval string from a HEC-RAS HDF attribute or plan file. Bytes are decoded as UTF-8 before parsing.

Return type:

datetime.timedelta

Raises:

ValueError – If text does not match the expected <number><unit> format or the unit is not recognised.

rivia.utils.helpers.timed(level=35)[source]

Decorator that logs the elapsed wall-clock time of a function call.

Parameters:

level (int) – logging level constant (e.g. logging.INFO, logging.DEBUG). Defaults to logging.DEBUG.

Examples

>>> from rivia.utils import timed
>>> import logging
>>> @timed(logging.INFO)
... def my_func(): ...