Calendar filter

Value resolver – Abstract

Purpose: Performs a check for working days against a specified Calendar based on a date or date range provided as an input value. If the check fails, an alternate date is returned, otherwise the input value is returned.

images/download/attachments/58596494/image2022-8-10_13-26-30-version-1-modificationdate-1660130790728-api-v2.png

The Calendar filter value resolver performs a check for working days based on a date or date range provided as input value (see below for details) against a Calendar specified either as Static or at runtime by a value resolver. The check is considered passed if the Calendar classifies the date or the from and to dates of a date range as a working day. Then the input value is returned. Otherwise, an alternative date for the date or date range is searched for and returned.

The Jump backwards option decides the search direction (earlier/later) for the alternative date if the input value does not pass the check for working days against the specified Calendar.

Special use case: In the context of a For each loop event action (see last example below), the Calendar filter value resolver can be used to determine, starting from a start date, a date that is a certain number of business days away from the start date.

One of the following data types is expected as input value:

  • Long ( java.lang.Long)

  • 'Date' (java.lang.Date)

  • 'Timestamp' (java.sql.Timestamp)

  • 'Date with time' (DateTime)

  • 'Date range with time' (DateRange)

Interpretation of date values without declared time zone

A Long value as input value is interpreted as milliseconds since 01.01.1970 00:00:00.000 (UTC). However, as for all input value types interpreted as a date without a time zone (Long, Timestamp, Date), the UTC time zone is not the default. Rather, the default time zone applicable in the context is considered according to the following logic:

  • If a 'Default time zone' (defaultTimeZone) is defined for the User of session (in the actual logged-in session), this will be used.

  • Otherwise, the account of the Company of session (in the actual logged-in session) and the 'Default time zone' (defaultTimeZone) defined there, if applicable, will be used.

  • Only if neither account defines a 'Default time zone' for the actual logged in session, the selection for the time zone in the operating system of the server or client will be the deciding factor:

The type of the return value always corresponds to the type of the input value.

NOTE◄ For the data types summarized as 'Date values without declared time zone' this means that the default time zone applicable in the context is taken into account by the checking and calculation logic, but does not explicitly appear in the data of the return value. The time zone used for interpretation can be decisive for which calendar day a certain input value is assigned, which formally defines only 'UTC milliseconds'. However, the return value determined depending on the comparison between the assigned calendar day and a Calendar is then again defined only in 'UTC milliseconds'.

The following case distinction is used to determine the return value:

Suitable type as input value?

Calendar defined?

'Check for working days' (see below) against the Calendar?

'Jump backwards?' option

Return value

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/error.svg Unsuitable
(e.g. XYZ or $null)

irrelevant

irrelevant

irrelevant

Input value

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/check.svg Suitable
(Data type from the list above)

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/error.svg Calendar not defined)

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/check.svg Calendar is defined

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/check.svg Check passed

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/error.svg Check not passed

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/error.svg 'Jump forwards'
(default)

Alternative date: Least possible shift of the input value (date value/range) to later,
for which the 'Check for working days' is passed.

images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/check.svg 'Jump backwards'

Alternative date: Least possible shift of the input value (date value/range) to earlier,
for which the 'Check for working days' is passed.

NOTE◄ Rules for 'Jump forward' or 'Jump backward'.

  • 'Jumping' is done with an increment of whole calendar days.

  • Times from the input value apply unchanged to the alternative date.

  • If no suitable alternative date is found when 'jumping' in the desired direction, two cases can be distinguished:

    • For individual date values this is very unlikely but potentially highly problematic (see CAUTION in the following table).

    • For a date range, the check simply terminates if necessary and returns the input value as a return value.

The following rules apply to the 'Check for working days' of the input value against the defined Calendar:

Type of input value

Checking logic

Long
or 'Date'
or 'Timestamp'
or 'Date with time'

A date value (as opposed to a 'Date range', see below) is considered a working day if the calendar day determined with respect to the applicable time zone is considered a working day according to the defined Calendar.

If necessary, definitions on different levels of the calendar model are taken into account:

  • Each Calendar primarily defines which days of the week are considered working days by default.

  • A Calendar can optionally define exceptions that explicitly qualify a particular calendar day as a 'Working day' or 'No working day'.

    • Each exception must be related by a 'factor' to the whole (factor: 1.0) or a portion (factor<1.0) of the calendar day in question.

  • A Calendar can also optionally refer to one or more 'Holiday groups' (see Holiday groups).

  • A 'Holiday group' defines exceptions of the 'No working day' type, accordingly

    • Each holiday must be related by a 'factor' to the whole calendar day (factor: 1.0) or a share (factor<1.0).

A calendar day is considered a working day if one of the following conditions is met:

  • The day of the week is considered a working day by default according to the Calendar...
    ... and the Calendar does not specify an exception of the 'No working day' type for the calendar day with 'factor' 1.0
    ... and the Calendar does not refer to any holiday group that defines a holiday with a 'factor' of 1.0 for the calendar day, which is not neutralized by an exception of the 'Working day' type in the Calendar (with any 'factor', i.e. also 0).

  • According to the Calendar, the day of the week is not considered a working day by default, and the Calendar does not specify an exception of the 'Working day' type (with any 'factor', i.e. also 0) that refers to the calendar day in question.


images/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg CAUTIONimages/s/-95e2zf/9012/8yg2g7/_/images/icons/emoticons/warning.svg Theoretically, a Calendar can be configured not to contain working days by default, so that working days are created only by exceptions of the 'Working day' type. In conjunction with the Calendar filter value resolver, there is then a risk that when 'Jump forward' or 'Jump backward' is used starting from a calendar day that is not specified as a working day, no viable alternative dates can be found.

References to improperly parameterized calendars in a calendar filter value resolver can cause infinite loops that require a server restart.

'Date range with time'

A 'Date range' is considered a working day if the calendar days for the 'From' and 'To' components, determined taking into account the time zone, are considered working days when evaluated against the defined Calendar according to the check logic described above.

IMPORTANT◄ Whether the Calendar shows working days between the 'From' and 'To' calendar days or not is irrelevant for the check!

If the check is not passed for a date range, then the date range as a whole is moved 'in parallel', i.e. an alternative date is determined while retaining the original time span between the 'From' and 'To' components.


WARNING◄ It is possible that a Calendar in the desired search direction does not contain a pair of working days (for 'From' and 'To') in the 'suitable' interval.

For example, if a calendar defines only three adjacent days of the week (say: Monday, Tuesday and Wednesday) as working days, then it is impossible to find a suitable date for a date range with a time span of 3 – 4 days.

The following diagram illustrates the problem in the example:
┌────────── +4 ──────────┐... MON - TUE - WED -(THU)-(FRI) -(SAT)-(SUN)- MON - TUE - WED - ... └────── +3 ───────┘
The Calendar filter value resolver then returns the input value unchanged.

Configuration

The Calendar filter value resolver expects a date value or date range as input value, which can be provided by concatenation or as a reference object.

The Static option (unchecked by default) refers to the configuration for the required Calendar parameter.

If the option is checked (see image), a dropdown box appears, which supports a static single selection for a Calendar. All calendars for which read access exists in the context of the configuration appear in the dropdown.

At runtime, there is always access to the selected calendar. An already selected calendar for which there is no read access in the current configuration session appears with the label 'Hidden calendar'.

As shown in the image, a search function supports the selection of the calendar based on the properties contained in the label (in the example: Name '24-1 (MON)').

images/download/attachments/58596494/image2022-8-10_13-30-44-version-1-modificationdate-1660131044377-api-v2.png

If the Static option is unchecked, then a value resolver must be configured for the Calendar parameter. As return value for the value resolver either a Calendar object (Calendar) is expected (see image below right) or a Long value (see image right), which specifies the ID (id) of a Calendar object.

In the upper right image, the statically defined Long value 451 references the Calendar '24-1 (MON)' from the example above.

In the image on the bottom right, a Variable value resolver is used to read a variable that must return an object of Type 'Calendar' (Calendar) at runtime. This variable could be filled with a Search (Event action), for example.

NOTE

  • The reference via the Long value, in contrast to the static selection (above), is not suitable for transferring configurations via Meta exchange between systems in which corresponding calendars do not necessarily use the same IDs. Only with a static selection (above) deviating IDs are automatically adjusted during an Import job.

  • A Calendar reference via the Long value also does not prevent the Calendar from being deleted. As long as a static selection (see above) exists, the selected Calendar cannot be deleted.

  • If the reference by ID (Long value) or another value resolver does not return a Calendar object at runtime, then the Calendar filter returns the input value directly, i.e. unchecked and without triggering an error message or a warning. The fact that the check has failed cannot be established in this case (see table for case distinction above).

images/download/attachments/58596494/image2022-8-10_13-31-26-version-1-modificationdate-1660131086509-api-v2.png

images/download/attachments/58596494/image2022-8-10_13-32-26-version-1-modificationdate-1660131146506-api-v2.png

The option Jump backwards is unchecked by default. Then the calendar (or along a theoretical 'time axis') is 'jumped forward' if the input value does not pass the 'Check for working day' (see above).

If the option Jump backwards is checked, then the system searches for replacement dates that are earlier than the input value, if necessary.

  • In the example on the right, a Calendar '24-3 (MON_WED)' is specified that defines only Monday, Tuesday and Wednesday as working days. Input values concerning times between Thursday and Sunday are 'reverted back' to the previous Wednesday with the configuration shown, while keeping the same time.

images/download/attachments/58596494/image2022-8-10_13-33-29-version-1-modificationdate-1660131209240-api-v2.png

Examples

Simple date calculation taking into account working days

In the context of an event handling, the estimated time of arrival ('ETA') of a shipment is calculated as the 'Date with time'.

Since the incoming goods are considered to be available immediately (or on the same calendar day) only if they are received on a working day, the calculated 'ETA' date is compared with an existing Calendar to determine a further date ('AVAIL') for the effective availability of the goods at the consignee's address.

The user should be informed about the calendar days for 'ETA' and 'AVAIL' by a Show alert (Popup) event action.

Runtime example:

images/download/attachments/58596494/image2022-8-9_15-38-57-version-1-modificationdate-1660052337309-api-v2.png

  • If the shipment arrives on Saturday, 1 October (2022), the delivered goods will be considered available only from Tuesday, 4 October, since the Calendar used for the check takes into account not only the weekend (Saturday/Sunday) but also a holiday on Monday 3 October.

Configuration:

For the configuration on the right, the already calculated 'ETA' date (as 'Date with time') is valid as a reference object within an Execute with event action (not shown in the image).

NOTE◄ The availability date is only displayed here as a calendar day without time components and is not otherwise processed or stored. In this respect, it does not matter that a time contained in the calculated 'ETA' date may pass to the 'AVAIL' date. The following example deals with this problem.

images/download/attachments/58596494/image2022-8-10_13-36-13-version-1-modificationdate-1660131373910-api-v2.png

Date calculation with conditional adjustment of the time (only when 'jumping forward' to the following working day)

The previous example is now extended so that on the one hand the time calculated in the 'ETA' date appears in the message to the exact minute.

On the other hand, when 'jumping forward' – i.e. when the 'ETA' date falls on a calendar day that is not a working day – the time for the availability date ('AVAIL') is statically set to the time 07:30 (on the following working day). If the 'ETA' directly matches a working day, the goods are considered 'immediately' available.

Runtime example:

images/download/attachments/58596494/image2022-8-9_16-40-49-version-1-modificationdate-1660056049474-api-v2.png

  • When the shipment arrives on the same weekend as in the previous example, the goods are considered available from the following working day (here: Tuesday, 4 October) at 07:30.

Configuration:

  • Before the Show alert (Popup) event action, a case distinction is inserted per an If then else event action, which compares in an Entity property rule whether the Calendar filter value resolver (settings see above) returns a value deviating from the 'ETA' date (reference object). The original value In any case, the return value from the Calendar filter value resolver is stored in the avail variable via the concatenated Store value as variable value resolver.

  • If the Calendar filter returns a return value that differs from its input value, then the return value is post-processed in the avail variable in the 'Then' branch. A Set value event action overwrites the 'ETA' time in the return value from the Calendar filter with the statically specified time (7:30). This is enabled by the Relative date with time value resolver with the Type 'Custom' and the following Custom time:
    7H 30m 0s 0S.

  • In the subsequent Show alert (Popup) event action, only the avail variable must be accessed instead of the Calendar filter (see above) to define the availability date in the Message.

images/download/attachments/58596494/image2022-8-10_13-45-5-version-1-modificationdate-1660131905221-api-v2.png

Appointment determination against a 'dynamically' selected calendar at runtime

In the context of event handling, it is determined up to which date in the current month partial loads can still be ordered via the freight forwarder already selected for the specific order. For this reason, a Calendar with the uniform name 'LTL' has been created for each freight forwarder for the coordination of appointments, which represents recurring and discreetly defined appointment options for the processing of partial loads as 'working days'.

Configuration:

The event handling must first determine the calendar matching the selected freight forwarder in the context of the relevant order. This allows a Search (Event action) to be executed within a Run as event action to ensure read access for the calendars created in the possession of the various freight forwarders. The Search (Event action) will not be described in detail here. It is intended as a tuple search to find the first (and by convention: only) Calendar owned by a particular freight forwarder whose name is 'LTL'. As a projection, only the id field is needed for the Calendar filter. The result of the tuple search is written to the variable LTL@FWD.

  • On the right side of the Set value event action, the 'End of month' (END_THIS_MONTH) is first determined via the Relative date with time value resolver. This 'Date with time' is passed as an input value to a Calendar filter value resolver via concatenation.

  • In the Calendar filter value resolver, the Calendar determined for the relevant freight forwarder is referenced for the 'check for working days' by assigning the Object property id from the search result in the LTL@FWD variable to the Calendar parameter.

  • The Jump backwards option ensures that the LTL_ultimate variable (on the left side of the Setze Wer event action) returns the latest calendar day defined as a working day in the freight forwarder's calendar, which is before the end of the current month.

NOTE◄ The fact that the LTL_ultimate date is already in the past at the time of the request is not dealt with separately here.

images/download/attachments/58596494/image2022-8-10_13-48-1-version-1-modificationdate-1660132081379-api-v2.png

Runtime example:

According to its 'LTL' calendar, a freight forwarder offers transports for partial loads only on Thursdays as a rule. A query for the LTL_ultimate date in August 2022 results in the value shown to the right, which refers to the calendar day 'Thursday, 25 August 2022'.

NOTE◄ The millisecond value in the dateValue field in the image on the right shows that the time (23:59:59.999) from the input value ('end of the month') is also reflected in the return value of the calendar filter.

Section from the 'Storage' with variable values in a test run
<entry>
<key xsi:type="xsd:string">LTL_ultimate</key>
<value dateValue="1661464799999" timeZone="Europe/Berlin" xsi:type="core:DateTime"/>
</entry>

Appointment offset by a predefined number of working days

A target date (end) is determined from a given date – here as a 'Date with time' value in the variable start – by comparing it with a specific Calendar. The target date is a specific number of working days (offset) after the start date.

Configuration:

Within an event action, the For each loop shown on the right iterates over the offset variable, which defines the number of business days from start as an integer:

  • The Set value event action within the loop should assign the 'next' business day to the end variable at each iteration.

  • The enables (on the right in the picture) a concatenation of the following value resolvers:

    • The previous value of the end variable serves as the initial value for the concatenation for each iteration.

    • In the first iteration, end (hopefully!) does not yet contain a value. Then the concatenated default value resolver assigns the actual Default value from the start variable.

    • The following Relative date with time value resolver adds exactly one calendar day to the input value with the Type 'Custom' and the Custom time value +1d.

    • The concatenated Calendar filter value resolver checks whether the calendar day present as input value in the Static selected Calendar '24-5 (MON_FRI)' is a working day.

      • If this is true, this value is returned.

      • Otherwise, 'Jump forward' will determine the next working day in the calendar and return it.

At the end there should be exactly as many working days (according to the selected Calendar) difference between start and end as specified in the offset variable.

NOTE◄ The configuration shown here assumes that the value of the offset>0 variable and the end variable does not contain a value ($null) at the beginning.

images/download/attachments/58596494/image2022-8-10_13-50-31-version-1-modificationdate-1660132231462-api-v2.png