FeelEx 



Introduction
A friendly expression language helps users define decision logic without needing deep technical expertise. This language is based on the FEEL(Friendly Enough Expression Language). For more information regarding FEEL, please take a look at the official OMG specification at https://www.omg.org/dmn/.
Installation
Add feel_ex to the list of dependencies in mix.exs:
def deps do
[
{:feel_ex, "~> 0.2.0"}
]
endData types
Null
A null value is represented simply by null.
iex(1)> FeelEx.evaluate("null")
%FeelEx.Value{value: nil, type: :null}Number
Allows for integers and decimal numbers. The numbers can be negative, and leading zero may be omitted.
iex(1)> FeelEx.evaluate("1")
%FeelEx.Value{value: 1, type: :number}
iex(2)> %FeelEx.Value{value: 2.4, type: :number}
FeelEx.evaluate("2.4")
iex(3)> FeelEx.evaluate(".4")
%FeelEx.Value{value: 0.4, type: :number}
iex(4)> FeelEx.evaluate("-5")
%FeelEx.Value{value: -5, type: :number}Strings
Strings are wrapped around in ".
iex(1)> FeelEx.evaluate("\"Aw dinja\"")
%FeelEx.Value{value: "Aw dinja", type: :string}Boolean
Either true or false.
iex(1)> FeelEx.evaluate("true")
%FeelEx.Value{value: true, type: :boolean}
iex(2)> FeelEx.evaluate("false")
%FeelEx.Value{value: false, type: :boolean}Date
Format: yyyy-MM-dd.
iex(1)> FeelEx.evaluate("date(\"2017-03-10\")")
%FeelEx.Value{value: ~D[2017-03-10], type: :date}
iex(2)> FeelEx.evaluate("@\"2017-03-10\"")
%FeelEx.Value{value: ~D[2017-03-10], type: :date}Time
Format: HH:mm:ss / HH:mm:ss+/-HH:mm / HH:mm:ss@ZoneId.
iex(1)> FeelEx.evaluate("time(\"11:45:30\")")
%FeelEx.Value{value: ~T[11:45:30], type: :time}
iex(2)> FeelEx.evaluate("time(\"13:30\")")
%FeelEx.Value{value: ~T[13:30:00], type: :time}
iex(3)> FeelEx.evaluate("time(\"11:45:30+02:00\")")
%FeelEx.Value{value: {~T[11:45:30], "+02:00"}, type: :time}
iex(4)> FeelEx.evaluate("time(\"10:31:10@Europe/Paris\")")
%FeelEx.Value{value: {~T[10:31:10], "+01:00", "Europe/Paris"}, type: :time}
iex(5)> FeelEx.evaluate("@\"11:45:30\"")
%FeelEx.Value{value: ~T[11:45:30], type: :time}
iex(6)> FeelEx.evaluate("@\"13:30\"")
%FeelEx.Value{value: ~T[13:30:00], type: :time}
iex(7)> FeelEx.evaluate("@\"11:45:30+02:00\"")
%FeelEx.Value{value: {~T[11:45:30], "+02:00"}, type: :time}
iex(8)> FeelEx.evaluate("@\"10:31:10@Europe/Paris\"")
%FeelEx.Value{value: {~T[10:31:10], "+01:00", "Europe/Paris"}, type: :time}
iex(9)> FeelEx.evaluate("@\"10:31:10@Europe/Paris\"")
%FeelEx.Value{value: {~T[10:31:10], "+01:00", "Europe/Paris"}, type: :time}Date-time
Format: yyyy-MM-dd'T'HH:mm:ss / yyyy-MM-dd'T'HH:mm:ss+/-HH:mm / yyyy-MM-dd'T'HH:mm:ss@ZoneId.
iex(1)> FeelEx.evaluate("date and time(\"2015-09-18T10:31:10\")")
%FeelEx.Value{value: ~N[2015-09-18 10:31:10], type: :date_time}
iex(2)> FeelEx.evaluate("date and time(\"2015-09-18T10:31:10+01:00\")")
%FeelEx.Value{value: {~N[2015-09-18 10:31:10], "+01:00"}, type: :date_time}
iex(3)> FeelEx.evaluate("date and time(\"2015-09-18T10:31:10@Europe/Paris\")")
%FeelEx.Value{
value: {~N[2015-09-18 10:31:10], "+01:00", "Europe/Paris"},
type: :date_time
}
iex(4)> FeelEx.evaluate("@\"2015-09-18T10:31:10\"")
%FeelEx.Value{value: ~N[2015-09-18 10:31:10], type: :date_time}
iex(5)> FeelEx.evaluate("@\"2015-09-18T10:31:10+01:00\"")
%FeelEx.Value{value: {~N[2015-09-18 10:31:10], "+01:00"}, type: :date_time}
iex(6)> FeelEx.evaluate("@\"2015-09-18T10:31:10@Europe/Paris\"")
%FeelEx.Value{
value: {~N[2015-09-18 10:31:10], "+01:00", "Europe/Paris"},
type: :date_time
}Days-time-duration
Format: PxDTxHxMxS.
iex(1)> FeelEx.evaluate("duration(\"P4D\")")
%FeelEx.Value{value: %Duration{day: 4}, type: :days_time_duration}
iex(2)> FeelEx.evaluate("duration(\"PT2H\")")
%FeelEx.Value{value: %Duration{hour: 2}, type: :days_time_duration}
iex(3)> FeelEx.evaluate("duration(\"PT30M\")")
%FeelEx.Value{value: %Duration{minute: 30}, type: :days_time_duration}
iex(4)> FeelEx.evaluate("duration(\" P1DT6H\")")
%FeelEx.Value{value: %Duration{day: 1, hour: 6}, type: :days_time_duration}
iex(5)> FeelEx.evaluate("@\"P4D\"")
%FeelEx.Value{value: %Duration{day: 4}, type: :days_time_duration}
iex(6)> FeelEx.evaluate("@\"PT2H\"")
%FeelEx.Value{value: %Duration{hour: 2}, type: :days_time_duration}
iex(7)> FeelEx.evaluate("@\"PT30M\"")
%FeelEx.Value{value: %Duration{minute: 30}, type: :days_time_duration}
iex(8)> FeelEx.evaluate("@\"P1DT6H\"")
%FeelEx.Value{value: %Duration{day: 1, hour: 6}, type: :days_time_duration}Years-months-duration
Format: PxYxM.
iex(1)> FeelEx.evaluate("duration(\"P2Y\")")
%FeelEx.Value{value: %Duration{year: 2}, type: :years_months_duration}
iex(2)> FeelEx.evaluate("duration(\"P6M\")")
%FeelEx.Value{value: %Duration{month: 6}, type: :years_months_duration}
iex(3)> FeelEx.evaluate("duration(\"P1Y6M\")")
%FeelEx.Value{value: %Duration{year: 1, month: 6}, type: :years_months_duration}
iex(4)> FeelEx.evaluate("@\"P2Y\"")
%FeelEx.Value{value: %Duration{year: 2}, type: :years_months_duration}
iex(5)> FeelEx.evaluate("@\"P6M\"")
%FeelEx.Value{value: %Duration{month: 6}, type: :years_months_duration}
iex(6)> FeelEx.evaluate("@\"P1Y6M\"")
%FeelEx.Value{value: %Duration{year: 1, month: 6}, type: :years_months_duration}List
A list of elements. Lists may contain lists or may be empty.
iex(1)> FeelEx.evaluate("[]")
[]
iex(2)> FeelEx.evaluate("[1,2,3]")
[
%FeelEx.Value{value: 1, type: :number},
%FeelEx.Value{value: 2, type: :number},
%FeelEx.Value{value: 3, type: :number}
]
iex(3)> FeelEx.evaluate("[\"a\",\"b\"]")
[
%FeelEx.Value{value: "a", type: :string},
%FeelEx.Value{value: "b", type: :string}
]Context
Key-value data structure. It may be empty or nested (value being a context). The key may be a name or a string.
iex(1)> FeelEx.evaluate("{}")
%FeelEx.Value{value: %{}, type: :context}
iex(2)> FeelEx.evaluate("{a:1}")
%FeelEx.Value{
value: %{a: %FeelEx.Value{value: 1, type: :number}},
type: :context
}
iex(3)> FeelEx.evaluate("{b:1, c: \"wow\"}")
%FeelEx.Value{
value: %{
c: %FeelEx.Value{value: "wow", type: :string},
b: %FeelEx.Value{value: 1, type: :number}
},
type: :context
}
iex(4)> FeelEx.evaluate("{nested: {d: 3}}")
%FeelEx.Value{
value: %{
nested: %FeelEx.Value{
value: %{d: %FeelEx.Value{value: 3, type: :number}},
type: :context
}
},
type: :context
}
iex(5)> FeelEx.evaluate("{\"a\": 1}")
%FeelEx.Value{
value: %{a: %FeelEx.Value{value: 1, type: :number}},
type: :context
}
iex(6)> FeelEx.evaluate("{\"b\": 2, \"c\": \"valid\"}")
%FeelEx.Value{
value: %{
c: %FeelEx.Value{value: "valid", type: :string},
b: %FeelEx.Value{value: 2, type: :number}
},
type: :context
}Strings
Creating a new string value.
iex(1)> FeelEx.evaluate("\"Aw dinja\"")
%FeelEx.Value{value: "Aw dinja", type: :string}String concatenation
iex(1)> FeelEx.evaluate("\"Aw\"+\" Dinja\"")
%FeelEx.Value{value: "Aw Dinja", type: :string}string()
Converting datatypes to string
Examples
null
iex(1)> FeelEx.evaluate("string(null)")
%FeelEx.Value{value: "null", type: :string}string (idempotent)
iex(1)> FeelEx.evaluate("string(\"Aw Dinja\")")
%FeelEx.Value{value: "Aw Dinja", type: :string}number
iex(1)> FeelEx.evaluate("string(12)")
%FeelEx.Value{value: "12", type: :string}
iex(2)> FeelEx.evaluate("string(.22)")
%FeelEx.Value{value: "0.22", type: :string}
iex(3)> FeelEx.evaluate("string(-2.22)")
%FeelEx.Value{value: "-2.22", type: :string}
iex(4)> FeelEx.evaluate("string(-.22)")
%FeelEx.Value{value: "-0.22", type: :string}boolean
iex(1)> FeelEx.evaluate("string(true)")
%FeelEx.Value{value: "true", type: :string}
iex(2)> FeelEx.evaluate("string(false)")
%FeelEx.Value{value: "false", type: :string}date
iex(1)> FeelEx.evaluate("string(@\"2024-01-01\")")
%FeelEx.Value{value: "2024-01-01", type: :string}
iex(2)> FeelEx.evaluate("string(date(\"2024-01-01\"))")
%FeelEx.Value{value: "2024-01-01", type: :string}time
iex(1)> FeelEx.evaluate("string(time(\"11:45:30\"))")
%FeelEx.Value{value: "11:45:30", type: :string}
iex(2)> FeelEx.evaluate("string(time(\"11:45\"))")
%FeelEx.Value{value: "11:45:00", type: :string}
iex(3)> FeelEx.evaluate("string(time(\"11:45:30+02:00\"))")
%FeelEx.Value{value: "11:45:30+02:00", type: :string}
iex(4)> FeelEx.evaluate("string(time(\"11:45:30+02:00\"))")
%FeelEx.Value{value: "11:45:30+02:00", type: :string}
iex(5)> FeelEx.evaluate("string(time(\"10:31:10@Europe/Paris\"))") %FeelEx.Value{value: "10:31:10@Europe/Paris", type: :string}
iex(6)> FeelEx.evaluate("string(@\"11:45:30\")")
%FeelEx.Value{value: "11:45:30",type: :string}
iex(7)> FeelEx.evaluate("string(@\"13:30\")")
%FeelEx.Value{value: "13:30:00", type: :string}
iex(8)> FeelEx.evaluate("string(@\"10:45:30+02:00\")")
%FeelEx.Value{value: "10:45:30+02:00", type: :string}
iex(9)> FeelEx.evaluate("string(@\"10:31:10@Europe/Paris\")")
%FeelEx.Value{value: "10:31:10@Europe/Paris", type: :string}date-time
iex(1)> FeelEx.evaluate("string(date and time(\"2015-09-18T10:31:10\"))") %FeelEx.Value{value: "2015-09-18T10:31:10", type: :string}
iex(2)> FeelEx.evaluate("string(date and time(\"2015-09-18T10:31:10+01:00\"))") %FeelEx.Value{value: "2015-09-18T10:31:10+01:00", type: :string}
iex(3)> FeelEx.evaluate("string(date and time(\"2015-09-18T10:31:10@Europe/Paris\"))")
%FeelEx.Value{value: "2015-09-18T10:31:10@Europe/Paris", type: :string}
iex(3)> FeelEx.evaluate("string(@\"2015-09-18T10:31:10\")")
%FeelEx.Value{value: "2015-09-18T10:31:10", type: :string}
iex(4)> FeelEx.evaluate("string(@\"2015-09-18T10:31:10+01:00\")")
%FeelEx.Value{value: "2015-09-18T10:31:10+01:00", type: :string}
iex(5)> FeelEx.evaluate("string(@\"2015-09-18T10:31:10@Europe/Paris\")") %FeelEx.Value{value: "2015-09-18T10:31:10@Europe/Paris", type: :string}days-time duration
iex(1)> FeelEx.evaluate("string(duration(\"P4D\"))")
%FeelEx.Value{value: "P4D", type: :string}
iex(2)> FeelEx.evaluate("string(duration(\"PT2H\"))")
%FeelEx.Value{value: "PT2H", type: :string}
iex(3)> FeelEx.evaluate("string(duration(\"PT30M\"))")\
%FeelEx.Value{value: "PT30M", type: :string}
iex(4)> FeelEx.evaluate("string(duration(\"P1DT6H\"))")
%FeelEx.Value{value: "P1DT6H", type: :string}
iex(5)> FeelEx.evaluate("string(@\"P4D\")")
%FeelEx.Value{value: "P4D",type: :string}
iex(6)> FeelEx.evaluate("string(@\"PT2H\")")
%FeelEx.Value{value: "PT2H", type: :string}
iex(7)> FeelEx.evaluate("string(@\"PT30M\")")
%FeelEx.Value{value: "PT30M", type: :string}
iex(8)> FeelEx.evaluate("string(@\"P1DT6H\")")
%FeelEx.Value{value: "P1DT6H", type: :string}years-month-duration
iex(1)> FeelEx.evaluate("string(duration(\"P2Y\"))")
%FeelEx.Value{value: "P2Y", type: :string}
iex(2)> FeelEx.evaluate("string(duration(\"P6M\"))")
%FeelEx.Value{value: "P6M", type: :string}
iex(3)> FeelEx.evaluate("string(duration(\"P1Y6M\"))")
%FeelEx.Value{value: "P1Y6M", type: :string}
iex(4)> FeelEx.evaluate("string(@\"P2Y\")")
%FeelEx.Value{value: "P2Y", type: :string}
iex(5)> FeelEx.evaluate("string(@\"P6M\")")
%FeelEx.Value{value: "P6M", type: :string}
iex(6)> FeelEx.evaluate("string(@\"P1Y6M\")")
%FeelEx.Value{value: "P1Y6M", type: :string}context
(To fix) order of keys not preserved.
context =
"""
string(
{
a: 1,
"b": date and time("2021-01-01T01:00:00"),
c: @\"P2Y\"
}
)
"""
iex(1)> FeelEx.evaluate(context)
%FeelEx.Value{value: "{a:1, b:2021-01-01T01:00:00, c: P2Y}", type: :string}list
iex(1)< FeelEx.evaluate("string([1,2+4])")
%FeelEx.Value{value: "[1, 6]", type: :string}Note!
Please note that string concatenation is only available for string values. However one may use the string() function to convert a value in some datatype to string and use the
iex(1)> FeelEx.evaluate("\"You are number \"+string(1)")
%FeelEx.Value{value: "You are number 1", type: :string}Take a look at these tests: https://github.com/ExSemantic/feel_ex/blob/master/test/expression_tests/string_test.exs for more examples.
Numbers
Leading 0's are valid
iex(1)> FeelEx.evaluate("-000002")
%FeelEx.Value{value: -2, type: :number}
iex(2)> FeelEx.evaluate("0001.5")
%FeelEx.Value{value: 1.5, type: :number}Addition, Subtraction, Multiplication, Division, Exponentiation
We can carry out the usual arithmetic operators with exponentiation having the highest precedence, division and multiplication the second highest and addition and subtraction the least precedence.
Examples:
2+3*2 is not 10 but 8 since the multiplicative operator * has more precedence than +
iex(1)> FeelEx.evaluate("2+3*2")
%FeelEx.Value{value: 8, type: :number}
iex(2)> FeelEx.evaluate("2/3")
%FeelEx.Value{value: 0.6666666666666666, type: :number}16/4**2 is not 16 but 1 since the multiplicative operator ** has more precedence than /
iex(1)> FeelEx.evaluate("2+3*2")
%FeelEx.Value{value: 1.0, type: :number}Take a look at these tests: https://github.com/ExSemantic/feel_ex/blob/master/test/expression_tests/number_test.exs for more examples.
Lists
Getting element list[i]
Access element using 1-based indexing. When index is out of bounds, null is returned.
iex(1)> FeelEx.evaluate("[1, \"a\", 3][1]")
%FeelEx.Value{value: 1, type: :number}
iex(2)> FeelEx.evaluate("[1, \"a\", 3][2]")
%FeelEx.Value{value: "a", type: :string}
iex(3)> FeelEx.evaluate("[1, \"a\", 3][3]")
%FeelEx.Value{value: 3, type: :number}
iex(4)> FeelEx.evaluate("[1, \"a\", 3][4]")
%FeelEx.Value{value: nil, type: :null}
iex(5)> FeelEx.evaluate("[1, \"a\", 3][5]")
%FeelEx.Value{value: nil, type: :null}
Using negative indexing we can access elements from the back of the list. The last element of the list is at index -1.
iex(1)> FeelEx.evaluate("[1, \"a\", 3][-1]")
%FeelEx.Value{value: 3, type: :number}
iex(2)> FeelEx.evaluate("[1, \"a\", 3][-2]")
%FeelEx.Value{value: "a", type: :string}
iex(3)> FeelEx.evaluate("[1, \"a\", 3][-3]")
%FeelEx.Value{value: 1, type: :number}
iex(4)> FeelEx.evaluate("[1, \"a\", 3][-4]")
%FeelEx.Value{value: nil, type: :null}Filtering
We can filter a list by a condition. The current element of the list is assigned to variable item.
iex(1)> FeelEx.evaluate("[1,2,4, 3][even(item)]")
[%FeelEx.Value{value: 2, type: :number}, %FeelEx.Value{value: 4, type: :number}]
iex(2)> FeelEx.evaluate("[1,2,4, 3][item>2]")
[%FeelEx.Value{value: 4, type: :number}, %FeelEx.Value{value: 3, type: :number}]Quantified expression
some a in b satisfies c: iterates over list b, assigning current element in list to a, and evaluating c. If some of the elements evaluates to true then the statement is true else it is false.
every a in b satisfies c: iterates over list b, assigning current element in list to a, and evaluating c. If all of the elements evaluates to true then the statement is true else it is false.
iex(1)> FeelEx.evaluate("some x in [1,2,3] satisfies x > 2")
%FeelEx.Value{value: true, type: :boolean}
iex(2)> FeelEx.evaluate("some x in [1,2,3] satisfies x > 5")
%FeelEx.Value{value: false, type: :boolean}
iex(3)> FeelEx.evaluate("some x in [1,2,3] satisfies even(x)")
%FeelEx.Value{value: true, type: :boolean}
iex(4)> FeelEx.evaluate("every x in [1,2,3] satisfies x >= 1")
%FeelEx.Value{value: true, type: :boolean}
iex(5)> FeelEx.evaluate("every x in [1,2,3] satisfies x >= 2")
%FeelEx.Value{value: false, type: :boolean}We can also apply this statement to cartesian product of more than one lists.
iex(6)> FeelEx.evaluate("every x in [1,2], y in [2,3] satisfies x < y")
%FeelEx.Value{value: false, type: :boolean}
iex(7)> FeelEx.evaluate("some x in [1,2], y in [2,3] satisfies x < y")
%FeelEx.Value{value: true, type: :boolean}Take a look at these tests: https://github.com/ExSemantic/feel_ex/blob/master/test/expression_tests/list_test.exs for more examples.
Contexts
Allows for previous element access
iex(1)> FeelEx.evaluate("{a: 2, b: a*2}.a")
%FeelEx.Value{
value: %{
a: %FeelEx.Value{value: 2, type: :number},
b: %FeelEx.Value{value: 4, type: :number}
},
type: :context
}Nested contexts
Values of contexts can be contexts themselves.
iex(1)> program = """
...(2)> {
...(2)> a: 1,
...(2)> b: {
...(2)> c: 2
...(2)> }
...(2)> }
...(2)> """
"{\n a: 1,\n b: {\n c: 2\n }\n}\n"
iex(3)> FeelEx.evaluate(program)
%FeelEx.Value{
value: %{
a: %FeelEx.Value{value: 1, type: :number},
b: %FeelEx.Value{
value: %{c: %FeelEx.Value{value: 2, type: :number}},
type: :context
}
},
type: :context
}
Get entry path a.b
We may use dot notation to access elements of a context.
iex(1)> FeelEx.evaluate("{a: 2}.a")
%FeelEx.Value{value: 2, type: :number}
iex(2)> FeelEx.evaluate("{a: 2, b: {b: 3}}.b")
%FeelEx.Value{
value: %{b: %FeelEx.Value{value: 3, type: :number}},
type: :context
}If the name we are accessing does not exist in the context than we simply return null.
iex(1)> FeelEx.evaluate("{}.a")
%FeelEx.Value{value: nil, type: :null}
iex(2)> FeelEx.evaluate("{b: 1}.a")
%FeelEx.Value{value: nil, type: :null}
iex(3)> FeelEx.evaluate("{a: {c: 2}}.a.b")
%FeelEx.Value{value: nil, type: :null}
Filter a[c]
Given a list of context element a we may filter elements using a filter c.
Examples:
iex(1)> program =
...(1)> """
...(1)> [
...(1)> {
...(1)> a: "p1",
...(1)> b: 5
...(1)> },
...(1)> {
...(1)> a: "p2",
...(1)> b: 10
...(1)> }
...(1)> ][b > 7]
...(1)> """
"[\n {\n a: \"p1\",\n b: 5\n },\n {\n a: \"p2\",\n b: 10\n }\n][b > 7]\n"
iex(2)> FeelEx.evaluate(program)
[
%FeelEx.Value{
value: %{
b: %FeelEx.Value{value: 10, type: :number},
a: %FeelEx.Value{value: "p2", type: :string}
},
type: :context
}
]Projection
The dot notation may be used over a list to access multiple context at once.
Example:
iex(1)> program1 =
...(1)> """
...(1)> [
...(1)> {
...(1)> a: "p1",
...(1)> b: 5
...(1)> },
...(1)> {
...(1)> a: "p2",
...(1)> b: 10
...(1)> }
...(1)> ].a
...(1)> """
"[\n {\n a: \"p1\",\n b: 5\n },\n {\n a: \"p2\",\n b: 10\n }\n].a\n"
iex(2)> FeelEx.evaluate(program1)
[
%FeelEx.Value{value: "p1", type: :string},
%FeelEx.Value{value: "p2", type: :string}
]
iex(3)> program2 =
...(3)> """
...(3)> [
...(3)> {
...(3)> a: "p1",
...(3)> b: 5
...(3)> },
...(3)> {
...(3)> a: "p2",
...(3)> c: 20
...(3)> }
...(3)> ].b
...(3)> """
"[\n {\n a: \"p1\",\n b: 5\n },\n {\n a: \"p2\",\n c: 20\n }\n].b\n"
iex(4)> FeelEx.evaluate(program2)
[%FeelEx.Value{value: 5, type: :number}, %FeelEx.Value{value: nil, type: :null}]Take a look at these tests: https://github.com/ExSemantic/feel_ex/blob/master/test/expression_tests/context_test.exs for more examples.
Functions
Numerical Functions
Decimal
iex(1)> FeelEx.evaluate("1/3")
%FeelEx.Value{value: 0.3333333333333333, type: :number}
iex(2)> FeelEx.evaluate("decimal(1/3,2)")
%FeelEx.Value{value: 0.33, type: :number}floor
iex(1)> FeelEx.evaluate("floor(1)")
%FeelEx.Value{value: 1, type: :number}floor with scale
iex(1)> FeelEx.evaluate("floor(1.56,1)")
%FeelEx.Value{value: 1.5, type: :number}ceiling
iex(1)> FeelEx.evaluate("ceiling(1.54)")
%FeelEx.Value{value: 2, type: :number}ceiling with scale
iex(1)> FeelEx.evaluate("ceiling(1.5432,2)")
%FeelEx.Value{value: 1.55, type: :number}round up
Rounds to given scale.
iex(1)> FeelEx.evaluate("round up(1.123,3)")
%FeelEx.Value{value: 1.123, type: :number}
iex(2)> FeelEx.evaluate("round up(1.1234,3)")
%FeelEx.Value{value: 1.124, type: :number}
iex(3)> FeelEx.evaluate("round up(-1.1234,3)")
%FeelEx.Value{value: -1.124, type: :number}
iex(4)> FeelEx.evaluate("round up(-1.1234,1)")
%FeelEx.Value{value: -1.2, type: :number}
iex(5)> FeelEx.evaluate("round up(-1.121,2)")
%FeelEx.Value{value: -1.13, type: :number}round down
iex(1)> FeelEx.evaluate("round down(-5.5,0)")
%FeelEx.Value{value: -5, type: :number}
iex(2)> FeelEx.evaluate("round down(-5.5,1)")
%FeelEx.Value{value: -5.5, type: :number}
iex(3)> FeelEx.evaluate("round down(1.121,2)")
%FeelEx.Value{value: 1.12, type: :number}
iex(4)> FeelEx.evaluate("round down(-1.126,2)")
%FeelEx.Value{value: -1.12, type: :number}round half up
iex(1)> FeelEx.evaluate("round half up(1.126,2)")
%FeelEx.Value{value: 1.13, type: :number}
iex(2)> FeelEx.evaluate("round half up(1.125,2)")
%FeelEx.Value{value: 1.13, type: :number}
iex(3)> FeelEx.evaluate("round half up(1.124,2)")
%FeelEx.Value{value: 1.12, type: :number}
iex(4)> FeelEx.evaluate("round half up(1.124,0)")
%FeelEx.Value{value: 1.0, type: :number}
iex(5)> FeelEx.evaluate("round half up(1.124,0)")
%FeelEx.Value{value: 1.0, type: :number}
iex(6)> recompile
iex(7)> FeelEx.evaluate("round half up(1.124,0)")
%FeelEx.Value{value: 1, type: :number}
iex(8)> FeelEx.evaluate("round half up(-1.124,2)")
%FeelEx.Value{value: -1.12, type: :number}
iex(9)> FeelEx.evaluate("round half up(-1.125,2)")
%FeelEx.Value{value: -1.13, type: :number}
Temporal Expressions
Addition
<date>+<duration>=<duration>
iex(1)> FeelEx.evaluate("date(\"2020-04-06\") + duration(\"P1D\")")
%FeelEx.Value{value: ~D[2020-04-07], type: :date}<duration>+<date>=<duration>
iex(1)> FeelEx.evaluate("duration(\"P1D\")+ date(\"2020-04-06\")")<time>+<duration>=<time>
iex(1)> FeelEx.evaluate("time(\"08:00:00\") + duration(\"PT1H\")")
%FeelEx.Value{value: ~T[09:00:00], type: :time}
iex(2)> FeelEx.evaluate("time(\"08:00:00@Europe/Paris\") + duration(\"PT1H\")")
%FeelEx.Value{value: {~T[09:00:00], "Europe/Paris"}, type: :context}
iex(3)> FeelEx.evaluate("time(\"08:00:00+01:00\") + duration(\"PT1H\")")
%FeelEx.Value{value: {~T[09:00:00], "+01:00"}, type: :time}<duration>+<time>=<time>
iex(1)> FeelEx.evaluate("duration(\"PT1H\") + time(\"08:00:00\")")
%FeelEx.Value{value: ~T[09:00:00], type: :time}
iex(2)> FeelEx.evaluate("duration(\"PT1H\") + time(\"08:00:00@Europe/Paris\")")
%FeelEx.Value{value: {~T[09:00:00], "Europe/Paris"}, type: :context}
iex(3)> FeelEx.evaluate("duration(\"PT1H\") + time(\"08:00:00+01:00\")")
%FeelEx.Value{value: {~T[09:00:00], "+01:00"}, type: :time}<date-time>+<duration>=<duration>
iex(1)> FeelEx.evaluate("date and time(\"2020-04-06T08:00:00\") + duration(\"P7D\")")
%FeelEx.Value{value: ~N[2020-04-13 08:00:00], type: :date_time}
iex(2)> FeelEx.evaluate("date and time(\"2020-04-06T08:00:00+01:00\") + duration(\"P7D\")")
%FeelEx.Value{value: {~N[2020-04-13 08:00:00], "+01:00"}, type: :date_time}
iex(3)> FeelEx.evaluate("date and time(\"2020-04-06T08:00:00@Europe/Malta\") + duration(\"P7D\")")
%FeelEx.Value{
value: {~N[2020-04-13 08:00:00], "+01:00", "Europe/Malta"},
type: :date_time
}<duration>+<date-time>=<duration>
iex(1)> FeelEx.evaluate("duration(\"P7D\")+date and time(\"2020-04-06T08:00:00\")")
%FeelEx.Value{value: ~N[2020-04-13 08:00:00], type: :date_time}
iex(2)> FeelEx.evaluate("duration(\"P7D\") + date and time(\"2020-04-06T08:00:00+01:00\")")
%FeelEx.Value{value: {~N[2020-04-13 08:00:00], "+01:00"}, type: :date_time}
iex(3)> FeelEx.evaluate("duration(\"P7D\")+date and time(\"2020-04-06T08:00:00@Europe/Malta\")")
%FeelEx.Value{
value: {~N[2020-04-13 08:00:00], "+01:00", "Europe/Malta"},
type: :date_time
}<duration>+<duration>=<duration>
iex(1)> FeelEx.evaluate("duration(\"P1D\") + duration(\"PT1H\")")
%FeelEx.Value{value: %Duration{day: 1, hour: 1}, type: :days_time_duration}
iex(2)> FeelEx.evaluate("duration(\"P1DT2H\") + duration(\"P1DT3H\")")
%FeelEx.Value{value: %Duration{day: 2, hour: 5}, type: :days_time_duration}Take a look at these tests: https://github.com/ExSemantic/feel_ex/blob/master/test/expression_tests/temporal_expressions_test.exs for more examples.
Subtraction
<date>-<date>=<duration>
iex(1)> FeelEx.evaluate("date(\"2020-04-06\") - date(\"2020-04-01\")")
%FeelEx.Value{value: %Duration{day: 5}, type: :days_time_duration}
iex(2)> FeelEx.evaluate("date(\"2023-10-01\") - date(\"2023-07-01\")")
%FeelEx.Value{value: %Duration{day: 92}, type: :days_time_duration}
iex(3)> FeelEx.evaluate("date(\"2023-01-01\") - date(\"2022-12-31\")")
%FeelEx.Value{value: %Duration{day: 1}, type: :days_time_duration}<date>-<duration>=<date>
iex(1)> FeelEx.evaluate("date(\"2020-04-06\") - duration(\"P5D\")")
%FeelEx.Value{value: ~D[2020-04-01], type: :date}
iex(2)> FeelEx.evaluate("date(\"2021-08-15\") - duration(\"P5D\")")
%FeelEx.Value{value: ~D[2021-08-10], type: :date}
iex(3)> FeelEx.evaluate("date(\"2020-04-06\") - duration(\"P-5D\")")
%FeelEx.Value{value: ~D[2020-04-11], type: :date}<time>-<time>=<days-time-duration>
iex(1)> FeelEx.evaluate("time(\"08:00:00\") - time(\"06:00:01\")")
%FeelEx.Value{
value: %Duration{hour: 1, minute: 59, second: 59},
type: :days_time_duration
}
iex(2)> FeelEx.evaluate("time(\"08:00:00+01:00\") - time(\"06:00:01+01:00\")")
%FeelEx.Value{
value: %Duration{hour: 1, minute: 59, second: 59},
type: :days_time_duration
}
iex(3)> FeelEx.evaluate("time(\"08:00:00+01:00\") - time(\"06:00:01-01:00\")")
[warning] [Elixir.FeelEx.Expression][do_subtract/2] Cannot subtract %FeelEx.Value{value: {~T[08:00:00], "+01:00"}, type: :time} with %FeelEx.Value{value: {~T[06:00:01], "-01:00"}, type: :time}.
%FeelEx.Value{value: nil, type: :null}
iex(4)> FeelEx.evaluate("time(\"08:00:00@Europe/Malta\") - time(\"06:00:01@Europe/Malta\")")
%FeelEx.Value{
value: %Duration{hour: 1, minute: 59, second: 59},
type: :days_time_duration
}
iex(5)> FeelEx.evaluate("time(\"08:00:00@Europe/Malta\") - time(\"06:00:01@Europe/Paris\")")
[warning] [Elixir.FeelEx.Expression][do_subtract/2] Cannot subtract %FeelEx.Value{value: {~T[08:00:00], "+01:00", "Europe/Malta"}, type: :time} with %FeelEx.Value{value: {~T[06:00:01], "+01:00", "Europe/Paris"}, type: :time}.
%FeelEx.Value{value: nil, type: :null}Note!: Time difference for times with different time zones and offsets is currently not supported.
<date-time>-<date-time>=<days-time-duration>
iex(1)> FeelEx.evaluate("date and time(\"2025-01-01T08:00:00\") - date and time(\"2024-01-01T06:00:01\")")
%FeelEx.Value{
value: %Duration{hour: 8785, minute: 59, second: 59},
type: :days_time_duration
}
iex(2)> FeelEx.evaluate("date and time(\"2025-01-01T08:00:00+01:00\") - date and time(\"2024-01-01T06:00:01+01:00\")")
%FeelEx.Value{
value: %Duration{hour: 8785, minute: 59, second: 59},
type: :days_time_duration
}
iex(3)> FeelEx.evaluate("date and time(\"2025-01-01T08:00:00+01:00\") - date and time(\"2024-01-01T06:00:01-01:00\")")
[warning] [Elixir.FeelEx.Expression][do_subtract/2] Cannot subtract %FeelEx.Value{value: {~N[2025-01-01 08:00:00], "+01:00"}, type: :date_time} with %FeelEx.Value{value: {~N[2024-01-01 06:00:01], "-01:00"}, type: :date_time}.
%FeelEx.Value{value: nil, type: :null}
iex(4)> FeelEx.evaluate("date and time(\"2025-01-01T08:00:00@Europe/Malta\") - date and time(\"2024-01-01T06:00:01@Europe/Malta\")")
%FeelEx.Value{
value: %Duration{hour: 8785, minute: 59, second: 59},
type: :days_time_duration
}
iex(5)> FeelEx.evaluate("date and time(\"2025-01-01T08:00:00@Europe/Malta\") - date and time(\"2024-01-01T06:00:01@Europe/Paris\")")
[warning] [Elixir.FeelEx.Expression][do_subtract/2] Cannot subtract %FeelEx.Value{value: {~N[2025-01-01 08:00:00], "+01:00", "Europe/Malta"}, type: :date_time} with %FeelEx.Value{value: {~N[2024-01-01 06:00:01], "+01:00", "Europe/Paris"}, type: :date_time}.
%FeelEx.Value{value: nil, type: :null}Note!: DateTime difference for times with different time zones and offsets is currently not supported.
<date-time>-<duration>=<date-time>
iex(1)> FeelEx.evaluate("date and time(\"2021-01-01T08:00:00\") - duration(\"PT2H\")")
%FeelEx.Value{value: ~N[2021-01-01 06:00:00], type: :date_time}
iex(2)> FeelEx.evaluate("date and time(\"2021-01-01T08:00:00+01:00\") - duration(\"PT2H\")")
%FeelEx.Value{value: {~N[2021-01-01 06:00:00], "+01:00"}, type: :date_time}
iex(3)> FeelEx.evaluate("date and time(\"2021-01-01T08:00:00@Europe/Malta\") - duration(\"PT2H\")")
%FeelEx.Value{
value: {~N[2021-01-01 06:00:00], "+01:00", "Europe/Malta"},
type: :date_time
}<days-time-duration>-<days-time-duration>=<days-time-duration>
iex(1)> FeelEx.evaluate("duration(\"P7D\") - duration(\"P2D\")")
%FeelEx.Value{value: %Duration{hour: 120}, type: :days_time_duration}
iex(2)> FeelEx.evaluate("duration(\"P7D\") - duration(\"P8DT1S\")")
%FeelEx.Value{
value: %Duration{hour: -24, second: -1},
type: :days_time_duration
}<years-months-duration>-<years-months-duration>=<years-months-duration>
iex(1)> FeelEx.evaluate("duration(\"P1Y\") - duration(\"P3M\")")
%FeelEx.Value{value: %Duration{month: 9}, type: :years_months_duration}
iex(2)> FeelEx.evaluate("duration(\"P3Y1M\") - duration(\"P1Y12M\")")
%FeelEx.Value{value: %Duration{year: 1, month: 1}, type: :years_months_duration}Multiplication
<number>*<days_time_duration>=<days_time_duration>
iex(1)> FeelEx.evaluate("5*duration(\"P1D\")")
%FeelEx.Value{value: %Duration{day: 5}, type: :days_time_duration}<days_time_duration>*<number>=<days_time_duration>
iex(1)> FeelEx.evaluate("duration(\"P1D\") * 5")
%FeelEx.Value{value: %Duration{day: 5}, type: :days_time_duration}`<number>*<years_months_duration>=<years_months_duration>
iex(1)> FeelEx.evaluate("13 * duration(\"P1M\")")
%FeelEx.Value{value: %Duration{year: 1, month: 1}, type: :years_months_duration}<years_months_duration>*<number>=<years_months_duration>
iex(15)> FeelEx.evaluate("duration(\"P1M\") * 13")
%FeelEx.Value{value: %Duration{year: 1, month: 1}, type: :years_months_duration}Division
<days-time-duration>/<days-time-duration>=<number>
iex(1)> FeelEx.evaluate("duration(\"P5D\") / duration(\"P1D\")")
%FeelEx.Value{value: 5, type: :number}<days-time-duration>/<number>=<days-time-duration>
FeelEx.evaluate("duration(\"P5D\")/5")<years-months-duration>/<years-months-duration>=<number>
iex(1)> FeelEx.evaluate("duration(\"P1Y\") / duration(\"P2M\")")
%FeelEx.Value{value: 6, type: :number}<years-months-duration>/<number>=<years-months-duration>
iex(1)> FeelEx.evaluate("duration(\"P1Y\") / 12")
%FeelEx.Value{value: %Duration{month: 1}, type: :years_months_duration}Temporal Properties
Accessing year
Interactive Elixir (1.17.3) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> FeelEx.evaluate("@\"2021-01-01\".year")
%FeelEx.Value{value: 2021, type: :number}
iex(2)> FeelEx.evaluate("date(\"2021-01-01\").year")
%FeelEx.Value{value: 2021, type: :number}
iex(3)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").year")
%FeelEx.Value{value: 2021, type: :number}
iex(3)> FeelEx.evaluate("@\"2021-01-01T08:01:05\".year")
%FeelEx.Value{value: 2021, type: :number}
iex(4)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05+01:00\").year")
%FeelEx.Value{value: 2021, type: :number}
iex(5)> FeelEx.evaluate("@\"2021-01-01T08:01:05+01:00\".year")
%FeelEx.Value{value: 2021, type: :number}
iex(6)> FeelEx.evaluate("@\"2021-01-01T08:01:05@Europe/Malta\".year")
%FeelEx.Value{value: 2021, type: :number}
iex(7)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05@Europe/Malta\").year")
%FeelEx.Value{value: 2021, type: :number}
Accessing month in [1-12] where 1 is January.
iex(1)> FeelEx.evaluate("@\"2021-01-01\".month")
%FeelEx.Value{value: 1, type: :number}
iex(2)> FeelEx.evaluate("date(\"2021-01-01\").month")
%FeelEx.Value{value: 1, type: :number}
iex(3)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").month")
%FeelEx.Value{value: 1, type: :number}
iex(4)> FeelEx.evaluate("@\"2021-01-01T08:01:05\".month")
%FeelEx.Value{value: 1, type: :number}
iex(5)> FeelEx.evaluate("date and time(\"2021-05-01T08:01:05+01:00\").month")
%FeelEx.Value{value: 5, type: :number}
iex(6)> FeelEx.evaluate("@\"2021-01-01T08:05:05+01:00\".month")
%FeelEx.Value{value: 1, type: :number}
iex(7)> FeelEx.evaluate("date and time(\"2021-05-01T08:01:05@Europe/Malta\").month")
%FeelEx.Value{value: 5, type: :number}
iex(8)> FeelEx.evaluate("@\"2021-01-01T08:05:05@Europe/Malta\".month")
%FeelEx.Value{value: 1, type: :number}
Accessing day in [1-31].
iex(1)> FeelEx.evaluate("@\"2021-01-01\".day")
%FeelEx.Value{value: 1, type: :number}
iex(2)> FeelEx.evaluate("date(\"2021-01-01\").day")
%FeelEx.Value{value: 1, type: :number}
iex(3)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").day")
%FeelEx.Value{value: 1, type: :number}
iex(4)> FeelEx.evaluate("@\"2021-01-01T08:01:05\".day")
%FeelEx.Value{value: 1, type: :number}
iex(5)> FeelEx.evaluate("date and time(\"2021-05-01T08:01:05+01:00\").day")
%FeelEx.Value{value: 1, type: :number}
iex(6)> FeelEx.evaluate("@\"2021-01-01T08:05:05+01:00\".day")
%FeelEx.Value{value: 1, type: :number}
iex(7)> FeelEx.evaluate("date and time(\"2021-05-01T08:01:05@Europe/Malta\").day")
%FeelEx.Value{value: 1, type: :number}
iex(8)> FeelEx.evaluate("@\"2021-01-01T08:05:05@Europe/Malta\".day")
%FeelEx.Value{value: 1, type: :number}
Accessing weekday in [1-7] where 1 is Monday.
iex(1)> FeelEx.evaluate("@\"2021-01-01\".weekday")
%FeelEx.Value{value: 5, type: :number}
iex(2)> FeelEx.evaluate("date(\"2021-01-01\").weekday")
%FeelEx.Value{value: 5, type: :number}
iex(3)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").weekday")
%FeelEx.Value{value: 5, type: :number}
iex(4)> FeelEx.evaluate("@\"2021-01-01T08:01:05\".weekday")
%FeelEx.Value{value: 5, type: :number}
iex(5)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05+01:00\").weekday")
%FeelEx.Value{value: 5, type: :number}
iex(6)> FeelEx.evaluate("@\"2021-01-01T08:01:05+01:00\".weekday")
%FeelEx.Value{value: 5, type: :number}
iex(7)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05@Europe/Malta\").weekday")
%FeelEx.Value{value: 5, type: :number}
iex(8)> FeelEx.evaluate("@\"2021-01-01T08:01:05@Europe/Malta\".weekday")
%FeelEx.Value{value: 5, type: :number}
Accessing hour in [0-23]
iex(1)> FeelEx.evaluate("time(\"08:01:05\").hour")
%FeelEx.Value{value: 8, type: :number}
iex(2)> FeelEx.evaluate("@\"08:01:05\".hour")
%FeelEx.Value{value: 8, type: :number}
iex(3)> FeelEx.evaluate("time(\"08:01:05+01:00\").hour")
%FeelEx.Value{value: 8, type: :number}
iex(4)> FeelEx.evaluate("@\"08:01:05+01:00\".hour")
%FeelEx.Value{value: 8, type: :number}
iex(5)> FeelEx.evaluate("time(\"08:01:05@Europe/Malta\").hour")
%FeelEx.Value{value: 8, type: :number}
iex(6)> FeelEx.evaluate("@\"08:01:05@Europe/Malta\".hour")
%FeelEx.Value{value: 8, type: :number}
iex(7)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").hour")
%FeelEx.Value{value: 8, type: :number}
iex(8)> FeelEx.evaluate("@\"2021-01-01T08:01:05\".hour")
%FeelEx.Value{value: 8, type: :number}
iex(9)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05+01:00\").hour")
%FeelEx.Value{value: 8, type: :number}
iex(10)> FeelEx.evaluate("@\"2021-01-01T08:01:05+01:00\".hour")
%FeelEx.Value{value: 8, type: :number}
iex(11)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05@Europe/Malta\").hour")
%FeelEx.Value{value: 8, type: :number}
iex(12)> FeelEx.evaluate("@\"2021-01-01T08:01:05@Europe/Malta\".hour")
%FeelEx.Value{value: 8, type: :number}
Accessing minute in [0-59]
iex(1)> FeelEx.evaluate("time(\"08:01:05\").minute")
%FeelEx.Value{value: 1, type: :number}
iex(2)> FeelEx.evaluate("@\"08:01:05\".minute")
%FeelEx.Value{value: 1, type: :number}
iex(3)> FeelEx.evaluate("time(\"08:01:05+01:00\").minute")
%FeelEx.Value{value: 1, type: :number}
iex(4)> FeelEx.evaluate("@\"08:01:05+01:00\".minute")
%FeelEx.Value{value: 1, type: :number}
iex(5)> FeelEx.evaluate("time(\"08:01:05@Europe/Malta\").minute")
%FeelEx.Value{value: 1, type: :number}
iex(6)> FeelEx.evaluate("@\"08:01:05@Europe/Malta\".minute")
%FeelEx.Value{value: 1, type: :number}
iex(7)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").minute")
%FeelEx.Value{value: 1, type: :number}
iex(8)> FeelEx.evaluate("@\"2021-01-01T08:01:05\".minute")
%FeelEx.Value{value: 1, type: :number}
iex(9)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05+01:00\").minute")
%FeelEx.Value{value: 1, type: :number}
iex(10)> FeelEx.evaluate("@\"2021-01-01T08:01:05+01:00\".minute")
%FeelEx.Value{value: 1, type: :number}
iex(11)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05@Europe/Malta\").minute")
%FeelEx.Value{value: 1, type: :number}
iex(12)> FeelEx.evaluate("@\"2021-01-01T08:01:05@Europe/Malta\".minute")
%FeelEx.Value{value: 1, type: :number}
Accessing second in [0-59]
iex(1)> FeelEx.evaluate("time(\"08:01:05\").second")
%FeelEx.Value{value: 5, type: :number}
iex(2)> FeelEx.evaluate("@\"08:01:05\".second")
%FeelEx.Value{value: 5, type: :number}
iex(3)> FeelEx.evaluate("time(\"08:01:05+01:00\").second")
%FeelEx.Value{value: 5, type: :number}
iex(4)> FeelEx.evaluate("@\"08:01:05+01:00\".second")
%FeelEx.Value{value: 5, type: :number}
iex(5)> FeelEx.evaluate("time(\"08:01:05@Europe/Malta\").second")
%FeelEx.Value{value: 5, type: :number}
iex(6)> FeelEx.evaluate("@\"08:01:05@Europe/Malta\".second")
%FeelEx.Value{value: 5, type: :number}
iex(7)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05\").second")
%FeelEx.Value{value: 5, type: :number}
iex(8)> FeelEx.evaluate("@\"2021-01-01T08:01:05\".second")
%FeelEx.Value{value: 5, type: :number}
iex(9)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05+01:00\").second")
%FeelEx.Value{value: 5, type: :number}
iex(10)> FeelEx.evaluate("@\"2021-01-01T08:01:05+01:00\".second")
%FeelEx.Value{value: 5, type: :number}
iex(11)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05@Europe/Malta\").second")
%FeelEx.Value{value: 5, type: :number}
iex(12)> FeelEx.evaluate("@\"2021-01-01T08:01:05@Europe/Malta\".second")
%FeelEx.Value{value: 5, type: :number}Accessing time offset
iex(1)> FeelEx.evaluate("@\"08:01:05+01:32\".time offset")
%FeelEx.Value{value: %Duration{hour: 1, minute: 32}, type: :days_time_duration}
iex(2)> FeelEx.evaluate("time(\"08:01:05-02:21\").time offset")
%FeelEx.Value{value: %Duration{hour: -2, minute: -21}
iex(3)> FeelEx.evaluate("time(\"08:01:05-01@Europe/Malta\").time offset")
%FeelEx.Value{value: %Duration{hour: 1}, type: :days_time_duration}
iex(4)> FeelEx.evaluate("@\"08:01:05@Europe/Malta\".time offset")
%FeelEx.Value{value: %Duration{hour: 1}, type: :days_time_duration}
iex(5)> FeelEx.evaluate("@\"2021-01-03T08:01:05+01:02\".time offset")
%FeelEx.Value{value: %Duration{hour: 1, minute: 2}, type: :days_time_duration}
iex(6)> FeelEx.evaluate("date and time(\"2021-01-03T08:01:05-02:01\").time offset")
%FeelEx.Value{value: %Duration{hour: -2, minute: -1}, type: :days_time_duration}
iex(7)> FeelEx.evaluate("@\"2021-01-03T08:01:05+01:02\".time offset")
%FeelEx.Value{value: %Duration{hour: 1, minute: 2}, type: :days_time_duration}
iex(8)> FeelEx.evaluate("date and time(\"2021-01-03T08:01:05-02:01\").time offset")
%FeelEx.Value{value: %Duration{hour: -2, minute: -1}, type: :days_time_duration}
iex(9)> FeelEx.evaluate("@\"2021-01-03T08:01:05@Europe/Malta\".time offset")
%FeelEx.Value{value: %Duration{hour: 1}, type: :days_time_duration}
iex(10)> FeelEx.evaluate("date and time(\"2021-01-03T08:01:05@Europe/Malta\").time offset")
%FeelEx.Value{value: %Duration{hour: 1}, type: :days_time_duration}Accessing timezone
iex(1)> FeelEx.evaluate("time(\"08:01:05@Europe/Malta\").timezone")
%FeelEx.Value{value: "Europe/Malta", type: :string}
iex(2)> FeelEx.evaluate("@\"08:01:05@Europe/Malta\".timezone")
%FeelEx.Value{value: "Europe/Malta", type: :string}
iex(3)> FeelEx.evaluate("date and time(\"2021-01-01T08:01:05@Europe/Malta\").timezone")
%FeelEx.Value{value: "Europe/Malta", type: :string}
iex(4)> FeelEx.evaluate("@\"2021-01-01T08:01:05@Europe/Malta\".timezone")
%FeelEx.Value{value: "Europe/Malta", type: :string}
Access days, hours in [0..23], minutes in [0..59], seconds in [0..59]for days-time-duration
iex(1)> FeelEx.evaluate("@\"PT24H\".days")
%FeelEx.Value{value: 1, type: :number}
iex(2)> FeelEx.evaluate("@\"P2DT-24H\".days")
%FeelEx.Value{value: 1, type: :number}
iex(3)> FeelEx.evaluate("@\"P3DT-24H\".days")
%FeelEx.Value{value: 2, type: :number}
iex(4)> FeelEx.evaluate("@\"P3DT24H\".days")
%FeelEx.Value{value: 4, type: :number}
iex(5)> FeelEx.evaluate("@\"P3DT24H1440M\".days")
%FeelEx.Value{value: 5, type: :number}
iex(6)> FeelEx.evaluate("@\"P3DT24H1441M\".days")
%FeelEx.Value{value: 5, type: :number}
iex(7)> FeelEx.evaluate("@\"P3DT48H1441M\".days")
%FeelEx.Value{value: 6, type: :number}
iex(8)> FeelEx.evaluate("@\"PT25H63M\".minutes")
%FeelEx.Value{value: 3, type: :number}
iex(9)> FeelEx.evaluate("@\"PT25H63M119S\".seconds")
%FeelEx.Value{value: 59, type: :number}
Access years, months in [0..11]
iex(1)> FeelEx.evaluate("@\"P1Y13M\".years")
%FeelEx.Value{value: 2, type: :number}
iex(2)> FeelEx.evaluate("@\"P1Y13M\".months")
%FeelEx.Value{value: 1, type: :number}
iex(3)> FeelEx.evaluate("@\"P1Y13M\".months")
%FeelEx.Value{value: 1, type: :number}