Skip to content

Commit

Permalink
refactoring date/time functions (wip) (#405)
Browse files Browse the repository at this point in the history
* refactors date/time functions
* adds date time format constants
* updates documentation for release 3.1.0
  • Loading branch information
uklimaschewski authored Nov 19, 2023
1 parent dfe5aab commit b6290f9
Show file tree
Hide file tree
Showing 39 changed files with 951 additions and 367 deletions.
56 changes: 52 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@ EvalEx - Java Expression Evaluator
[![Vulnerabilities](https://sonarcloud.io/api/project_badges/measure?project=ezylang_EvalEx&metric=vulnerabilities)](https://sonarcloud.io/summary/new_code?id=ezylang_EvalEx)
[![Maven Central](https://img.shields.io/maven-central/v/com.ezylang/EvalEx.svg?label=Maven%20Central)](https://search.maven.org/search?q=a:%22EvalEx%22)

| :warning: Version 3 of EvalEx is a complete rewrite of the popular expression evaluator. See [the new documentation area](https://ezylang.github.io/EvalEx/concepts/changes.html) for an overview of the changes. |
|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| For a complete documentation, see [the documentation site](https://ezylang.github.io/EvalEx/). |
|------------------------------------------------------------------------------------------------|

EvalEx is a handy expression evaluator for Java, that allows to parse and evaluate expression
strings.
EvalEx is a handy expression evaluator for Java, that allows to parse and evaluate expression strings.

## Key Features:

- Supports numerical, boolean, string, date time, duration, array and structure expressions, operations and variables.
- Array and structure support: Arrays and structures can be mixed, building arbitrary data
structures.
- Supports the NULL datatype.
- Uses BigDecimal for numerical calculations.
- MathContext and number of decimal places can be configured, with optional automatic rounding.
- No dependencies to external libraries.
Expand Down Expand Up @@ -97,6 +97,35 @@ EvaluationValue result = expression
System.out.println(result.getNumberValue()); // prints 6.00
```

### Values can be passed in a map

Instead of specifying the variable values one by one, they can be set by defining a map with names and values and then
passing it to the _withValues()_ method:

The data conversion of the passed values will automatically be performed through a customizable converter.

It is also possible to configure a custom data accessor to read and write values.

```java
Expression expression = new Expression("a+b+c");

Map<String, Object> values = new HashMap<>();
values.put("a", true);
values.put("b", " : ");
values.put("c", 24.7);

EvaluationValue result = expression.withValues(values).evaluate();

System.out.println(result.getStringValue()); // prints "true : 24.7"
```

See chapter [Data Types](https://ezylang.github.io/EvalEx/concepts/datatypes.html) for details on the conversion.

Another option to have EvalEx use your data is to define a custom data accessor.

See chapter [Data Access](https://ezylang.github.io/EvalEx/customization/data_access.html) for details.


### Boolean expressions produce a boolean result:

```java
Expand Down Expand Up @@ -163,6 +192,25 @@ BigDecimal result = expression.evaluate().getNumberValue();
System.out.println(result); // prints 44.85
```

### Calculating with date-time and duration

Date-tme and duration values are supported. There are functions to create, parse and format these values.
Additionally, the plus and minus operators can be used to e.g. add or subtract durations, or to calculate the
difference between two dates:

```java
Instant start = Instant.parse("2023-12-05T11:20:00.00Z");
Instant end = Instant.parse("2023-12-04T23:15:30.00Z");

Expression expression = new Expression("start - end");
EvaluationValue result = expression
.with("start", start)
.and("end", end)
.evaluate();
System.out.println(result); // will print "EvaluationValue(value=PT12H4M30S, dataType=DURATION)"
```
See the [Documentation](https://ezylang.github.io/EvalEx/concepts/date_time_duration.html) for more details.

## EvalEx-big-math

[Big-math](https://github.com/eobermuhlner/big-math) is a library by Eric Obermühlner. It provides
Expand Down
8 changes: 5 additions & 3 deletions docs/concepts/changes.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@ documentation for more information.
Most notably new features:

* Better boolean support.
* Full support for string operations and functions.
* Full support for multidimensional arrays.
* Full support for nestable structures.
* Support for string operations and functions.
* Support for date-time and duration values and operations.
* Support for _null_ values.
* Support for multidimensional arrays.
* Support for nestable structures.
* Structures and arrays can be combined to work with arbitrary data structures.
* New data access support, connecting expressions with you data made easy.
* New configuration concept.
Expand Down
7 changes: 4 additions & 3 deletions docs/concepts/datatypes.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,10 @@ object.

### DATE_TIME

Any instance of _java.time.LocalDate_, _java.time.LocalDateTime_, _java.time.ZoneDateTime_ or _java.time.OffsetDateTime_ will automatically be converted to
a _DATE_TIME_ datatype. Conversion will be done by using the current time zone id on the input
object.
Any instance of _java.time.Instant_, _java.time.LocalDate_, _java.time.LocalDateTime_, _java.time.ZoneDateTime_,
_java.time.OffsetDateTime_, _java.util.Date_ or _java.util.Calendar_, will automatically be converted to
a _DATE_TIME_ datatype. If the conversion requires a time zone and no time zone is given in the input object,
then the configured time zone is used.

### DURATION

Expand Down
25 changes: 21 additions & 4 deletions docs/concepts/date_time_duration.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@ _java.time.Duration_ values.
A _DATE_TIME_ instant is instantaneous point on the time-line, it holds no information about the time zone.
Time zones come into play, when converting local dates-times to instants and vice versa.
The same instant can have different local date-time values, depending on the destination time zone.

Functions and operations that require a time zone use either the configured time zone or a zone-id parameter.
Time zones are specified using _java.time.ZoneId_.

The precision of a _DATE_TIME_ is up to nanoseconds.

A _DURATION_ is a certain amount of time, like e.g. "3 hours, 15 minutes and 6 seconds".
The textual representation of a _DURATION_ value is the IS-8601 format, e.g. "P2DT3H4M" means 2 days, 3 hours and 4 minutes
The smallest amount of a duration is 1 nanosecond.

### Arithmetic operations with _DATE_TIME_ and _DURATION_.
Expand All @@ -34,7 +39,7 @@ The outcome of the operation depends on the operator types:

All other combinations of _DATE_TIME_ and _DURATION_ with other types will do a string concatenation.

Example. Adding a duration to a date-time:
Example: Adding a duration to a date-time:
```java
Instant start = Instant.parse("2023-12-03T23:15:30.00Z");
Duration duration = Duration.ofHours(3);
Expand All @@ -58,7 +63,7 @@ System.out.println(result); // will print "EvaluationValue(value=2023-12-04T02:1

All other combinations of _DATE_TIME_ and _DURATION_ with other types will throw an _EvaluationException_.

Example. Find out the duration between two date-times:
Example: Find out the duration between two date-times:
```java
Instant start = Instant.parse("2023-12-05T11:20:00.00Z");
Instant end = Instant.parse("2023-12-04T23:15:30.00Z");
Expand All @@ -71,7 +76,7 @@ EvaluationValue result = expression
System.out.println(result); // will print "EvaluationValue(value=PT12H4M30S, dataType=DURATION)"
```

The string representation of a duration is here in SO format, meaning 12 hours, 4 minutes and 30 seconds.
The string representation of a duration is here in ISO-8601 format, meaning 12 hours, 4 minutes and 30 seconds.

### Passing other Date-Time Types as variables

Expand All @@ -94,4 +99,16 @@ functions to work with date-times. Most of them allow to create, parse and forma

See Chapter [Date Time Functions](../references/functions.html#date-time-Functions)

### Configuration Changes
### Configuration Changes

There are two new configuration parameters for date-time handling.
* Date time formatters: The formatters to use when parsing or formatting date-time values.
* Zone id: The time zone id. By default, the system default zone ID is used.

See Chapter [configuration](../configuration/configuration.html)

### New Constants

There are also some new constants for common formatter patterns.

See Chapter [Standard Constants](../references/constants.html#standard-constants)
7 changes: 3 additions & 4 deletions docs/concepts/parsing_evaluation.md
Original file line number Diff line number Diff line change
Expand Up @@ -108,21 +108,20 @@ EvaluationValue result = expression.withValues(values).evaluate();
System.out.println(result.getNumberValue()); // prints 6.00
```

The data conversion of the passed values will automatically be performed through the created
_EvaluationObject_.
The data conversion of the passed values will automatically be performed through a customizable converter.

The map can also hold data of different types:
```java
Expression expression = new Expression("a+b+c");

Map<String, Object> values = new HashMap<>();
values.put("a", true);
values.put("b", " ");
values.put("b", " : ");
values.put("c", 24.7);

EvaluationValue result = expression.withValues(values).evaluate();

System.out.println(result.getStringValue()); // prints "true 24.7"
System.out.println(result.getStringValue()); // prints "true : 24.7"
```

See chapter [Data Types](datatypes.html) for details on the conversion.
Expand Down
27 changes: 27 additions & 0 deletions docs/configuration/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,18 @@ The supplier is called whenever a new Expression is created, so that each expres
instance of an accessor. Custom implementations of the supplier and data accessor may allow
expressions to share the same space.

### Date Time Formatters

The date-time formatters. When parsing, each format will be tried and the first matching will be used.
For formatting, only the first will be used.\
By default, the _ExpressionConfiguration.DEFAULT_DATE_TIME_FORMATTERS_ are used:

* _DateTimeFormatter.ISO_DATE_TIME_
* _DateTimeFormatter.ISO_DATE_
* _DateTimeFormatter.ISO_LOCAL_DATE_TIME_
* _DateTimeFormatter.ISO_LOCAL_DATE_
* _DateTimeFormatter.RFC_1123_DATE_TIME_

### Decimal Places Rounding

Specifies the amount of decimal places to round to in each operation or function.
Expand All @@ -66,6 +78,11 @@ name and _EvaluationValue_ as value. Each expression has a case-insensitive copy
constants.
See the reference chapter for a list: [Default Constants](../references/constants.html)

### Evaluation Value Converter

The converter to use when converting different data types to an _EvaluationValue_.
The _DefaultEvaluationValueConverter_ is used by default.

### Function Dictionary

The function dictionary is used to look up the functions that are used in an expression.
Expand Down Expand Up @@ -135,3 +152,13 @@ E.g. a _BigDecimal_ result of _9.0_ will become _9_ and _-2.120000_ will become
Specifies if the structure separator ('.') operator is allowed (default is true). If set to false,
the expression will throw a _ParseException_, if the a '.' is encountered in the expression and also
no operator or function is defined for this character.

### Zone Id

The time zone id. By default, the system default zone ID is used.
```java
ExpressionConfiguration configuration=ExpressionConfiguration.builder()
.zoneId(ZoneId.of("Europe/Berlin"))
.build();
```

86 changes: 69 additions & 17 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,14 @@ title: Welcome
nav_order: 1
---

# EvalEx - Java Expression Evaluator

EvalEx is a handy expression evaluator for Java, that allows to parse and evaluate expression
strings.

_Version 3 of EvalEx is a complete rewrite of the popular expression evaluator.
See [Major Changes](https://ezylang.github.io/EvalEx/concepts/changes.html) for an overview of the
changes._
EvalEx is a handy expression evaluator for Java, that allows to parse and evaluate expression strings.

## Key Features:

- Supports numerical, boolean, string, array and structure expressions, operations and variables.
- Supports numerical, boolean, string, date time, duration, array and structure expressions, operations and variables.
- Array and structure support: Arrays and structures can be mixed, building arbitrary data
structures.
- Supports the NULL datatype.
- Uses BigDecimal for numerical calculations.
- MathContext and number of decimal places can be configured, with optional automatic rounding.
- No dependencies to external libraries.
Expand All @@ -31,6 +25,11 @@ changes._
x-y)
- Lazy evaluation of function parameters (see the IF function) and support of sub-expressions.

## Documentation

The full documentation for EvalEx can be found
on [GitHub Pages](https://ezylang.github.io/EvalEx/)

## Discussion

For announcements, questions and ideas visit
Expand Down Expand Up @@ -69,7 +68,7 @@ dependencies {

## Examples

A simple example, that shows how it works in general:
### A simple example, that shows how it works in general:

```java
Expression expression = new Expression("1 + 2 / (4 * SQRT(4))");
Expand All @@ -79,8 +78,7 @@ EvaluationValue result = expression.evaluate();
System.out.println(result.getNumberValue()); // prints 1.25
```

Of course, variables can be specified in the expression and their values can be passed for
evaluation:
### Variables can be specified in the expression and their values can be passed for evaluation:

```java
Expression expression = new Expression("(a + b) * (a - b)");
Expand All @@ -93,7 +91,36 @@ EvaluationValue result = expression
System.out.println(result.getNumberValue()); // prints 6.00
```

Boolean expressions produce a boolean result:
### Values can be passed in a map

Instead of specifying the variable values one by one, they can be set by defining a map with names and values and then
passing it to the _withValues()_ method:

The data conversion of the passed values will automatically be performed through a customizable converter.

It is also possible to configure a custom data accessor to read and write values.

```java
Expression expression = new Expression("a+b+c");

Map<String, Object> values = new HashMap<>();
values.put("a", true);
values.put("b", " : ");
values.put("c", 24.7);

EvaluationValue result = expression.withValues(values).evaluate();

System.out.println(result.getStringValue()); // prints "true : 24.7"
```

See chapter [Data Types](https://ezylang.github.io/EvalEx/concepts/datatypes.html) for details on the conversion.

Another option to have EvalEx use your data is to define a custom data accessor.

See chapter [Data Access](https://ezylang.github.io/EvalEx/customization/data_access.html) for details.


### Boolean expressions produce a boolean result:

```java
Expression expression = new Expression("level > 2 || level <= 0");
Expand All @@ -105,7 +132,7 @@ EvaluationValue result = expression
System.out.println(result.getBooleanValue()); // prints true
```

Like in Java, strings and text can be mixed:
### Like in Java, strings and text can be mixed:

```java
Expression expression = new Expression("\"Hello \" + name + \", you are \" + age")
Expand All @@ -115,7 +142,10 @@ Expression expression = new Expression("\"Hello \" + name + \", you are \" + age
System.out.println(expression.evaluate().getStringValue()); // prints Hello Frank, you are 38
```

Arrays (also multidimensional) are supported and can be passed as Java _Lists_:
### Arrays (also multidimensional) are supported and can be passed as Java _Lists_.

See the [Documentation](https://ezylang.github.io/EvalEx/concepts/datatypes.html#array)
for more details.

```java
Expression expression = new Expression("values[i-1] * factors[i-1]");
Expand All @@ -129,8 +159,11 @@ EvaluationValue result = expression
System.out.println(result.getNumberValue()); // prints 4
```

Structures are supported and can be passed as Java _Maps_.
Arrays and Structures can be combined to build arbitrary data structures:
### Structures are supported and can be passed as Java _Maps_.

Arrays and Structures can be combined to build arbitrary data structures. See
the [Documentation](https://ezylang.github.io/EvalEx/concepts/datatypes.html#structure)
for more details.

```java
Map<String, Object> order = new HashMap<>();
Expand All @@ -153,6 +186,25 @@ BigDecimal result = expression.evaluate().getNumberValue();
System.out.println(result); // prints 44.85
```

### Calculating with date-time and duration

Date-tme and duration values are supported. There are functions to create, parse and format these values.
Additionally, the plus and minus operators can be used to e.g. add or subtract durations, or to calculate the
difference between two dates:

```java
Instant start = Instant.parse("2023-12-05T11:20:00.00Z");
Instant end = Instant.parse("2023-12-04T23:15:30.00Z");

Expression expression = new Expression("start - end");
EvaluationValue result = expression
.with("start", start)
.and("end", end)
.evaluate();
System.out.println(result); // will print "EvaluationValue(value=PT12H4M30S, dataType=DURATION)"
```
See the [Documentation](https://ezylang.github.io/EvalEx/concepts/date_time_duration.html) for more details.

## EvalEx-big-math

[Big-math](https://github.com/eobermuhlner/big-math) is a library by Eric Obermühlner. It provides
Expand Down
Loading

0 comments on commit b6290f9

Please sign in to comment.