Coerce raw URPX parser output into typed Clojure values.
The parser (urpx.core/load-rate-plan) produces a Clojure map with
namespaced keys but all-string leaf values. This namespace applies the
:decode/urpx-jsonld decoders attached to urpx.schema schemas to convert
those strings into BigDecimals, LocalDates, LocalTimes, LocalDateTimes,
Durations, and integer month numbers — and to normalize fields that URPX
permits as either a single map or a vector of maps.
Coerce raw URPX parser output into typed Clojure values. The parser (`urpx.core/load-rate-plan`) produces a Clojure map with namespaced keys but all-string leaf values. This namespace applies the `:decode/urpx-jsonld` decoders attached to `urpx.schema` schemas to convert those strings into BigDecimals, LocalDates, LocalTimes, LocalDateTimes, Durations, and integer month numbers — and to normalize fields that URPX permits as either a single map or a vector of maps.
URPX rate plan loading and price resolution.
Parses URPX JSON-LD rate plan documents into Clojure data structures and resolves prices for any given timestamp and timezone.
URPX rate plan loading and price resolution. Parses URPX JSON-LD rate plan documents into Clojure data structures and resolves prices for any given timestamp and timezone.
Derive a holiday-date predicate from a rate plan's embedded urpx:HolidayCalendar.
URPX rate plans may embed a HolidayCalendar at :urpx/hasRatePlanVersion → :urpx/hasPlanElements → :urpx/hasHolidayCalendar listing each Holiday with a urpx:holidayName plus either:
derive-predicate returns a (java.time.LocalDate -> bool) predicate, or
nil when the plan has no embedded calendar. The predicate covers any year
on demand; per-year date sets are computed once and cached internally so
driving price-schedule across thousands of timestamps doesn't repeat work.
Recognized urpx:holidayRule patterns:
When a Holiday carries an explicit urpx:observanceRule (Ref to one of urpx:actualDateObservance / urpx:nearestWeekdayObservance / urpx:mondayIfWeekendObservance / urpx:fridayIfWeekendObservance) it overrides the implicit observance derived from the rule string.
Unrecognized rules throw ex-info — pass an explicit :holiday? predicate
in urpx.price/resolve-prices opts to override the derived calendar.
Derive a holiday-date predicate from a rate plan's embedded
urpx:HolidayCalendar.
URPX rate plans may embed a HolidayCalendar at
:urpx/hasRatePlanVersion → :urpx/hasPlanElements → :urpx/hasHolidayCalendar
listing each Holiday with a urpx:holidayName plus either:
- urpx:holidayDate — literal xsd:date for one specific instance, OR
- urpx:holidayRule — free-form string like 'Third Monday in February'
or 'January 1 (legally observed)'.
`derive-predicate` returns a `(java.time.LocalDate -> bool)` predicate, or
nil when the plan has no embedded calendar. The predicate covers any year
on demand; per-year date sets are computed once and cached internally so
driving `price-schedule` across thousands of timestamps doesn't repeat work.
Recognized urpx:holidayRule patterns:
- 'First|Second|Third|Fourth|Fifth <Weekday> in <Month>'
- 'Last <Weekday> in <Month>'
- '<Month> <Day>' — observed on the actual date
- '<Month> <Day> (legally observed)' — observed on the nearest weekday
when the actual date falls on
a weekend (Sat → Fri, Sun → Mon)
When a Holiday carries an explicit urpx:observanceRule (Ref to one of
urpx:actualDateObservance / urpx:nearestWeekdayObservance /
urpx:mondayIfWeekendObservance / urpx:fridayIfWeekendObservance) it
overrides the implicit observance derived from the rule string.
Unrecognized rules throw ex-info — pass an explicit `:holiday?` predicate
in `urpx.price/resolve-prices` opts to override the derived calendar.Build and query an entity index for URPX documents.
URPX JSON-LD documents are graphs: most entities carry a :jsonld/id and refer
to other entities by reference shape {:jsonld/id "urpx:foo"}. Coercion
leaves these references intact; consumers dereference them on demand against
an index keyed by id string.
Note: many references point to vocabulary IRIs in the URPX ontology (e.g. urpx:peakTier, urpx:allDays, urpx:bundledLedger) rather than entities defined in the document. Those lookups return nil — callers distinguish internal refs (resolve to a node) from vocabulary terms (do not).
Build and query an entity index for URPX documents.
URPX JSON-LD documents are graphs: most entities carry a :jsonld/id and refer
to other entities by reference shape `{:jsonld/id "urpx:foo"}`. Coercion
leaves these references intact; consumers dereference them on demand against
an index keyed by id string.
Note: many references point to vocabulary IRIs in the URPX ontology
(e.g. urpx:peakTier, urpx:allDays, urpx:bundledLedger) rather than entities
defined in the document. Those lookups return nil — callers distinguish
internal refs (resolve to a node) from vocabulary terms (do not).Resolve applicable per-energy prices for a URPX rate plan at a given instant.
Given a coerced rate plan (urpx.coerce/coerce-rate-plan) and a
ZonedDateTime, resolve-prices returns the season, the matched TOU period
(if any), and one entry per active per-energy ledger (commodity, distribution,
public benefits, etc.). Each ledger entry carries a :tiers vector — for
block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is
surfaced so the caller can pick the active one based on cumulative usage;
for non-tiered ledgers the vector has a single entry.
Skipped:
:urpx/hasCalculationMethod is set
(recurring fixed charges like a monthly customer charge — these are
subscription-style and don't apply to instantaneous lookup).Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays, urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays booleans (both default to true when omitted). Holiday detection sources, in priority order:
:holiday? predicate in opts (highest precedence — overrides).urpx.holidays/derive-predicate.Plans without a HolidayCalendar and called without :holiday? retain the
pre-existing 'every date is a non-holiday' fallback — so brackets that
opt out of non-holidays (urpx:includeNonHolidays = false) will never match.
Resolve applicable per-energy prices for a URPX rate plan at a given instant.
Given a coerced rate plan (`urpx.coerce/coerce-rate-plan`) and a
ZonedDateTime, `resolve-prices` returns the season, the matched TOU period
(if any), and one entry per active per-energy ledger (commodity, distribution,
public benefits, etc.). Each ledger entry carries a `:tiers` vector — for
block-tiered ledgers (CPAU E-1) every tier's bound and unit-price is
surfaced so the caller can pick the active one based on cumulative usage;
for non-tiered ledgers the vector has a single entry.
Skipped:
- PriceDefinitions whose own `:urpx/hasCalculationMethod` is set
(recurring fixed charges like a monthly customer charge — these are
subscription-style and don't apply to instantaneous lookup).
Day types honored (URPX ontology): urpx:allDays, urpx:weekdayDays,
urpx:weekendDays, urpx:customDays. Holiday inclusion is expressed by the
TimeBracket's optional urpx:includeHolidays / urpx:includeNonHolidays
booleans (both default to true when omitted). Holiday detection sources,
in priority order:
1. Explicit `:holiday?` predicate in opts (highest precedence — overrides).
2. The plan's embedded urpx:HolidayCalendar, derived via
`urpx.holidays/derive-predicate`.
3. Fallback: every date treated as a non-holiday.
Plans without a HolidayCalendar and called without `:holiday?` retain the
pre-existing 'every date is a non-holiday' fallback — so brackets that
opt out of non-holidays (urpx:includeNonHolidays = false) will never match.Generate contiguous price-interval schedules from a coerced URPX rate plan.
price-schedule walks a [start, end) instant window in the rate plan's
local timezone, calls urpx.price/resolve-prices at each step, and
merges adjacent steps whose ledger resolutions are identical.
Output is a vector of interval maps each carrying :tick/beginning and
:tick/end (java.time.Instants) plus the full urpx.price resolved
structure under :urpx.interval/resolved. Suitable for feeding to a
consumer like the price-server's TariffFetcher, which can extract a
single $/kWh value per interval via urpx.price/marginal-unit-rate.
Default step is 1 hour, anchored to the start-of-hour of start. Pass
{:step (Duration/ofMinutes 15)} etc. for finer granularity when a rate
plan defines sub-hour TOU bracket transitions.
Generate contiguous price-interval schedules from a coerced URPX rate plan.
`price-schedule` walks a [start, end) instant window in the rate plan's
local timezone, calls `urpx.price/resolve-prices` at each step, and
merges adjacent steps whose ledger resolutions are identical.
Output is a vector of interval maps each carrying `:tick/beginning` and
`:tick/end` (java.time.Instants) plus the full `urpx.price` resolved
structure under `:urpx.interval/resolved`. Suitable for feeding to a
consumer like the price-server's TariffFetcher, which can extract a
single $/kWh value per interval via `urpx.price/marginal-unit-rate`.
Default step is 1 hour, anchored to the start-of-hour of `start`. Pass
`{:step (Duration/ofMinutes 15)}` etc. for finer granularity when a rate
plan defines sub-hour TOU bracket transitions.Malli schemas for URPX entities, describing the coerced shape.
Two-layer model (mirroring the clj-oa3 pattern):
Schemas carry :decode/urpx-jsonld decoders that turn the raw parser output
(strings) into the typed shape described here. The transformer is built and
applied in urpx.coerce. Reference resolution (URPX-ej9) keeps :jsonld/id
references intact; consumers dereference via an entity index.
Schemas are bare def vars referenced by symbol — there is no central registry.
Malli schemas for URPX entities, describing the coerced shape.
Two-layer model (mirroring the clj-oa3 pattern):
- urpx.core — raw parse: JSON-LD with namespaced keys, all string values.
- urpx.schema — coerced shape: typed Clojure values (BigDecimal, LocalDate,
LocalTime, LocalDateTime, Duration, integer month numbers).
Schemas carry `:decode/urpx-jsonld` decoders that turn the raw parser output
(strings) into the typed shape described here. The transformer is built and
applied in `urpx.coerce`. Reference resolution (URPX-ej9) keeps :jsonld/id
references intact; consumers dereference via an entity index.
Schemas are bare def vars referenced by symbol — there is no central registry.Best-effort timezone inference for URPX rate plans whose
urpx:timezoneIdentifier is absent.
This namespace is opt-in — urpx.schedule does not call it
automatically. Callers that want plug-and-play timezone resolution
compose inference with the declared field at the call site:
(or (some-> plan :urpx/timezoneIdentifier ZoneId/of)
(:zone (urpx.tz-inference/infer-zone plan)))
Inference uses utility-identifying fields on the publishing
Organization: urpx:eiaId (preferred — official US energy reporting
code) and urpx:legalName (fallback). When the utility is unknown to
the lookup tables, or known to operate across more than one IANA
zone, infer-zone returns nil so the caller can fail loudly rather
than silently pick one.
The shipped tables only cover utilities used by the clj-urpx test suite; production deployments are expected to supply their own table (e.g. derived from EIA Form 861).
Best-effort timezone inference for URPX rate plans whose
`urpx:timezoneIdentifier` is absent.
This namespace is **opt-in** — `urpx.schedule` does not call it
automatically. Callers that want plug-and-play timezone resolution
compose inference with the declared field at the call site:
(or (some-> plan :urpx/timezoneIdentifier ZoneId/of)
(:zone (urpx.tz-inference/infer-zone plan)))
Inference uses utility-identifying fields on the publishing
Organization: `urpx:eiaId` (preferred — official US energy reporting
code) and `urpx:legalName` (fallback). When the utility is unknown to
the lookup tables, or known to operate across more than one IANA
zone, `infer-zone` returns `nil` so the caller can fail loudly rather
than silently pick one.
The shipped tables only cover utilities used by the clj-urpx test
suite; production deployments are expected to supply their own table
(e.g. derived from EIA Form 861).cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |