Skip to content

NIFI-15658 - Add duration arithmetic Expression Language functions for Date and Instant values#10956

Open
Scrooge-McDucks wants to merge 2 commits intoapache:mainfrom
Scrooge-McDucks:NIFI-15658
Open

NIFI-15658 - Add duration arithmetic Expression Language functions for Date and Instant values#10956
Scrooge-McDucks wants to merge 2 commits intoapache:mainfrom
Scrooge-McDucks:NIFI-15658

Conversation

@Scrooge-McDucks
Copy link
Contributor

@Scrooge-McDucks Scrooge-McDucks commented Mar 3, 2026

Summary

NIFI-15658

This adds four new NiFi Expression Language functions: plusDuration, minusDuration, plusInstantDuration, and minusInstantDuration.

These functions support human-readable duration arithmetic directly on Date and Instant values. Today, users often need to convert parsed dates or timestamps through numeric or epoch-based steps to perform simple adjustments, which is harder to read and less intuitive for common use cases.

Examples:

${date:toDate('dd-MM-yyyy'):plusDuration('1 week'):format('dd-MM-yyyy')}
${date:toDate('dd-MM-yyyy'):minusDuration('3 months'):format('dd-MM-yyyy')}
${ts:toInstant('dd-MM-yyyy HH:mm:ss', 'UTC'):plusInstantDuration('1 week'):formatInstant('dd-MM-yyyy HH:mm:ss', 'UTC')}
${ts:toInstant('dd-MM-yyyy HH:mm:ss', 'UTC'):minusInstantDuration('3 months'):formatInstant('dd-MM-yyyy HH:mm:ss', 'UTC')}

The new functions accept a string argument in the form " ", such as "1 week" or "3 months". plusDuration() and minusDuration() return Date values so they can be chained with other date functions such as format(). plusInstantDuration() and minusInstantDuration() return Instant values so they can be chained with instant functions such as formatInstant().

The implementation is calendar-aware rather than based on raw millisecond arithmetic. For example, adding one month to January 31 results in February 28 or 29 depending on the year. Supported units are seconds, minutes, hours, days, weeks, months, and years. Unit matching is case-insensitive, supports singular and plural forms, and requires a space between the numeric value and the unit.

Instant arithmetic is evaluated in UTC so results are deterministic across environments. When formatting an adjusted Instant in another time zone, the displayed time may differ due to daylight saving transitions.

Null subjects continue to return null gracefully.

Tracking

Please complete the following tracking steps prior to pull request creation.

Issue Tracking

Pull Request Tracking

  • Pull Request title starts with Apache NiFi Jira issue number, such as NIFI-00000
  • Pull Request commit message starts with Apache NiFi Jira issue number, as such NIFI-00000
  • Pull request contains commits signed with a registered key indicating Verified status

Pull Request Formatting

  • Pull Request based on current revision of the main branch
  • Pull Request refers to a feature branch with one commit containing changes

Verification

Please indicate the verification steps performed prior to pull request creation.

Build

  • Build completed using ./mvnw clean install -P contrib-check
    • JDK 21
    • JDK 25

Licensing

  • New dependencies are compatible with the Apache License 2.0 according to the License Policy
  • New dependencies are documented in applicable LICENSE and NOTICE files

Documentation

  • Documentation formatting appears as expected in rendered files

Copy link
Contributor

@exceptionfactory exceptionfactory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for proposing these new functions @Scrooge-McDucks. The general concept looks helpful. On a cursory review, I recommend something along the lines of plusDuration and minusDuration, following the pattern of the action first in the name.

@Scrooge-McDucks Scrooge-McDucks changed the title NIFI-15658 - Add datePlus and dateMinus Expression Language functions NIFI-15658 - Add plusDuration and minusDuration Expression Language functions Mar 3, 2026
@Scrooge-McDucks
Copy link
Contributor Author

@exceptionfactory — Thanks for the review! The naming change makes a lot of sense. I’ve refactored the implementation to plusDuration and minusDuration. Please let me know if there’s anything I missed.

@Scrooge-McDucks Scrooge-McDucks changed the title NIFI-15658 - Add plusDuration and minusDuration Expression Language functions NIFI-15658 - Add duration arithmetic Expression Language functions for Date and Instant values Mar 4, 2026
@Scrooge-McDucks
Copy link
Contributor Author

Scrooge-McDucks commented Mar 4, 2026

I realized the same duration arithmetic logic should also be supported for Instant values, so I included the corresponding plusInstantDuration and minusInstantDuration functions as part of this update.

I also rebased the branch down to a single commit to make the pull request easier to review.

* Units are case-insensitive and accept singular/plural: second(s), minute(s), hour(s),
* day(s), week(s), month(s), year(s).</p>
*/
public final class DateAmountParser {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this class necessary for parsing the different duration expressions? There already exists the DurationFormat class in the nifi-api which does most of the durations listed here except for month and that class has nanos.

Copy link
Contributor Author

@Scrooge-McDucks Scrooge-McDucks Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call about the nanos. I can include nanoseconds as a supported unit so it aligns more closely with the Duration logic for fixed-length units.

I did now have a look at delegating to DurationFormat, but it converts everything to a fixed nanosecond count. Months and years require java.time.Period for calendar-aware arithmetic (e.g., adding 1 month to Jan 31 → Feb 28), which means we’d still need a separate path for those cases.

Happy to adjust if there’s a preferred direction here, but my thinking was that this keeps the behavior simpler.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added nanoseconds support and updated the docs. Let me know if you think it’s worth refactoring to leverage DurationFormat.

@Scrooge-McDucks Scrooge-McDucks requested a review from dan-s1 March 5, 2026 09:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants