> ## Documentation Index
> Fetch the complete documentation index at: https://anvil.servicetitan.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Date Values

> How Anvil2 date components accept and return ISO date strings, and how to convert from JavaScript Date objects or other date libraries.

Anvil2 date field components use **ISO 8601 date strings** for input and output. This page explains the string format, why Anvil2 uses strings instead of JavaScript `Date` objects, and how to convert values from your application's date library.

## String format

Date field components accept and return **date-only ISO strings** in `YYYY-MM-DD` format (for example, `"2025-07-02"`).

Full ISO datetime strings (for example, `"2025-07-02T00:00:00.000Z"`) are also accepted as input. Date fields normalize these values to the calendar date and emit date-only strings from `onChange` callbacks.

| Direction                                             | Format                                                  | Example                                              |
| ----------------------------------------------------- | ------------------------------------------------------- | ---------------------------------------------------- |
| Input (`value`, `defaultValue`, `minDate`, `maxDate`) | ISO 8601 date string                                    | `"2025-07-02"`                                       |
| Output (`onChange`)                                   | ISO 8601 date string or `null`                          | `"2025-07-02"` or `null`                             |
| Range output                                          | Object with `startDate` and `endDate` strings or `null` | `{ startDate: "2025-07-01", endDate: "2025-07-31" }` |

<Note>
  Date Field Yearless and Date Field Yearless Range use `{ month, day }` objects instead of ISO strings because they represent recurring dates without a year. See [Date Field Yearless](/docs/web/components/date-field-yearless/code) and [Date Field Yearless Range](/docs/web/components/date-field-yearless-range/code) for those APIs.

  [Calendar](/docs/web/components/calendar/code) accepts date-only strings as input but returns full ISO datetime strings from `onSelection` (for example, "2025-07-02T00:00:00.000-07:00"). Convert Calendar output with `value?.split("T")[0]` (handle `undefined`) or a date library before passing it to date fields.
</Note>

## Why strings instead of JavaScript Date objects

Anvil2 date components use strings rather than JavaScript `Date` objects for three reasons:

1. **Library neutrality** — Teams across ServiceTitan use different date libraries (Luxon, Moment, Dispatch Temporal-lite, and others). ISO strings provide a single interchange format that any library can parse and produce without coupling components to one runtime type.
2. **Predictable calendar dates** — JavaScript `Date` objects carry timezone and time-of-day information. Passing a `Date` between layers can shift the displayed calendar day. Date-only strings represent the intended calendar date directly.
3. **API alignment** — Backend services and generated API clients often serialize dates as ISO strings. Strings map directly to form state, request payloads, and URL parameters without intermediate conversion at the component boundary.

Anvil1 Date Picker components accepted JavaScript `Date` objects. When migrating to Anvil2, convert `Date` values to ISO strings before passing them to date fields. See the [Anvil to Anvil2 migration guide](/docs/resources/migration-guides/anvil-to-anvil2) for conversion patterns.

## Components that use date strings

The following Anvil2 components use ISO date strings:

| Component                                                        | Value prop                                                       | Output                                           |
| ---------------------------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------------------ |
| [Date Field Single](/docs/web/components/date-field-single/code) | `string \| null`                                                 | `change.date` (date-only)                        |
| [Date Field Range](/docs/web/components/date-field-range/code)   | `{ startDate: string \| null; endDate: string \| null } \| null` | `change.startDate`, `change.endDate` (date-only) |
| [Calendar](/docs/web/components/calendar/code)                   | `string` or `{ start, end }` (date-only input)                   | `onSelection` (full ISO datetime)                |
| [Filter Bar](/docs/web/components/filter-bar/code) date filters  | ISO string, range object, or `null`                              | Filter value                                     |

## Convert from JavaScript Date

When your application stores dates as JavaScript `Date` objects, convert to a date-only string before passing the value to date fields. If your API client already returns ISO date strings, pass them directly without conversion.

```tsx theme={null}
function toDateString(date: Date): string {
  const year = date.getFullYear();
  const month = String(date.getMonth() + 1).padStart(2, "0");
  const day = String(date.getDate()).padStart(2, "0");
  return `${year}-${month}-${day}`;
}

// Usage with DateFieldSingle
<DateFieldSingle
  value={apiResponse.scheduledDate ? toDateString(apiResponse.scheduledDate) : null}
  onChange={(change) => {
    if (change.date) {
      setScheduledDate(change.date);
    }
  }}
/>
```

Use local date components (`getFullYear`, `getMonth`, `getDate`) rather than `toISOString()` when converting from a JavaScript `Date`. The `toISOString()` method returns UTC, which can produce a different calendar date in some timezones.

## Convert from Luxon

Anvil2 uses [Luxon](https://moment.github.io/luxon/) internally for date parsing. If your application already uses Luxon, use `toISODate()`:

```tsx theme={null}
import { DateTime } from "luxon";
import { DateFieldSingle } from "@servicetitan/anvil2";

const today = DateTime.now().toISODate(); // "2025-07-02"

<DateFieldSingle
  value={today}
  onChange={(change) => {
    if (change.date) {
      setSelectedDate(DateTime.fromISO(change.date, { zone: "utc" }));
    } else {
      setSelectedDate(null);
    }
  }}
/>
```

## Convert from other date libraries

The same ISO string format works with any date library:

```tsx theme={null}
import moment from "moment";
// Moment.js
const momentDateString = moment().format("YYYY-MM-DD");
// date-fns
import { format } from "date-fns";
const dateFnsDateString = format(new Date(), "yyyy-MM-dd");
```

Parse Anvil2 output with your library's ISO parser, then store or transmit the value in whatever format your application layer requires.

## Controlled usage pattern

Store ISO date strings in React state and pass them directly to date components:

```tsx theme={null}
import { DateFieldSingle, DateFieldRange } from "@servicetitan/anvil2";
import { useState } from "react";

function AppointmentForm() {
  const [appointmentDate, setAppointmentDate] = useState<string | null>(null);
  const [reportRange, setReportRange] = useState<{
    startDate: string | null;
    endDate: string | null;
  }>({ startDate: null, endDate: null });

  return (
    <>
      <DateFieldSingle
        label="Appointment date"
        value={appointmentDate}
        onChange={(change) => setAppointmentDate(change.date)}
      />
      <DateFieldRange
        label="Report period"
        value={reportRange}
        onChange={(change) =>
          setReportRange({
            startDate: change.startDate,
            endDate: change.endDate,
          })
        }
      />
    </>
  );
}
```

Submit form data by passing the ISO strings directly to your API, or convert them to your backend's expected format in the submit handler.
