Skip to content

Instantly share code, notes, and snippets.

@fralalonde
Last active August 28, 2018 20:43
Show Gist options
  • Save fralalonde/5f5183ad086a9c4f4bab5b7b1d1b8215 to your computer and use it in GitHub Desktop.
Save fralalonde/5f5183ad086a9c4f4bab5b7b1d1b8215 to your computer and use it in GitHub Desktop.
Playa Time Expressions

Playa

A friendly language to express and evaluate real-world schedules.

Allows building complex scheduling rulesets:

  • to trigger the timely execution of tasks
  • to calculate intervals of time to be processed by batch jobs
  • to manage the impacts of potential scheduling rule changes on dependent tasks & jobs.

...Because neither cron or airflow address this problem.

Concepts

Instant

A playa instant is a specific point in time. Instants are precise to the second. Instant litterals start with @. Their regular format follows the ISO 8601 syntax. For brevity, smaller units can be omitted and will be assumed to be 0 (or 1 for date & month).

# Fully specified instant
@2018-05-22T12:34:55

# Midnight, 22nd of May 2018
@2018-05-22

TODO Instants alt-specified as the number of seconds since the epoch?

Duration

A playa duration is the time interval between two instants. An instant's duration is zero. A closed period's duration is the difference between its bounds. An open period's duration is infinite.

days(3)
months(6)  

Period

A playa period represents a range of time. A period is delimited by one or two instants, called bounds.

A period with two bounds is closed. A closed period can be expressed using the [ partial ] syntax, following ISO8601 format but omitting smaller fields.

# The whole 9th hour of the 22nd day of May 2018
[ 2018-05-22T09 ]

A closed period can also be expressed using the [ bound .. bound ] syntax.

# From June 2018 (inclusively) until June 2020 (exclusively)
[ @2018-06 .. @2020-06 ]

A period with a single bound is open.

# Any time after July 1st 1978
[ @1978-07-01 .. ]

# Any time before July 1st 1978
[ .. @1978-07-01 ]    

Period Set

A playa period set defines a sequence of periods. A period set can define zero periods (be empty), multiple periods or an infinite number of periods. Like periods, infinite sets are said to be open by opposition to empty or finite sets which are closed.

Infinite period set litterals are delimited by { and } and follow ISO8601 format with some date or time fields replaced by * (fifty shades of cron).

# every christmas day
{ *-12-25 }
# every day from 6AM to 7AM
{ 6:*:* }
# the sixteenth minute after 3PM on the 22nd each month
{ *-*-22T15:16:* }

Period litterals can be used to define single-period sets.

# A single period set
[ 2018-12-23 ]

Period sets can be combined to form more complex sets using operators.

# A closed set of two day-long periods
[ 2018-12-23 ], [ 2018-12-25 ]

# First hour past midnight every day of the month of May 2018
[ 2018-06 ] & { 00:*:* }

Syntax

Named sets

Sets can be named by prefixing their definition with an alphanumeric string and a semicolon:

christmas: { *-12-25 } 

Sets can be built by referring to other sets by name.

Playa defines a few named sets by default: months (january to december), days (monday to sunday), noon and midnight.

TODO namespaces? overrides?

Expressions

Playa period sets are combined with operators. Operators transform the sequence or the periods returned by sets, thereby defining a new set.

Operators acting on a single set are said to be unary. Operators combining two sets are said to be binary. Unary operators have precedence over binary operators. Operations can be grouped using parenthesis (, ) to force precedence.

Unary operators

from (|>)

from returns a forward, inclusive, open period.

# From July 1st 1978
|> @1978-07-01
from @1978-07-01

If applied to a closed range, the range's start instant is used.

# From July 1st 1978
|> [ 1978-07-01 ]
from [ 1978-07-01 ]

after (|>>)

after returns a forward, exclusive, open period.

# From Midnight, July 2nd 1978
|>> [ 1978-07-01 ]
after [ 1978-07-01 ]

Applied to an instant, it has the same result as from.

until (>|)

until returns a backward, exclusive, open period

# Until July 8th 2003
>| @2003-07-08
>| [ 1978-07-01 ]
until [ 1978-07-01 ]

By design, there is no inclusive backward open period operator.

not (!)

not turns a closed period into two open periods:

  • an open period until the period's start
  • an open period from the period's start

Binary operators

Overlap

Periods can overlap.

( A, B, C )
1 2 3 4 5 6 7 8 9 0    1 2 3 4 5 6 7 8 9 0
A A A A                A A A A                
    B B B B                B B B B        
        C C C C                C C C C

Juxtapose

Periods sorted and truncated to not overlap. Can be applied forward or backward.

( A ~ B ~ C )
1 2 3 4 5 6 7 8 9 0    1 2 3 4 5 6 7 8 9 0
A A A A                A A A A                
    B B B B                    B B        
        C C C C                    C C

Lazy union

Overlapping periods (A.stop > B.start) are merged into one.

( A | B )
1 2 3 4 5 6 7 8 9 0    1 2 3 4 5 6 7 8 9 0
A A A A                D D D D D D C C
    B B B B            
            C C        

Greedy union

Consecutive or overlapping periods (A.stop >= B.start) are merged into one.

( A |+ B )
1 2 3 4 5 6 7 8 9 0    1 2 3 4 5 6 7 8 9 0
A A A A                D D D D D D D D
    B B B B                  
            C C        

Intersect ( A & B )

Overlapping periods combine to form multiple ranges only where they all apply.

1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
A A A A                D D
    B B B B                  

Skip ( A skip n )

Skip every nth period.

( A skip 2)
1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
A A A A A A          A   A   A

TODO offset? syntax / verb / operator?

Shift forward ( A >> B )

Period A shifts towards future by duration B

( A >> 2)
1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
A A                    A A

Shift backward ( A << B )

Period A shifts towards past by duration B

( A << 2)
1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
    A A            A A

Substract ( A - B )

Substracts duration B from period A, starting from period's end.

( A - 1 )
1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
A A A              A A

Substracting from start requires shitfing forward by the same amount that is substracted.

( A - 1 >> 1 )
1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
A A A                A A

TODO Instant: returns the duration from instant A to instant B

Append ( A + B )

Append duration B to period A.

( A + 2 )
1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
A A                A A A A

Prepending is achieved by appending and shifting back by the same amount.

( A + 2 << 2 )
1 2 3 4 5 6 7 8    1 2 3 4 5 6 7 8 9 0
    A A            A A A A

Divide ( A / B )

Returns the number of duration Bs that can fit in period A's. TODO really?

Evaluation

Context

Sets declared without a name are pushed to the set stack.

TODO vars

Origin

Sets are queried by iterating from an instant named origin.

The origin can be set by the user.

The default origin is the current time.

set $origin @2015-06-25

Now

Iteration state is maintained as an instant named now. The value of now is altered by iterators.

When sub-iteration is performed, now is copied to the iterator stack.

When the origin is set, it also resets to the now.

get $now

Period

The last period returned by the iterator. If no iterator was called, this is empty.

seq

Describes the set on top of the stack.

Iterators

next

Iterate forward.

from @2018-08-04
& @09:00 & (monday, tuesday)
print next
>>> 2018-08-06T09:00:00

Prev

Iterate backward.

until @2018-08-04
@09:00 & (monday, tuesday)
print prev
>>> 2018-07-31T09:00:00

Syntax

  • Identation is ignored
  • Lines begining with # are ignored (comments)
  • Statements delimited by ; or newline if no () are opened.

TODO Functions

fn = name(params)

every(n, r): $r % $n
every(3, monday)

TODO Scoping

blob: (
  blab(z): z + 4
  
)

examples

statutory_holidays: (
    christmas
    easter
)

vacations_length: weeks(2)

vacations: [ 2018-07%2w ] + vacations_length

weekend: sat | sun

business_hours: (
    (mon | tue | wed) & [ @09-@18 ]
    (thu | fri) & [ @09-@21 ]
    weekend & [ @10-@17 ]
    !vacations
    !statutory_holidays
)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment