diff --git a/docs/querying/filtering-query-results/_category_.json b/docs/querying/filtering-query-results/_category_.json
new file mode 100644
index 0000000000..e789d38f90
--- /dev/null
+++ b/docs/querying/filtering-query-results/_category_.json
@@ -0,0 +1,4 @@
+{
+ "position": 5,
+ "label": "Filtering Query Results"
+}
diff --git a/docs/querying/filtering-query-results/content/_filter-by-date-and-time-csharp.mdx b/docs/querying/filtering-query-results/content/_filter-by-date-and-time-csharp.mdx
new file mode 100644
index 0000000000..9c706bdb39
--- /dev/null
+++ b/docs/querying/filtering-query-results/content/_filter-by-date-and-time-csharp.mdx
@@ -0,0 +1,982 @@
+import Admonition from '@theme/Admonition';
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import CodeBlock from '@theme/CodeBlock';
+import ContentFrame from '@site/src/components/ContentFrame';
+import Panel from '@site/src/components/Panel';
+
+
+
+* You can filter query results by date and time in one of the following ways:
+ * An explicit date
+ * The current UTC date-time, using [now()](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-using-now), with or without an offset
+ * The start of the current UTC day, using [today()](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-using-today)
+
+* The `now()` and `today()` functions are evaluated **server-side** when the query is executed.
+
+* In this article:
+ * [Filter by an explicit date](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-by-an-explicit-date)
+ * [Filter by single date](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-by-single-date)
+ * [Filter by date range](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-by-date-range)
+ * [Filter by date range using `between`](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-by-date-range-using-between)
+ * [Filter using `now()`](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-using-now)
+ * [Filter using `now()` with offset](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-using-now-with-offset)
+ * [Negative offset (past)](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#negative-offset-past)
+ * [Positive offset (future)](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#positive-offset-future)
+ * [Offset format](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#offset-format)
+ * [Filter using `today()`](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-using-today)
+ * [Restrictions](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#restrictions)
+ * [Result caching with time functions](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#result-caching-with-time-functions)
+ * [Syntax](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#syntax)
+
+
+
+
+
+* 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](https://learn.microsoft.com/dotnet/api/system.datetimekind) is passed to the `DateTime` constructor to mark the value as UTC.
+
+* Unlike the [Restrictions](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#restrictions) on `now()` and `today()`,
+ explicit date values are deterministic and **can be used** in [Exploration queries](../../../indexes/querying/exploration-queries.mdx) and [Subscription queries](../../../client-api/data-subscriptions/creation/examples.mdx).
+
+---
+
+### Filter by single date
+
+The following query returns all employees hired on or after January 1st, 1995 (UTC):
+
+
+
+```csharp
+var cutoff = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+List employees = session
+ .Query()
+ .Where(e => e.HiredAt >= cutoff)
+ .ToList();
+```
+
+
+```csharp
+var cutoff = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+List employees = await asyncSession
+ .Query()
+ .Where(e => e.HiredAt >= cutoff)
+ .ToListAsync();
+```
+
+
+```csharp
+var cutoff = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+List employees = session.Advanced
+ .DocumentQuery()
+ .WhereGreaterThanOrEqual("HiredAt", cutoff)
+ .ToList();
+```
+
+
+```csharp
+var cutoff = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+List employees = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereGreaterThanOrEqual("HiredAt", cutoff)
+ .ToListAsync();
+```
+
+
+```csharp
+var cutoff = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+List employees = session.Advanced
+ .RawQuery("from Employees where HiredAt >= $cutoff")
+ .AddParameter("cutoff", new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .ToList();
+```
+
+
+```csharp
+var cutoff = new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+
+List employees = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt >= $cutoff")
+ .AddParameter("cutoff", new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .ToListAsync();
+```
+
+
+```sql
+from Employees
+where HiredAt >= "1995-01-01T00:00:00.0000000Z"
+```
+
+
+
+---
+
+### 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**):
+
+
+
+```csharp
+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 employees = session
+ .Query()
+ .Where(e => e.HiredAt >= from && e.HiredAt < to)
+ .ToList();
+```
+
+
+```csharp
+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 employees = await asyncSession
+ .Query()
+ .Where(e => e.HiredAt >= from && e.HiredAt < to)
+ .ToListAsync();
+```
+
+
+```csharp
+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 employees = session.Advanced
+ .DocumentQuery()
+ .WhereGreaterThanOrEqual("HiredAt", from)
+ .AndAlso()
+ .WhereLessThan("HiredAt", to)
+ .ToList();
+```
+
+
+```csharp
+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 employees = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereGreaterThanOrEqual("HiredAt", from)
+ .AndAlso()
+ .WhereLessThan("HiredAt", to)
+ .ToListAsync();
+```
+
+
+```csharp
+List employees = session.Advanced
+ .RawQuery("from Employees where HiredAt >= $from and HiredAt < $to")
+ .AddParameter("from", new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .AddParameter("to", new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .ToList();
+```
+
+
+```csharp
+List employees = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt >= $from and HiredAt < $to")
+ .AddParameter("from", new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .AddParameter("to", new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .ToListAsync();
+```
+
+
+```sql
+from Employees
+where HiredAt >= "1995-01-01T00:00:00.0000000Z"
+ and HiredAt < "2010-01-01T00:00:00.0000000Z"
+```
+
+
+
+---
+
+### 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**:
+
+
+
+```csharp
+// 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 employees = session
+ .Query()
+ .Where(e => e.HiredAt >= from && e.HiredAt <= to)
+ .ToList();
+```
+
+
+```csharp
+// LINQ has no dedicated Between method — the query translator emits
+// RQL 'between' 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 employees = await asyncSession
+ .Query()
+ .Where(e => e.HiredAt >= from && e.HiredAt <= to)
+ .ToListAsync();
+```
+
+
+```csharp
+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 employees = session.Advanced
+ .DocumentQuery()
+ .WhereBetween("HiredAt", from, to)
+ .ToList();
+```
+
+
+```csharp
+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 employees = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereBetween("HiredAt", from, to)
+ .ToListAsync();
+```
+
+
+```csharp
+List employees = session.Advanced
+ .RawQuery("from Employees where HiredAt between $from and $to")
+ .AddParameter("from", new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .AddParameter("to", new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .ToList();
+```
+
+
+```csharp
+List employees = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt between $from and $to")
+ .AddParameter("from", new DateTime(1995, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .AddParameter("to", new DateTime(2010, 1, 1, 0, 0, 0, DateTimeKind.Utc))
+ .ToListAsync();
+```
+
+
+```sql
+from Employees
+where HiredAt between "1995-01-01T00:00:00.0000000Z"
+ and "2010-01-01T00:00:00.0000000Z"
+```
+
+
+
+
+
+
+
+* 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:
+
+
+
+ ```csharp
+
+ List employees = session
+ .Query()
+ .Where(e => e.HiredAt < RavenQuery.Now())
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession
+ .Query()
+ .Where(e => e.HiredAt < RavenQuery.Now())
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List employees = session.Advanced
+ .DocumentQuery()
+ .WhereLessThan("HiredAt", RavenDocumentQuery.Now())
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereLessThan("HiredAt", RavenDocumentQuery.Now())
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List employees = session.Advanced
+ .RawQuery("from Employees where HiredAt <= now()")
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt < now()")
+ .ToListAsync();
+ ```
+
+
+ ```sql
+ from Employees
+ where HiredAt < now()
+ ```
+
+
+
+* All comparison operators are supported (`=`, `!=`, `<`, `<=`, `>`, `>=`).
+ For example, the following query returns orders whose _RequireAt_ date is **after** the current server time:
+
+
+
+ ```csharp
+ List orders = session
+ .Query()
+ .Where(o => o.RequireAt > RavenQuery.Now())
+ .ToList();
+ ```
+
+
+ ```csharp
+ List orders = await asyncSession
+ .Query()
+ .Where(o => o.RequireAt > RavenQuery.Now())
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List orders = session.Advanced
+ .DocumentQuery()
+ .WhereGreaterThan("RequireAt", RavenDocumentQuery.Now())
+ .ToList();
+ ```
+
+
+ ```csharp
+ List orders = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereGreaterThan("RequireAt", RavenDocumentQuery.Now())
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List orders = session.Advanced
+ .RawQuery("from Orders where RequireAt > now()")
+ .ToList();
+ ```
+
+
+ ```csharp
+ List orders = await asyncSession.Advanced
+ .AsyncRawQuery("from Orders where RequireAt > now()")
+ .ToListAsync();
+ ```
+
+
+ ```sql
+ from Orders
+ where RequireAt > now()
+ ```
+
+
+
+* 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:
+
+
+
+ ```csharp
+ List aliceHired = session
+ .Query()
+ .Where(e => e.HiredAt <= RavenQuery.Now() && e.FirstName == "Alice")
+ .ToList();
+ ```
+
+
+ ```csharp
+ List aliceHired = await asyncSession
+ .Query()
+ .Where(e => e.HiredAt <= RavenQuery.Now() && e.FirstName == "Alice")
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List aliceHired = session.Advanced
+ .DocumentQuery()
+ .WhereLessThanOrEqual("HiredAt", RavenDocumentQuery.Now())
+ .AndAlso()
+ .WhereEquals("FirstName", "Alice")
+ .ToList();
+ ```
+
+
+ ```csharp
+ List aliceHired = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereLessThanOrEqual("HiredAt", RavenDocumentQuery.Now())
+ .AndAlso()
+ .WhereEquals("FirstName", "Alice")
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List aliceHired = session.Advanced
+ .RawQuery("from Employees where HiredAt <= now() and FirstName = 'Alice'")
+ .ToList();
+ ```
+
+
+ ```csharp
+ List aliceHired = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt <= now() and FirstName = 'Alice'")
+ .ToListAsync();
+ ```
+
+
+ ```sql
+ from Employees
+ where HiredAt <= now() and FirstName = 'Alice'
+ ```
+
+
+
+
+
+
+
+
+
+ * `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](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#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:
+
+
+
+ ```csharp
+ List employees = session.Query()
+ .Where(e => e.HiredAt <= RavenQuery.Now("-7d"))
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession.Query()
+ .Where(e => e.HiredAt <= RavenQuery.Now("-7d"))
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List employees = session.Advanced
+ .DocumentQuery()
+ .WhereLessThanOrEqual("HiredAt", RavenDocumentQuery.Now("-7d"))
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereLessThanOrEqual("HiredAt", RavenDocumentQuery.Now("-7d"))
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ // Using raw RQL - the offset string is passed directly to now()
+ List employees = session.Advanced
+ .RawQuery("from Employees where HiredAt <= now('-7d')")
+ .ToList();
+
+ // Using parameter - the offset string is supplied via AddParameter().
+ // Note: with a parameter, repeated calls won't return 304 Not Modified.
+ List employeesParam = session.Advanced
+ .RawQuery("from Employees where HiredAt <= now($offset)")
+ .AddParameter("offset", "-7d")
+ .ToList();
+ ```
+
+
+ ```csharp
+ // Using raw RQL - the offset string is passed directly to now()
+ List employees = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt <= now('-7d')")
+ .ToListAsync();
+
+ // Using parameter - the offset string is supplied via AddParameter().
+ // Note: with a parameter, repeated calls won't return 304 Not Modified.
+ List employeesParam = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt <= now($offset)")
+ .AddParameter("offset", "-7d")
+ .ToListAsync();
+ ```
+
+
+ ```sql
+ // Offset string is passed as a literal string:
+ from Employees
+ where HiredAt <= now('-7d')
+
+ // Offset string is passed as a parameter:
+ // Note: with a parameter, repeated calls won't return 304 Not Modified.
+ from Employees
+ where HiredAt <= now($offset)
+ { "offset": "-7d" }
+ ```
+
+
+
+---
+
+### 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:
+
+
+
+```csharp
+List orders = session.Query()
+ .Where(o => o.RequireAt <= RavenQuery.Now("+7d"))
+ .ToList();
+```
+
+
+```csharp
+List orders = await asyncSession.Query()
+ .Where(o => o.RequireAt <= RavenQuery.Now("+7d"))
+ .ToListAsync();
+```
+
+
+```csharp
+List orders = session.Advanced
+ .DocumentQuery()
+ .WhereLessThanOrEqual("RequireAt", RavenDocumentQuery.Now("+7d"))
+ .ToList();
+```
+
+
+```csharp
+List orders = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereLessThanOrEqual("RequireAt", RavenDocumentQuery.Now("+7d"))
+ .ToListAsync();
+```
+
+
+```csharp
+// Using raw RQL - the offset string is passed directly to now()
+List orders = session.Advanced
+ .RawQuery("from Orders where RequireAt <= now('+7d')")
+ .ToList();
+
+// Using parameter - the offset string is supplied via AddParameter().
+// Note: with a parameter, repeated calls won't return 304 Not Modified.
+List ordersParam = session.Advanced
+ .RawQuery("from Orders where RequireAt <= now($offset)")
+ .AddParameter("offset", "+7d")
+ .ToList();
+```
+
+
+```csharp
+// Using raw RQL - the offset string is passed directly to now()
+List orders = await asyncSession.Advanced
+ .AsyncRawQuery("from Orders where RequireAt <= now('+7d')")
+ .ToListAsync();
+
+// Using parameter - the offset string is supplied via AddParameter().
+// Note: with a parameter, repeated calls won't return 304 Not Modified.
+List ordersParam = await asyncSession.Advanced
+ .AsyncRawQuery("from Orders where RequireAt <= now($offset)")
+ .AddParameter("offset", "+7d")
+ .ToListAsync();
+```
+
+
+```sql
+// Offset string is passed as a literal string:
+from Orders
+where RequireAt <= now('+7d')
+
+// Offset string is passed as a parameter:
+// Note: with a parameter, repeated calls won't return 304 Not Modified.
+from Orders
+where RequireAt <= now($offset)
+{ "offset": "+7d" }
+```
+
+
+
+---
+
+### Offset format
+
+* The offset is a signed sequence of `` tokens.
+ Whitespace is allowed after the sign and between tokens.
+ Unit names are case-insensitive.
+
+ | Unit | Short form | Aliases |
+ |---------|------------|----------------------------|
+ | Years | `y` | `year`, `years` |
+ | Months | `mo` | `month`, `months` |
+ | Days | `d` | `day`, `days` |
+ | Hours | `h` | `hour`, `hours` |
+ | Minutes | `m` | `min`, `minute`, `minutes` |
+ | Seconds | `s` | `sec`, `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**:
+
+ | Offset | Effect |
+ |--------------------|-------------------------------------------------------------------------------------------|
+ | `+7d` | Add 7 days, then round down to the start of the day. |
+ | `-3d` | Subtract 3 days, then round down to the start of the day. |
+ | `+1d5h` | Add 1 day and 5 hours, then round down to the start of the hour. |
+ | `7y0s` | Add 7 years, then round down to the start of the second. |
+ | `0h` | Do not shift the time, but round down to the start of the hour. |
+ | `+1 year 6 months` | Add 1 year and 6 months, then round down to the start of the month. (whitespace allowed). |
+ | `1Y2MO3D4H5M6S` | Add all specified units; unit names are case-insensitive. |
+
+
+
+
+
+* 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](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-using-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:
+
+
+
+ ```csharp
+ List employees = session
+ .Query()
+ .Where(e => e.HiredAt < RavenQuery.Today())
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession
+ .Query()
+ .Where(e => e.HiredAt < RavenQuery.Today())
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List employees = session.Advanced
+ .DocumentQuery()
+ .WhereLessThan("HiredAt", RavenDocumentQuery.Today())
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession.Advanced
+ .AsyncDocumentQuery()
+ .WhereLessThan("HiredAt", RavenDocumentQuery.Today())
+ .ToListAsync();
+ ```
+
+
+ ```csharp
+ List employees = session.Advanced
+ .RawQuery("from Employees where HiredAt < today()")
+ .ToList();
+ ```
+
+
+ ```csharp
+ List employees = await asyncSession.Advanced
+ .AsyncRawQuery("from Employees where HiredAt < today()")
+ .ToListAsync();
+ ```
+
+
+ ```sql
+ from Employees
+ where HiredAt < today()
+ ```
+
+
+
+* `today()` and `now()` can be combined in the same query.
+ For example, to return all employees hired so far today:
+
+
+ ```sql
+ from Employees
+ where HiredAt >= today() and HiredAt <= now()
+ ```
+
+
+
+
+
+
+* **Exploration queries**
+ Both `now()` and `today()` are not supported in [exploration queryies](../../../indexes/querying/exploration-queries.mdx).
+ For example, the following query is not allowed:
+
+
+ ```sql
+ // 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](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-by-an-explicit-date) is fully supported in exploration queries.
+
+---
+
+* **Subscription queries**
+ Both `now()` and `today()` are not supported in [subscription queries](../../../client-api/data-subscriptions/creation/examples.mdx).
+ For example, the following query is not allowed:
+
+
+ ```sql
+ // 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](../../../querying/filtering-query-results/filter-by-date-and-time.mdx#filter-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.
+
+
+
+
+
+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('')` resolved to the same value.
+
+* Client-side caching can be disabled at different scopes:
+ * **per-session**, by setting `session.Advanced.NoCaching` or by using the [NoCaching session option](../../../client-api/session/configuration/how-to-disable-caching.mdx),
+ * **per-query**, by using `IDocumentQuery.NoCaching()` / `DocumentQueryCustomization.NoCaching()`, or
+ * **store-level**, by setting [`DocumentConventions.MaxHttpCacheSize = 0`](../../../client-api/configuration/conventions.mdx#maxhttpcachesize).
+
+
+
+
+
+### Aggressive caching bypasses server re-evaluation
+
+* **When the request runs inside an [Aggressive caching](../../../client-api/how-to/setup-aggressive-caching.mdx) 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:
+
+| Expression | Resolves to | Can the server return `304`? | Valid until |
+| ------------------------------------------------- | ----------- | ---------------------------- | -------------- |
+| `today()` | Start of the current UTC day (`00:00:00`) | ✅ yes | Until UTC day rolls over or the queried collection changes. |
+| `now()`
_(no offset)_ | Current UTC date and time | ❌ no | n/a
Re-evaluated on every call. |
+| `now('')`
_(literal string offset)_ | `now + offset`
Floored to the smallest unit in the offset.
(`'+7d'` → day, `'+1h30m'` → minute, `'+15s'` → second) | ✅ yes | Floored value changes or the queried collection changes. |
+| `now($param)`
_(parameter offset)_ | `now + offset`
Treated as non-deterministic. | ❌ no | n/a
Re-evaluated on every call. |
+
+
+
+
+
+
+
+```csharp
+// Inside a System.Linq.Expressions.Expression>:
+RavenQuery.Now() // current server UTC time
+RavenQuery.Now(string offset) // current server UTC time + offset, rounded
+RavenQuery.Today() // start of current UTC day
+```
+
+
+
+
+
+```csharp
+RavenDocumentQuery.Now()
+RavenDocumentQuery.Now(string offset)
+RavenDocumentQuery.Today()
+```
+
+
+
+
+
+```sql
+now()
+now('')
+today()
+```
+
+
+
+| Parameter | Type | Description |
+|------------|----------|-------------|
+| **offset** | `string` | _(optional, `now()` only)_
Signed time-shift expression (e.g. `'+7d'`, `'-1d5h'`).
Sets the rounding unit. |
+
+
\ No newline at end of file
diff --git a/docs/querying/filtering-query-results/filter-by-date-and-time.mdx b/docs/querying/filtering-query-results/filter-by-date-and-time.mdx
new file mode 100644
index 0000000000..555ab30e21
--- /dev/null
+++ b/docs/querying/filtering-query-results/filter-by-date-and-time.mdx
@@ -0,0 +1,28 @@
+---
+title: "Filter by Date and Time"
+sidebar_label: "Filter by Date and Time"
+description: "Learn how to filter RavenDB query results by date and time using explicit UTC date-time values, now(), today(), and time offsets, including supported syntax, restrictions, and query caching behavior."
+sidebar_position: 0
+supported_languages: ["csharp"]
+see_also:
+ - title: "Query Overview"
+ link: "querying/overview"
+ source: "docs"
+ path: "Querying"
+ - title: "What is a Document Query"
+ link: "querying/document-query/what-is-document-query"
+ source: "docs"
+ path: "Querying > DocumentQuery"
+---
+
+import LanguageSwitcher from "@site/src/components/LanguageSwitcher";
+import LanguageContent from "@site/src/components/LanguageContent";
+
+import FilterByDateAndTimeCsharp from './content/_filter-by-date-and-time-csharp.mdx';
+
+
+
+
+
+
+
diff --git a/docs/querying/rql/what-is-rql.mdx b/docs/querying/rql/what-is-rql.mdx
index 432256a37d..fd145d424a 100644
--- a/docs/querying/rql/what-is-rql.mdx
+++ b/docs/querying/rql/what-is-rql.mdx
@@ -210,7 +210,7 @@ The following options are available:
#### Query a specific collection: `from `
-```csharp
+```sql
// Full collection query
// Data source: The raw collection documents (Auto-index is Not created)
from "Employees"
@@ -218,7 +218,7 @@ from "Employees"
-```csharp
+```sql
// Collection query - by ID
// Data source: The raw collection documents (Auto-index is Not created)
from "Employees" where id() = "employees/1-A"
@@ -226,7 +226,7 @@ from "Employees" where id() = "employees/1-A"
-```csharp
+```sql
// Dynamic query - with filtering
// Data source: Auto-index (server uses an existing auto-index or creates a new one)
from "Employees" where FirstName = "Laura"
@@ -240,7 +240,7 @@ from "Employees" where FirstName = "Laura"
#### Query all documents: `from @all_docs`
-```csharp
+```sql
// All collections query
// Data source: All raw collections (Auto-index is Not created)
from @all_docs
@@ -248,7 +248,7 @@ from @all_docs
-```csharp
+```sql
// Dynamic query - with filtering
// Data source: Auto-index (server uses an existing auto-index or creates a new one)
from @all_docs where FirstName = "Laura"
@@ -262,7 +262,7 @@ from @all_docs where FirstName = "Laura"
#### Query an index: `from index `
-```csharp
+```sql
// Index query
// Data source: The specified index
from index "Employees/ByFirstName"
@@ -270,7 +270,7 @@ from index "Employees/ByFirstName"
-```csharp
+```sql
// Index query - with filtering
// Data source: The specified index
from index "Employees/ByFirstName" where FirstName = "Laura"
@@ -294,7 +294,7 @@ For example, you can return every document from the [Companies collection](../..
whose _field value_ **=** _a given input_.
-```csharp
+```sql
from "Companies"
where Name == "The Big Cheese" // Can use either '=' or'=='
```
@@ -304,7 +304,7 @@ Filtering on **nested properties** is also supported.
So in order to return all companies from 'Albuquerque' we need to execute following query:
-```csharp
+```sql
from "Companies"
where Address.City = "Albuquerque"
```
@@ -320,14 +320,14 @@ The operator `between` returns results inclusively, and the type of border value
It works on both 'numbers' and 'strings' and can be substituted with the `>=` and `<=` operators.
-```csharp
+```sql
from "Products"
where PricePerUnit between 10.5 and 13.0 // Using between
```
-```csharp
+```sql
from "Products"
where PricePerUnit >= 10.5 and PricePerUnit <= 13.0 // Using >= and <=
```
@@ -343,14 +343,14 @@ The `in` operator evaluates a field against a list of values.
It will return results if the field matches **any** of the items in that list.
-```csharp
+```sql
from "Companies"
where Name in ("The Big Cheese", "Unknown company name")
```
-```csharp
+```sql
from "Orders"
where Lines[].ProductName in ("Chang", "Spegesild", "Unknown product name")
```
@@ -365,7 +365,7 @@ To ensure accuracy, especially when fields might be missing from some documents,
use `exists(fieldName)` as the anchor:
-```csharp
+```sql
from "Companies"
where exists(Name) and NOT Name in ("The Big Cheese", "The Cracker Box")
```
@@ -387,7 +387,7 @@ Due to its mechanics, it is only useful when used on array fields.
The following query will yield no results in contrast to the `in` operator.
-```csharp
+```sql
from "Orders"
where Lines[].ProductName all in ("Chang", "Spegesild", "Unknown product name")
```
@@ -397,7 +397,7 @@ Removing 'Unknown product name' will return only orders that contain products wi
'Chang' and 'Spegesild' names.
-```csharp
+```sql
from "Orders"
where Lines[].ProductName all in ("Chang", "Spegesild")
```
@@ -407,27 +407,27 @@ where Lines[].ProductName all in ("Chang", "Spegesild")
-#### Binary Operators: `AND`, `OR`, `NOT`
+#### Binary operators: `AND`, `OR`, `NOT`
Binary operators can be used to build more complex statements.
The `NOT` operator can only be used with one of the other binary operators creating `OR NOT` or `AND NOT` ones.
-```csharp
+```sql
from "Companies"
where Name = "The Big Cheese" OR Name = "Richter Supermarkt"
```
-```csharp
+```sql
from "Orders"
where Freight > 500 AND ShippedAt > '1998-01-01'
```
-```csharp
+```sql
from "Orders"
where Freight > 500 AND ShippedAt > '1998-01-01' AND NOT Freight = 830.75
```
@@ -435,6 +435,31 @@ where Freight > 500 AND ShippedAt > '1998-01-01' AND NOT Freight = 830.75
+
+
+#### Methods: `today()`, `now()`
+
+Use `today()` and `now()` to compare date/time fields with the current server date or current server time.
+Learn more in [Filter by date and time](../../querying/filtering-query-results/filter-by-date-and-time.mdx).
+
+
+```sql
+// Find orders that were shipped before the current date
+from "Orders"
+where ShippedAt < today()
+```
+
+
+
+```sql
+// Find orders that are required at or after the current date and time
+from "Orders"
+where RequiredAt >= now()
+```
+
+
+
+
#### Subclauses: `(`, `)`
@@ -495,7 +520,7 @@ Specify the number of items to **skip** from the beginning of the result set and
This is useful when [paging](../../indexes/querying/paging.mdx) results.
-```csharp
+```sql
// Available syntax options:
// =========================
@@ -525,7 +550,7 @@ For more information, please refer to this [patching](../../client-api/operation
Single-line comments start with `//` and end at the end of that line.
-```csharp
+```sql
// This is a single-line comment.
from "Companies"
where Name = "The Big Cheese" OR Name = "Richter Supermarkt"
@@ -533,7 +558,7 @@ where Name = "The Big Cheese" OR Name = "Richter Supermarkt"
-```csharp
+```sql
from "Companies"
where Name = "The Big Cheese" // OR Name = "Richter Supermarkt"
```
@@ -548,7 +573,7 @@ where Name = "The Big Cheese" // OR Name = "Richter Supermarkt"
Multiline comments start with `/*` and end with `*/`.
-```csharp
+```sql
/*
This is a multiline comment.
Any text here will be ignored.
@@ -559,7 +584,7 @@ where Name = "The Big Cheese" OR Name = "Richter Supermarkt"
-```csharp
+```sql
from "Companies"
where Name = "The Big Cheese" /* this part is a comment */ OR Name = "Richter Supermarkt"
```
diff --git a/docs/querying/sorting-query-results/_category_.json b/docs/querying/sorting-query-results/_category_.json
index 0dd610f2ef..3b2e671aa1 100644
--- a/docs/querying/sorting-query-results/_category_.json
+++ b/docs/querying/sorting-query-results/_category_.json
@@ -1,4 +1,4 @@
{
- "position": 5,
+ "position": 6,
"label": "Sorting Query Results"
}