Skip to main content

Filter by Date and Time

Filter by an explicit date

  • To filter by an explicit date-time value, compare the date field directly with a DateTime value.

  • Use UTC values to avoid time-zone-related issues. RavenDB stores and compares date-time values in UTC.
    In the C# examples below, DateTimeKind is passed to the DateTime constructor to mark the value as UTC.

  • Unlike the Restrictions on now() and today(),
    explicit date values are deterministic and can be used in Exploration queries and Subscription queries.


Filter by single date

The following query returns all employees hired on or after January 1st, 1995 (UTC):

var cutoff = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);

List<Employee> employees = session
.Query<Employee>()
.Where(e => e.HiredAt >= cutoff)
.ToList();

Filter by date range

You can filter by a date range by combining two predicates.
The following query returns all employees hired between 1995-01-01 (inclusive) and 2010-01-01 (exclusive):

var from = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var to = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc);

List<Employee> employees = session
.Query<Employee>()
.Where(e => e.HiredAt >= from && e.HiredAt < to)
.ToList();

Filter by date range using between

When both bounds are inclusive, RQL offers a dedicated between operator,
equivalent to field >= from AND field <= to.

The following query returns all employees hired between January 1st, 1995 and January 1st, 2010, inclusive:

// LINQ has no dedicated Between method - 
// the query translator emits the 'between' operator in the generated RQL
// when both bounds are inclusive.
var from = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
var to = new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc);

List<Employee> employees = session
.Query<Employee>()
.Where(e => e.HiredAt >= from && e.HiredAt <= to)
.ToList();

Filter using now()

  • RQL provides the now() function for comparing date fields with the current UTC date-time.
    In RQL, the function name is case-insensitive. For example, now() and NOW() are equivalent.

  • now() is evaluated server-side when the query is executed, so the value reflects the server clock, not the client clock. Use now() when you need to compare a date field with the current UTC date-time when the query runs.

  • For example, the following query returns employees whose HiredAt date is before the current server time:


    List<Employee> employees = session
    .Query<Employee>()
    .Where(e => e.HiredAt < RavenQuery.Now())
    .ToList();
  • All comparison operators are supported (=, !=, <, <=, >, >=).
    For example, the following query returns orders whose RequireAt date is after the current server time:

    List<Order> orders = session
    .Query<Order>()
    .Where(o => o.RequireAt > RavenQuery.Now())
    .ToList();
  • You can also combine now() with other predicates.
    For example, query for employees named Alice who were hired on or before the current server time:

    List<Employee> aliceHired = session
    .Query<Employee>()
    .Where(e => e.HiredAt <= RavenQuery.Now() && e.FirstName == "Alice")
    .ToList();

Filter using now() with offset

  • now() can accept an optional positive or negative offset string, such as +7d, -3d, or +1d5h.

  • When an offset is provided, RavenDB first SHIFTS the current time by the specified amount
    and then ROUNDS the generated time value down to the start of the smallest unit in the offset.

  • This keeps the generated time value stable for the duration of the smallest unit in the offset,
    allowing identical queries to benefit from the server query cache and return 304 Not Modified when applicable. Learn more about caching in: Result caching with time functions.


Negative offset (past)

  • Use a negative offset to compare a date field with a time value in the past.

  • For example:
    now('-7d') subtracts 7 days from the current server time and then rounds the generated time value down to the start of that UTC day. The generated timestamp is truncated to 00:00:00.000 UTC, discarding the hour, minute, second, and millisecond components.

    If the server’s current UTC time is 2026-05-10T14:37:22Z, then now('-7d') is evaluated as follows:

    Shift: 2026-05-10T14:37:22Z - 7 days => 2026-05-03T14:37:22Z
    Round down to the day: 2026-05-03T14:37:22Z => 2026-05-03T00:00:00Z
    So this predicate: HiredAt <= now('-7d')
    effectively becomes: HiredAt <= 2026-05-03T00:00:00Z

  • The following query returns employees whose HiredAt value is earlier than or equal to 7 days ago,
    rounded down to the day:

    List<Employee> employees = session.Query<Employee>()
    .Where(e => e.HiredAt <= RavenQuery.Now("-7d"))
    .ToList();

Positive offset (future)

  • Use a positive offset to compare a date field with a time value in the future.

  • For example:
    now('+7d') adds 7 days to the current server time and then rounds the generated time value down to the start of that UTC day. The generated timestamp is truncated to 00:00:00.000 UTC, discarding the hour, minute, second, and millisecond components.

    If the server's current UTC time is 2026-05-10T14:37:22Z, then now('+7d') is evaluated as follows:

    Shift: 2026-05-10T14:37:22Z + 7 days => 2026-05-17T14:37:22Z
    Round down to the day: 2026-05-17T14:37:22Z => 2026-05-17T00:00:00Z
    So this predicate: RequireAt <= now('+7d')
    effectively becomes: RequireAt <= 2026-05-17T00:00:00Z

  • The following query returns orders whose RequireAt value is earlier than or equal to 7 days from now,
    rounded down to the day:

List<Order> orders = session.Query<Order>()
.Where(o => o.RequireAt <= RavenQuery.Now("+7d"))
.ToList();

Offset format

  • The offset is a signed sequence of <number><unit> tokens.
    Whitespace is allowed after the sign and between tokens.
    Unit names are case-insensitive.

    UnitShort formAliases
    Yearsyyear, years
    Monthsmomonth, months
    Daysdday, days
    Hourshhour, hours
    Minutesmmin, minute, minutes
    Secondsssec, second, seconds
  • Rules:

    • The sign (+ or -) is optional. When no sign is specified, the offset is treated as positive.
    • Units must appear in strictly descending order:
      years → months → days → hours → minutes → seconds. For example, '+5h1d' is rejected.
    • A unit may not appear more than once.
    • The smallest unit present determines the rounding precision.
    • An empty offset string, such as now(''), is rejected.
  • Examples:

    OffsetEffect
    +7dAdd 7 days, then round down to the start of the day.
    -3dSubtract 3 days, then round down to the start of the day.
    +1d5hAdd 1 day and 5 hours, then round down to the start of the hour.
    7y0sAdd 7 years, then round down to the start of the second.
    0hDo not shift the time, but round down to the start of the hour.
    +1 year 6 monthsAdd 1 year and 6 months, then round down to the start of the month. (whitespace allowed).
    1Y2MO3D4H5M6SAdd all specified units; unit names are case-insensitive.

Filter using today()

  • RQL provides the today() function for comparing date fields with the start of the current UTC day, (00:00:00.000).
    In RQL, the function name is case-insensitive. For example, today() and TODAY() are equivalent.

  • today() is evaluated server-side when the query is executed, so the value reflects the server clock, not the client clock. Use today() when you need to compare a date field with the start of the current UTC day, rather than with the current date and time.

  • today() does not accept any arguments. To filter relative to another day, use now() with offset instead.
    For example, use now('+1d') to compare with the start of tomorrow’s UTC day.

  • The following query returns employees whose HiredAt value is earlier than the start of the current UTC day:

    List<Employee> employees = session
    .Query<Employee>()
    .Where(e => e.HiredAt < RavenQuery.Today())
    .ToList();
  • today() and now() can be combined in the same query.
    For example, to return all employees hired so far today:

    from Employees
    where HiredAt >= today() and HiredAt <= now()

Restrictions

  • Exploration queries
    Both now() and today() are not supported in exploration queryies.
    For example, the following query is not allowed:

    // Not allowed: now() / today() are not supported in exploration query filter clauses
    from Employees
    filter HiredAt <= now()

    In exploration queries, these functions are blocked in filter clauses because filter expressions are evaluated as JavaScript expressions. Since now() and today() depend on the query execution time, using them in this context produces time-dependent results that conflict with the query result caching mechanism.

    Filtering by an explicit date is fully supported in exploration queries.


  • Subscription queries
    Both now() and today() are not supported in subscription queries.
    For example, the following query is not allowed:

    // Not allowed: now() / today() are not supported in subscription queries   
    from Employees
    where HiredAt <= now()

    In subscription queries, these functions are blocked because a subscription is an ongoing task. Using now() or today() would make the matching results depend on when the subscription task evaluates each document,
    yielding nondeterministic results: the set of matching documents could change dynamically even when the documents themselves have not changed.

    Filtering by an explicit date is fully supported in subscription queries.


  • today() does not accept arguments
    To filter relative to another day, use now() with an offset instead, for example now('+1d').

  • Invalid now() offset values
    When using now() with an offset, the offset must be a non-empty string in a valid offset format.

Result caching with time functions

When query caching is enabled, the server can return 304 Not Modified for time-based queries only while the resolved time value remains unchanged and no documents in the queried collection have been added, modified, or deleted in the meantime.

  • today()
    today() resolves to the start of the current UTC day (00:00:00).
    Because this value remains the same throughout the UTC day, repeated queries can receive 304 Not Modified from the server (provided no documents in the queried collection have changed in the meantime).
    When the UTC day changes, today() resolves to a new value and the query is re-evaluated.

  • now() without an offset
    now() without an offset resolves to the current UTC date and time each time the query is executed.
    Because the value changes on every call, the server re-evaluates the query and does not return 304 Not Modified.

  • now() with a literal offset string
    now() with a literal offset string is rounded down to the smallest time unit specified in the offset
    (e.g. '+7d' rounds to the day, '+1h30m' rounds to the minute).
    Repeated queries can receive 304 Not Modified from the server until the rounded value changes
    (and as long as the queried collection has not changed).

    Note:
    When the offset is supplied as a query parameter (e.g. now($offset)) instead of a literal string (now('-7d')),
    the server can't tell from the query text alone what value now() will resolve to - it can't evaluate the parameter at query-planning time, and the value could be different on the next call. It therefore behaves like now() without an offset: the query is re-run every time, and 304 Not Modified is never returned.

    Parameterized offsets are only reachable through raw RQL,
    e.g. via session.Advanced.RawQuery / AsyncRawQuery combined with AddParameter.

Client-side caching must be enabled

  • The behavior described above relies on the client's HTTP response cache to recognize the server's
    304 Not Modified reply and serve the previous result from memory.

  • If client-side caching is disabled, the client does not store responses and does not send the cache-validation header (If-None-Match). The server therefore cannot reply with 304 Not Modified, and every call returns a full 200 OK response, even when today() or now('<offset>') resolved to the same value.

  • Client-side caching can be disabled at different scopes:

Aggressive caching bypasses server re-evaluation

  • When the request runs inside an Aggressive caching scope,
    the client can return the previously cached response without contacting the server at all, as long as:

    • the cached entry is younger than the duration passed to AggressivelyCacheFor(...),
    • the query does not use WaitForNonStaleResults and was not issued with NoCaching(), and
    • in AggressiveCacheMode.TrackChanges (the default), the client's background database-changes notification has not flagged the cached entry as possibly modified.
  • As a consequence, now() and today() queries can return stale results inside an aggressive caching block.
    The server-side non-determinism for now() and the daily ETag rollover for today() that normally trigger a fresh evaluation are irrelevant once the client decides to skip the round-trip. In particular, a today() query cached just before midnight UTC can keep returning the previous day's result even after the UTC day has changed.
    The cached response is refreshed only when:

    • the cache entry's age exceeds the duration passed to AggressivelyCacheFor(...)
      or the store-level AggressiveCache.Duration default,
    • a database change is observed via the Changes API
      (only when running in AggressiveCacheMode.TrackChanges, which is the default), or
    • the aggressive-caching scope is exited.
  • If you need now() or today() to be re-evaluated on every call,
    run the query outside the aggressive caching scope, or wrap the call in store.DisableAggressiveCaching().


Assuming the request reaches the server and client-side HTTP caching is enabled,
the following table summarizes regular query caching behavior:

ExpressionResolves toCan the server return 304?Valid until
today()Start of the current UTC day (00:00:00)✅ yesUntil UTC day rolls over or the queried collection changes.
now()
(no offset)
Current UTC date and time❌ non/a
Re-evaluated on every call.
now('<offset>')
(literal string offset)
now + offset
Floored to the smallest unit in the offset.
('+7d' → day, '+1h30m' → minute, '+15s' → second)
✅ yesFloored value changes or the queried collection changes.
now($param)
(parameter offset)
now + offset
Treated as non-deterministic.
❌ non/a
Re-evaluated on every call.

Syntax

// Inside a System.Linq.Expressions.Expression<Func<T, bool>>:
RavenQuery.Now() // current server UTC time
RavenQuery.Now(string offset) // current server UTC time + offset, rounded
RavenQuery.Today() // start of current UTC day
RavenDocumentQuery.Now()
RavenDocumentQuery.Now(string offset)
RavenDocumentQuery.Today()
now()
now('<offset>')
today()
ParameterTypeDescription
offsetstring(optional, now() only)
Signed time-shift expression (e.g. '+7d', '-1d5h').
Sets the rounding unit.

In this article