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

# Input Datetime

> Asks for a date and a time.

`io.input.datetime()` requests a point in time and returns it as a [luxon](https://moment.github.io/luxon/) `DateTime`. Provided by the `@awaitio/input-datetime` package.

<Frame>
  <img src="https://mintcdn.com/awaitio/MjbT5AW66vMXbVck/images/io-input-datetime.png?fit=max&auto=format&n=MjbT5AW66vMXbVck&q=85&s=112383f633990e9e11ce3b9a95bd6d28" alt="A Trial ends at field with a date and time, and the hint Time zone: Europe/Prague under it" width="1004" height="212" data-path="images/io-input-datetime.png" />
</Frame>

The person picks the date and time in their browser's time zone, which is shown under the field (*Time zone: Europe/Prague*). The value is sent to the server in UTC, so the handler gets the same instant whatever time zone the person is in.

## Install

```bash theme={null}
npm install @awaitio/input-datetime
```

## Setup

Register it under the key you want in `io`, see [Input components](/core/components):

```ts app.ts {5} theme={null}
import { inputDatetime } from '@awaitio/input-datetime';

export const app = new AwaitIO({
  // name, actionsDirectory, theme, secret, users…
  components: { input: { datetime: inputDatetime } },
});
```

## Usage

```ts theme={null}
import { DateTime } from 'luxon';

const endsAt = await io.input.datetime('Trial ends at', {
  defaultValue: DateTime.now().plus({ days: 14 }).startOf('day'),
  min: DateTime.now(),
});
```

## Props

| Prop | Type | Required | Description |
| - | - | - | - |
| `helpText` | `string` | Optional | Secondary text under the field. |
| `defaultValue` | `DateTime \| Date \| string` | Optional | The value the field starts with. Empty when left out. |
| `min` | `DateTime \| Date \| string` | Optional | The earliest time that can be picked. |
| `max` | `DateTime \| Date \| string` | Optional | The latest time that can be picked. |
| `disabled` | `boolean` | Optional | Shows the starting value without letting it change; the handler gets that value whatever the browser sends. |

`defaultValue`, `min` and `max` take a luxon `DateTime`, a JavaScript `Date` or an ISO 8601 string. An impossible date such as `2026-02-30` throws when the io call is made.

## Optional

The field is required. Chain `.optional()` to let it stay empty; the handler then gets `DateTime | undefined`, see [Optional fields](/core/components#optional-fields).

```ts theme={null}
const remindAt = await io.input.datetime('Remind me at').optional();
```

## Returns

A luxon `DateTime` in the UTC zone. Convert it with `.setZone(...)` when you need local time, or `.toISO()` to store it.

## Built-in validation

The field is always required. The input works in whole minutes, so `min` and `max` are compared at minute precision: `min: DateTime.now()` still accepts the current minute. The server checks every answer:

| When | Message |
| - | - |
| No date and time picked | `<label>: pick a date and time.` |
| A date that does not exist | `<label>: pick a date and time that exists.` |
| Earlier than `min` | `<label> must not be earlier than <min>.` |
| Later than `max` | `<label> must not be later than <max>.` |

`<min>` and `<max>` are printed in UTC.

## Custom validation

Chain `.validate()` for a check of your own. It runs on the server after the checks above, gets the value the handler would get and returns a message to show under the field, or nothing when the value is fine; see [Custom validation](/core/components#custom-validation).

```ts theme={null}
const startsAt = await io.input.datetime('Call starts at').validate((startsAt) => {
  return startsAt.hour >= 9 && startsAt.hour < 17 ? undefined : 'Pick a time between 9 AM and 5 PM.';
});
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.