FEEL

FEEL date and time functions: dates, durations, time zones and calendar arithmetic

FEEL guide · 12 built-in functions · DMN 1.6

Deadlines, ages, notice periods and opening hours make dates the most common source of logic in DMN decision tables, and of bugs. FEEL has four temporal types: date, time, date and time and duration. Durations come in two kinds that do not mix. This guide covers the constructors, the calendar functions and the arithmetic between them.

Each result was computed by the FEEL engine behind the evaluator at the top. Examples that depend on the current moment say so.

All FEEL date and time functions at a glance

FunctionSignatureReturns
nownow()Returns the current date and time
todaytoday()Returns the current date
day of yearday of year(date)Returns the ordinal day within the year, 1 to 366
day of weekday of week(date)Returns the English weekday name of the date
month of yearmonth of year(date)Returns the English month name of the date
week of yearweek of year(date)Returns the ISO 8601 week number of the date
last day of monthlast day of month(date)Returns the day number of the last day of the value's month (28, 29, 30 or 31), handy for billing-period and deadline logic
datedate(from) or date(year, month, day)Creates a date from an ISO 8601 string, from year/month/day components, or by truncating a date and time value
timetime(from) or time(hour, minute, second, offset?)Creates a time from an ISO 8601 string, from components, or by extracting the time of a date and time value
date and timedate and time(from) or date and time(date, time)Creates a date and time from an ISO 8601 string or by combining a date with a time
durationduration(from)Creates a days-and-time or years-and-months duration from an ISO 8601 string
years and months durationyears and months duration(from, to)Returns the duration between two dates as whole years and months, dropping smaller units

Creating dates: strict ISO 8601

date("2026-07-24"), date(2026, 7, 24) and the literal @"2026-07-24" all create the same value. The string form accepts only ISO 8601, with zero-padded months and days. A malformed or impossible date gives null, not an error, so the mistake often surfaces later as an unexpected null.

date(2026, 7, 24) = @"2026-07-24"
date("2026-7-24")

Not zero-padded.

date("2026-02-30")

There is no 30 February.

date(date and time("2026-07-24T13:00:00"))
2026-07-24 Try it ↑

Truncate a date and time to its date.

Date arithmetic and the difference between two dates

Add or subtract a duration to move a date. Subtracting two dates gives a days-and-time duration; read .days to get the difference in days.

Be careful when adding months to the 29th, 30th or 31st. DMN 1.6 defines date plus months as the same day of the month in the target month (Table 58), so 31 January plus one month would be 31 February, which does not exist, and the result is null. Engines differ here, and some move to the last day of the month instead. A model that should run unchanged on any engine avoids adding months to those days.

A date has no time of day, so adding hours only moves it once they add up to whole days.

date("2026-07-24") + duration("P1M")
2026-08-24 Try it ↑

Same day of the month, one month later.

date("2026-01-31") + duration("P1M")

31 February does not exist.

date("2026-07-24") - duration("P30D")
2026-06-24 Try it ↑
(date("2026-07-24") - date("2025-07-24")).days

The difference in days.

date("2026-07-24") + duration("PT12H")
2026-07-24 Try it ↑

Twelve hours do not change a date.

date("2026-07-24") in [date("2026-01-01")..date("2026-12-31")]

Ranges work for dates too, which helps in decision table rules.

Two kinds of duration

A days-and-time duration (P3D, PT2H30M) is an exact length of time. A years-and-months duration (P1Y, P6M) is a calendar amount: one month is 28 to 31 days depending on where you start. The two cannot be compared or added to each other. years and months duration(from, to) gives the calendar difference between two dates, which is how you compute an age.

duration("P1D") = duration("PT24H")
duration("P1M") = duration("P30D")

Different kinds: not comparable.

date("2026-03-01") - date("2026-02-01")

The difference of two dates is a days-and-time duration.

years and months duration(date("2000-03-15"), date("2026-07-24")).years

Age in whole years.

duration("PT1H") / duration("PT15M")

How many 15-minute slots fit in an hour.

Time zones

A date and time may be local (no zone), have a UTC offset (+02:00, Z), or name an IANA zone (@Europe/Zurich). Values with zone information compare by instant. When a local value is compared with a zoned one, DMN 1.6 says the local value takes the other value's offset (Table 55). Not every engine implements that rule, so keep the inputs of a decision either all local or all zoned. Subtracting a local value from a zoned one is undefined, and the result is null.

date and time("2026-07-24T14:30:00+02:00") = date and time("2026-07-24T12:30:00Z")
date and time("2026-07-24T14:30:00@Europe/Zurich").timezone
Europe/Zurich Try it ↑
date and time("2026-07-24T14:30:00") < date and time("2026-07-24T15:00:00+02:00")

The local value is read as 14:30+02:00.

Day of week, week numbers and month ends

day of week and month of year return English names, so compare them with strings such as "Saturday". For a number, use the .weekday component (1 = Monday). week of year follows ISO 8601: weeks start on Monday, and the days around New Year can belong to the neighbouring year's week.

day of week(date("2026-07-24")) = "Friday"
date("2026-07-24").weekday >= 6

A weekend test with the numeric weekday.

week of year(date("2027-01-01"))

1 January 2027 is in ISO week 53 of 2026.

week of year(date("2024-12-30"))

30 December 2024 is in week 1 of 2025.

Function reference

Each function with its examples and edge cases. The heading links to the function's own page with its parameter table.

now

now()

Returns the current date and time.

DMN 1.6 notes that now() and today() are not deterministic and recommends isolating decision logic that uses them in its own decision, so that tests can override it with a fixed value. In practice, pass the reference date in as an input variable wherever you can. The engine behind this site reads the clock once per evaluation, so every call in one expression sees the same instant.

now()
result depends on the evaluation moment Try it ↑
now() instance of date and time
now() - now()

The same instant within one evaluation.

today() = date(now())

today

today()

Returns the current date.

today()
result depends on the evaluation moment Try it ↑
today() instance of date

day of year

day of year(date)

Returns the ordinal day within the year, 1 to 366.

day of year(date("2026-07-24"))
day of year(date("2024-12-31"))

Leap year.

day of week

day of week(date)

Returns the English weekday name of the date.

day of week(date("2026-07-24"))
Friday Try it ↑
day of week(date and time("2026-07-24T23:30:00"))
Friday Try it ↑

Works on date and time values too.

day of week("2026-07-24")

A string is not a date; wrap it in date().

date("2026-07-24").weekday

The numeric alternative: 1 = Monday.

month of year

month of year(date)

Returns the English month name of the date.

month of year(date("2026-07-24"))

week of year

week of year(date)

Returns the ISO 8601 week number of the date.

week of year(date("2026-01-01"))
week of year(date("2026-07-24"))
week of year(date("2027-01-01"))
week of year(date("2024-12-30"))

last day of month

last day of month(date)

Not part of the DMN 1.6 standard: an extension supported by the engine behind this site. A model that uses it may not run on other DMN engines.

Returns the day number of the last day of the value's month (28, 29, 30 or 31), handy for billing-period and deadline logic.

last day of month(date("2026-02-10"))
last day of month(date("2024-02-10"))
last day of month(date and time("2026-04-10T10:00:00"))

date

date(from) or date(year, month, day)

Creates a date from an ISO 8601 string, from year/month/day components, or by truncating a date and time value.

The string form is strict ISO 8601, YYYY-MM-DD with zero-padded month and day. Anything else, including impossible dates such as 30 February, gives null rather than an error, so a mistyped date shows up later as a null result. The @"2026-07-24" literal is shorthand for the same thing.

date("2026-07-24")
2026-07-24 Try it ↑
date(2026, 7, 24)
2026-07-24 Try it ↑
date(date and time("2026-07-24T13:00:00"))
2026-07-24 Try it ↑
date("2026-7-24")

Month and day must be zero-padded.

date("2026-02-30")

Impossible dates give null.

date("2026-07-24T10:00:00")

A date and time string is not a date string. Wrap it: date(date and time(...)).

date(2026, 13, 1)
date(date and time("2026-07-24T10:00:00"))
2026-07-24 Try it ↑

To get the date of a date and time, convert the value, not the string.

@"2026-07-24" = date("2026-07-24")

The @ literal is the same value.

date("2026-07-24").weekday

Components: .year, .month, .day, .weekday (1 = Monday).

time

time(from) or time(hour, minute, second, offset?)

Creates a time from an ISO 8601 string, from components, or by extracting the time of a date and time value.

time("14:30:00")
14:30:00 Try it ↑
time(14, 30, 0, duration("PT1H"))
14:30:00+01:00 Try it ↑
time("14:30:00") + duration("PT10H")
00:30:00 Try it ↑

Time arithmetic wraps around midnight.

time("14:30:00") - time("08:00:00")
PT6H30M Try it ↑
time("25:00:00")

date and time

date and time(from) or date and time(date, time)

Creates a date and time from an ISO 8601 string or by combining a date with a time.

A value can be local (no zone), carry a UTC offset such as +02:00 or Z, or name an IANA zone with @. Values with an offset compare by instant. When a local value is compared with a zoned one, DMN 1.6 lets the local value take the other value's offset (Table 55). Engines do not all implement that rule, so keep the inputs of a decision either all local or all zoned.

date and time("2026-07-24T14:30:00")
2026-07-24T14:30 Try it ↑
date and time(date("2026-07-24"), time("14:30:00"))
2026-07-24T14:30 Try it ↑
date and time("2026-07-24T14:30:00+02:00") = date and time("2026-07-24T12:30:00Z")

Same instant.

date and time("2026-07-24T14:30:00@Europe/Zurich").timezone
Europe/Zurich Try it ↑
date and time("2026-07-24")
2026-07-24T00:00 Try it ↑

A plain date string becomes midnight.

duration

duration(from)

Creates a days-and-time or years-and-months duration from an ISO 8601 string.

FEEL has two duration types that do not mix. Days-and-time durations (P3D, PT2H) are exact amounts of time. Years-and-months durations (P1Y, P6M) are calendar amounts whose length depends on the month. Comparing one with the other gives null, because a month is not a fixed number of days.

Durations are normalized: PT90M becomes PT1H30M and P14M becomes P1Y2M. Weeks (P2W) are not part of the notation. The components are available as .days, .hours, .minutes, .seconds, .years and .months.

duration("P3DT4H")
P3DT4H Try it ↑
duration("P1Y6M")
date("2026-07-01") + duration("P3D")
2026-07-04 Try it ↑
duration("PT90M")
PT1H30M Try it ↑

Normalized.

duration("P14M")

Months carry over into years.

duration("-P3D")

The sign goes in front of the P.

duration("P2W")

Weeks are not accepted; write P14D. B-FEEL returns PT0S.

duration("P1D") = duration("PT24H")
duration("P1Y") = duration("P12M")
duration("P1M") = duration("P30D")

The two duration types cannot be compared.

duration("PT1H") / duration("PT15M")

Dividing durations gives a number.

duration("PT2H") * 3
duration("3 days")

Only the XML Schema duration notation is accepted.

date("2026-07-24") + duration("P" + string(5) + "D")
2026-07-29 Try it ↑

Build a duration from a number by concatenating the ISO string.

years and months duration

years and months duration(from, to)

Returns the duration between two dates as whole years and months, dropping smaller units.

years and months duration(date("2024-01-10"), date("2026-07-24"))
years and months duration(date("2000-03-15"), date("2026-07-24")).years

A common way to compute an age in whole years.

How B-FEEL differs

In standard FEEL an invalid argument makes the result null. The business-friendly B-FEEL dialect returns a type default instead. Both columns were evaluated by the same engine:

ExpressionFEELB-FEEL
day of week(null)null(empty string)
month of year(null)null(empty string)

More FEEL guides

FEEL string functions · FEEL numeric functions · FEEL list functions · Language constructs · Examples cheat sheet

Defined by the OMG DMN 1.6 specification, chapter 10.3.4 (built-in functions).