HecTime
This guide covers the HecTime class in pydsstools — the datetime
handling system for HEC-DSS files.
HecTime stores time internally as two integers: a julian day (days
since December 31, 1899) and seconds since midnight (0-86400). It
provides parsing, formatting, arithmetic, and conversion to/from Python
datetime objects.
Key Concepts
Concept |
Description |
|---|---|
Julian Day |
Days since December 31, 1899. Julian day 0 = Dec 31, 1899. January 1, 1900 = julian day 1. |
Granularity |
Time precision in seconds. Values: 1 (second), 60 (minute, default), 3600 (hour), 86400 (day). |
midnight_as_2400 |
When True, midnight is represented as 24:00 of the previous day instead of 00:00 of the current day. |
Timestep Value |
Integer encoding of a datetime: |
UNDEFINED_TIME |
Sentinel value for invalid or undefined times. |
split_datetime |
Static method that parses a wide variety of datetime string formats into |
Internal Representation
HecTime("15Jul2019 14:30:00")
_julian = 43661 (days since 31Dec1899)
_seconds_since_midnight = 52200 (14*3600 + 30*60)
_granularity = 60 (minute precision)
Example 1 — Create from Strings
HecTime accepts a wide variety of date/time string formats.
from pydsstools.core import HecTime
# Grid-style format (single colon between date and time)
ht = HecTime("01JAN2000:1200")
print(ht.date()) # "01Jan2000"
print(ht.time()) # "12:00:00"
# Space-separated with colons in time
ht = HecTime("15Jul2019 23:00")
# Space-separated compact time
ht = HecTime("01JAN2000 1430")
# ISO format
ht = HecTime("2000-01-15T10:30:00")
# Date only (time defaults to 00:00)
ht = HecTime("01JAN2000")
print(ht.time()) # "00:00:00"
# With AM/PM
ht = HecTime("Jan 1, 2000 2:30 PM")
Accepted string formats:
Format |
Example |
|---|---|
Grid style |
|
Space + colon time |
|
Space + compact time |
|
ISO/XML |
|
Natural date |
|
Date only |
|
Example 2 — Create from Other Types
from datetime import datetime
from pydsstools.core import HecTime
# From Python datetime
dt = datetime(2000, 1, 1, 12, 0)
ht = HecTime(dt)
print(ht.text()) # "01Jan2000:12:00:00"
# From another HecTime (clone)
ht2 = HecTime(ht)
# From an integer timestep value
# Requires granularity and julian_base
ht = HecTime(100, granularity=60, julian_base="01JAN2000")
# Undefined time
ht = HecTime(None)
print(ht.is_undefined()) # True
Example 3 — Access Date and Time Components
from pydsstools.core import HecTime
ht = HecTime("15Jul2019 14:30:45")
# Individual components
print(ht.year()) # 2019
print(ht.month()) # 7
print(ht.day()) # 15
print(ht.hour()) # 14
print(ht.minute()) # 30
print(ht.second()) # 45
# Internal representation
print(ht.julian()) # Julian day number
print(ht.seconds_since_midnight()) # 52245 (14*3600 + 30*60 + 45)
print(ht.granularity()) # 60 (default)
Example 4 — Format Output
from pydsstools.core import HecTime
ht = HecTime("02Jun1985 08:30:00")
# Default DSS format
print(ht.text()) # "02Jun1985:08:30:00"
# Custom strftime format
print(ht.text(format="%Y-%m-%d %H:%M")) # "1985-06-02 08:30"
print(ht.text(format="%B %d, %Y at %I:%M %p")) # "June 02, 1985 at 08:30 AM"
# Date with style codes
print(ht.date()) # "02Jun1985" (default style 2 -> "2 June 1985" variant)
print(ht.date(date_style=0)) # "June 2, 1985"
print(ht.date(date_style=4)) # "02Jun1985"
print(ht.date(date_style=-13)) # "1985-06-02"
# Time with style codes
print(ht.time()) # "08:30:00" (style 2)
print(ht.time(time_style=0)) # "0830"
print(ht.time(time_style=1)) # "08:30"
print(ht.time(time_style=2)) # "08:30:00"
# Convert to Python datetime
dt = ht.datetime() # datetime.datetime(1985, 6, 2, 8, 30)
Date style codes (common):
Code |
Example |
|---|---|
0 |
|
1 |
|
2 |
|
4 |
|
7 |
|
104 |
|
-13 |
|
-111 |
|
Use HecTime._date_style_codes() to see all available codes.
Time style codes:
Code |
Example |
|---|---|
0 |
|
1 |
|
2 |
|
Example 5 — Time Arithmetic
HecTime supports adding and subtracting time intervals. All arithmetic
methods modify the object in place.
from pydsstools.core import HecTime
ht = HecTime("01Jan2000 12:00:00")
# Add time units
ht.add_seconds(90) # +1min 30sec
print(ht.time()) # "12:01:30"
ht.add_minutes(45) # +45min
print(ht.time()) # "12:46:30"
ht.add_hours(6) # +6 hours
print(ht.time()) # "18:46:30"
ht.add_days(10) # +10 days
print(ht.date()) # "11Jan2000"
# Subtract (use negative values)
ht.add_days(-5)
print(ht.date()) # "06Jan2000"
# General interval: add_time(interval_seconds, periods)
ht.add_time(3600, 3) # Add 3 hours
ht.add_time(86400, -2) # Subtract 2 days
Arithmetic methods:
Method |
Description |
|---|---|
|
Add |
|
Add |
|
Add |
|
Add |
|
Add |
|
Add a |
Example 6 — Add Months and Years with relativedelta
For calendar-aware arithmetic (adding months or years), use
dateutil.relativedelta:
from dateutil.relativedelta import relativedelta
from pydsstools.core import HecTime
ht = HecTime("01Jan2000 12:00:00")
# Add 2 months and 5 days
ht.add_delta(relativedelta(months=2, days=5))
print(ht.date()) # "06Mar2000"
# Add 1 year
ht.add_delta(relativedelta(years=1))
print(ht.date()) # "06Mar2001"
add_delta() converts to a Python datetime, applies the delta, then
converts back to HecTime. This correctly handles month length variations
and leap years.
Example 7 — Clone to Preserve Originals
Since arithmetic methods modify the object in place, use clone() to
create a copy before modifying.
from pydsstools.core import HecTime
ht1 = HecTime("01Jan2000 12:00:00")
ht2 = ht1.clone()
ht2.add_hours(6)
print(ht1.time()) # "12:00:00" — original unchanged
print(ht2.time()) # "18:00:00" — clone modified
Example 8 — Midnight Representation
DSS uses two conventions for midnight:
00:00 of the current day (
midnight_as_2400=False, default)24:00 of the previous day (
midnight_as_2400=True)
This matters for period-ending timestamps (e.g., a daily total ending at midnight).
from pydsstools.core import HecTime
# Default: midnight = 00:00 of Jan 1
ht = HecTime("01JAN2000 00:00", midnight_as_2400=False)
print(ht.date(), ht.time()) # "01Jan2000" "00:00:00"
# Alternative: midnight = 24:00 of Dec 31
ht = HecTime("01JAN2000 00:00", midnight_as_2400=True)
print(ht.date(), ht.time()) # "31Dec1999" "24:00:00"
# Toggle representation
ht.set_midnight_as_2400(False)
print(ht.date(), ht.time()) # "01Jan2000" "00:00:00"
The internal absolute time is the same in both cases — only the display
changes. When midnight_as_2400=True, midnight causes the julian day to
decrease by 1 and seconds to become 86400.
Example 9 — Timestep Values and Granularity
The value() method converts a HecTime to a single integer “timestep
value” used internally by the DSS library.
from pydsstools.core import HecTime
ht = HecTime("02JAN2019 00:00", granularity=60)
print("Minute value:", ht.value()) # Large integer (minutes since epoch)
ht = HecTime("02JAN2019 00:00:10", granularity=1)
print("Second value:", ht.value()) # Even larger (seconds since epoch)
# WARNING: second granularity can overflow for dates far from epoch!
# Safe second granularity with julian_base
ht = HecTime("02JAN2019 00:10", granularity=1, julian_base="01JAN2000")
print("Value with base:", ht.value()) # Smaller, safe value
Granularity settings:
Value |
Unit |
Precision |
Max Range |
|---|---|---|---|
86400 |
Day |
1 day |
Unlimited |
3600 |
Hour |
1 hour |
Unlimited |
60 |
Minute |
1 minute |
~4,000 years |
1 |
Second |
1 second |
~68 years from base |
Use minute granularity (60) unless you specifically need sub-minute
precision. When using second granularity, set a julian_base close to
your data dates to prevent integer overflow.
Example 10 — Parse Date/Time Strings with split_datetime
The static method split_datetime() breaks a datetime string into its
date and time components without creating a full HecTime object.
from pydsstools.core import HecTime
# ISO format
print(HecTime.split_datetime("2000-01-15T10:30:00"))
# ('2000-01-15', '10:30:00')
# Grid style (single colon)
print(HecTime.split_datetime("01JAN2000:1030"))
# ('01JAN2000', '1030')
# Space + colon time
print(HecTime.split_datetime("Jan 1, 2000 10:30 AM"))
# ('Jan 1, 2000', '10:30 AM')
# Date only
print(HecTime.split_datetime("01JAN2000"))
# ('01JAN2000', '')
# Undefined
print(HecTime.split_datetime("undefined"))
# ('', '')
The parser tries multiple strategies in order:
Check for
Noneor"undefined"Try
dateutil.parserfor date-only detectionTry regex patterns: ISO, Grid, Colon time, Plain time
Fall back to
dateutilfor complex formatsRaise
ValueErrorif all strategies fail
Example 11 — Undefined Times
HecTime(None) creates an undefined time. Undefined times are safe to
use — all methods return sentinel values without raising exceptions.
from pydsstools.core import HecTime
ht = HecTime(None)
print(ht.is_undefined()) # True
print(ht.date()) # "UNDEFINED"
print(ht.time()) # "UNDEFINED"
print(ht.text()) # None
print(ht.datetime()) # None
print(ht.year()) # None
print(ht.value()) # UNDEFINED_TIME constant
# Arithmetic on undefined time is a no-op
ht.add_hours(6)
print(ht.is_undefined()) # Still True
Example 12 — Using HecTime with Time Series
HecTime is used throughout the time-series API for timestamps and time windows.
from pydsstools.core import HecTime
from pydsstools.heclib.dss import HecDss
dss_file = "sample.dss"
pathname = "/REGULAR/TIMESERIES/FLOW//1HOUR//"
with HecDss.Open(dss_file) as fid:
# Window dates are parsed by HecTime internally
ts = fid.read_ts(pathname, window=("15JUL2019 2300", "16JUL2019 0100"))
# Start and end times are HecTime objects
print("Start:", ts.start_time.text())
print("End:", ts.end_time.text())
# Iterator yields HecTime objects
for ht in ts.times:
print(f" {ht.date()} {ht.time()} -> {ht.datetime()}")
API Summary
Construction
Input |
Example |
|---|---|
String |
|
datetime |
|
HecTime (clone) |
|
Integer timestep |
|
Undefined |
|
Optional Parameters
Parameter |
Type |
Default |
Description |
|---|---|---|---|
|
int |
60 |
Time precision in seconds (1, 60, 3600, 86400) |
|
bool |
False |
Midnight as 24:00 of previous day |
|
int |
2 |
Date formatting style code |
|
int |
2 |
Time formatting style code |
|
int or str |
0 |
Base julian day (only for int input) |
Properties and Methods
Method |
Returns |
Description |
|---|---|---|
|
int |
Julian day (days since Dec 31, 1899) |
|
int |
Seconds since midnight (0-86400) |
|
int |
Time precision in seconds |
|
int |
Encoded timestep value |
|
str |
Formatted date string |
|
str |
Formatted time string |
|
str |
Combined datetime string |
|
datetime |
Python datetime object |
|
int |
Year component |
|
int |
Month component (1-12) |
|
int |
Day component (1-31) |
|
int |
Hour component (0-24) |
|
int |
Minute component (0-59) |
|
int |
Second component (0-59) |
|
bool |
True if time is undefined |
|
bool |
Current midnight mode |
|
HecTime |
Create a copy |
Arithmetic Methods
Method |
Description |
|---|---|
|
Add |
|
Add |
|
Add |
|
Add |
|
Add |
|
Add months/years via |
|
Toggle midnight representation |
|
Fix overflow/underflow in seconds |
Static Methods
Method |
Description |
|---|---|
|
Parse string into |
|
Get all date formatting codes |
|
Get all time formatting codes |