Skip to content

Commit

Permalink
doc: Adds date and time information to Plugin RFD
Browse files Browse the repository at this point in the history
  • Loading branch information
Michael Chernicoff committed Sep 25, 2024
1 parent a3f9994 commit e16cf5a
Show file tree
Hide file tree
Showing 4 changed files with 78 additions and 12 deletions.
2 changes: 1 addition & 1 deletion hipcheck/src/policy_exprs/env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ fn divz(env: &Env, args: &[Expr]) -> Result<Expr> {
binary_primitive_op(name, env, args, op)
}

// Finds the difference in time between two datetimes, in units of hours (chosen for comparision safety)
// Finds the difference in time between two datetimes, in units no larger than hours (chosen for comparision safety)
fn duration(env: &Env, args: &[Expr]) -> Result<Expr> {
let name = "duration";

Expand Down
8 changes: 4 additions & 4 deletions hipcheck/src/policy_exprs/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,10 @@ pub enum Primitive {

/// Span of time using the [jiff] crate, which uses a modified version of ISO8601.
///
/// Can include weeks, days, hours, minutes, and seconds (including decimal fractions of a second).
/// Can include weeks, days, hours, minutes, and seconds. The smallest provided unit of time (but not weeks or days) can have a decimal fraction.
/// While spans with months, years, or both are valid under IS08601 and supported by [jiff] in general, we do not allow them in Hipcheck policy expressions.
/// This is because spans greater than a day require additional zoned datetime information in [jiff] (to determine e.g. how many days are in a year or month)
/// before we can do time arithematic with them.
/// before we can do time arithmetic with them.
/// We *do* allows spans with weeks, even though [jiff] has similar issues with those units.
/// We take care of this by converting a week to a period of seven 24-hour days that [jiff] can handle in arithematic without zoned datetime information.
///
Expand Down Expand Up @@ -327,10 +327,10 @@ mod tests {

#[test]
fn parse_span() {
let input = "P2W4DT1H30M";
let input = "P2W4DT1H30.5M";
let result = parse(input).unwrap();

let raw_span: Span = "P18DT1H30M".parse().unwrap();
let raw_span: Span = "P18DT1H30.5M".parse().unwrap();
let expected = span(raw_span).into_expr();

assert_eq!(result, expected);
Expand Down
2 changes: 1 addition & 1 deletion hipcheck/src/policy_exprs/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub enum Token {

// In the future this regex *could* be made more specific to reduce collision
// with Ident, or we could introduce a special prefix character like '@' or '#'
#[regex(r"PT?[0-9]+[a-zA-Z][^\s\)]*", lex_span)]
#[regex(r"PT?[0-9.]+[a-zA-Z][^\s\)]*", lex_span)]
Span(Box<Span>),

// Prioritize over span regex, which starts with a 'P'
Expand Down
78 changes: 72 additions & 6 deletions site/content/rfds/0004-plugin-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -607,11 +607,15 @@ The policy expression language is limited. It does not permit user-defined
functions, assignment to variables, or the retention of any state. Any
policy expression which does _not_ result in a boolean output will produce
an error. The primitive types accepted in policy expressions are only
integers, floating point numbers, and booleans.
integers, floating point numbers, booleans, date-times, and spans of time.

- `Integer`: 64-bit signed integers.
- `Float`: 64-bit IEEE double-precision floating point numbers.
- `Boolean`: True (`#t`) or false (`#f`).
- `DateTime`: A date-time value with a date, optional time, and optional UTC
offset. This follows a modified version of ISO8601 (see below for details).
- `Span`: A span of time, in some combination of weeks, days, hours, minutes,
seconds. This follows a modified version of ISO8601 (see below for details).

Policy expressions also accept arrays, which are ordered sequences of
values of the same type from the list of primitive types above. Arrays may
Expand Down Expand Up @@ -644,12 +648,17 @@ The following functions are currently defined for policy expressions:
- __`neq`__: Not-equal comparison. Example: `(neq 1 1)` is `#f`. This
function can be partially-evaluated when passed to a higher-order array function.
- Mathematical Functions
- __`add`__: Adds two integers or floats together. This function can be
partially-evaluated when passed to a higher-order array function.
- __`sub`__: Subtracts one integer or float from another. This function
can be partially-evaluated when passed to `foreach`, in which case the
order of the parameters is switched to match the expected result. So
- __`add`__: Adds two integers, floats, or spans together. Adds a date-time and a
span to get new date-time. This function can be partially-evaluated when passed to
a higher-order array function.
- __`sub`__: Subtracts one integer, float, or span from another. Subtracts a
span from a date-time to get a new date-time. This function can be
partially-evaluated when passed to `foreach`, in which case the order of
the parameters is switched to match the expected result. So
`(foreach (sub 1) [1 2 3 4 5])` becomes `[0 1 2 3 4]`.
- Date-time Specific Function
- __`duration`__: Returns the span representing the difference between two
date-times.
- Logical Functions
- __`and`__: Performs the logical "and" of two booleans. Example:
`(and #t #f)` becomes `#f`.
Expand Down Expand Up @@ -702,6 +711,63 @@ array. So `$/items/0`, for example, would select into the `items` field
of the provided object, and then into the first (`0`-th) element of that
array.

#### Date-time format details
The policy expression Date-time primitive uses a modified version of ISO8601.
A given date-time must include a date in the format `<YYYY>-<MM>-<DD>`.

An optional time in the format `T<HH>:[MM]:[SS]` can be provided after the date.
**Decimal fractions of hours and minutes are not allowed**; use smaller time units
instead (e.g. T10:30 instead of T10.5). Decimal fractions of seconds are allowed.

The timezone is always set to UTC, but you can set an offeset from UTC by
including `+{HH}:[MM]` or `-{HH}:[MM]` after the time. All datetimes are
treated as offsets ofUTC and do not include other timezone information (e.g.
daylight savings time adjustments).

Example of valid datetimes are:
- `2024-09-25`
- `2024-09-25T08`
- `2024-09-25T08:28:35`
- `2024-09-25T08:30-05`
- `2024-09-25T08:28:35-03:30`

All comparison functions work on date-times, with earlier date-times
considered to be "lesser than" later ones. A span can be added to or
subtraced from a date-time to get a new date-time. The __`duration`__
function is used to find the difference in time between two date-times,
returned as a span.

#### Span format details
The policy expression Span primitive uses a modified version of ISO8601. It can
include weeks, days, hours, minutes, and seconds. The smallest provided unit of
time (i.e. hours, minutes, or seconds) can have a decimal fraction.

While spans with months, years, or both are valid under IS08601, we do not allow
them in Hipcheck policy expressions. This is because spans greater than a day
require additional zoned datetime information (to determine e.g. how many days
are in a year or month) before we can do time arithmetic with them.
Spans with weeks, days, or both **are** allowed. Hipcheck handles this by treating
all days as periods of exactly 24 hours (without worrying about leap seconds)
and converting a week to a period of seven 24-hour days.

Spans are preceded by the letter "P" with any optional time units separated from
optional date units by the letter "T" (not whitespace, as is also allowed under
ISO8601). All units of dates and times are represented by single case-agnostic
letter abbreviations after the number.

Examples of valid spans are:
- `P4w`
- `P3d`
- `P1W2D`
- `PT4h15.25m`
- `PT5s`
- `P1w2dT3h4m5.6s`

All comparison functions work on spans. This is handled the "smart way," with
spans that have different representations but equalling the same amount of time
considred to be equal. e.g. `(eq PT1h PT60m)` will return `#t`. Spans can be added
to or subtracted from each other to return a new span.

#### Limitations of JSON Pointer syntax relative to RFC

The [JSON Pointer spec (RFC 6901)](https://datatracker.ietf.org/doc/html/rfc6901)
Expand Down

0 comments on commit e16cf5a

Please sign in to comment.