}>
  **Lesson 6 of 8**: build a time picker with spinbutton fields, then combine it with the calendar for a full datetime picker.

## The useTimePicker hook

`useTimePicker` handles time input — spinbutton fields, keyboard increment/decrement, and AM/PM.

```tsx showLineNumbers
import { useTimePicker } from '@gentleduck/calendar'

function MyTimePicker() {
  const { state, getFieldProps } = useTimePicker({
    hourCycle: '12',
    showSeconds: true,
  })

  return (
    <div>
      <input {...getFieldProps('hour')} />
      <span>:</span>
      <input {...getFieldProps('minute')} />
      <span>:</span>
      <input {...getFieldProps('second')} />
      <button {...getFieldProps('ampm')}>{state.displayAmPm}</button>
    </div>
  )
}
```

***

## How it works

Each field is a `spinbutton`. Users can:

* **Type** a number to set the value.
* Press <Kbd>ArrowUp</Kbd> / <Kbd>ArrowDown</Kbd> to increment/decrement.
* Press <Kbd>Tab</Kbd> to move between fields.
* On the AM/PM field: <Kbd>A</Kbd> for AM, <Kbd>P</Kbd> for PM.

`getFieldProps` applies:

* `role="spinbutton"` with `aria-valuemin`, `aria-valuemax`, `aria-valuenow`.
* Keyboard handlers for increment, decrement, and digit entry.
* Focus management via `tabIndex`.

***

## Hour cycles

| Cycle | Range | AM/PM? |
| :--- | :--- | :--- |
| `'24'` | 0-23 | No |
| `'12'` | 1-12 | Yes |

```tsx showLineNumbers
// 24-hour
useTimePicker({ hourCycle: '24' })
// state.value.hour is 0-23

// 12-hour
useTimePicker({ hourCycle: '12' })
// state.displayHour is 1-12
// state.displayAmPm is 'AM' or 'PM'
```

***

## Combining date and time

`useDateTime` composes `useCalendar` and `useTimePicker` into a single hook:

```tsx showLineNumbers
import { NativeAdapter, useDateTime } from '@gentleduck/calendar'

const adapter = new NativeAdapter()

function MyDateTimePicker() {
  const { calendar, timePicker, state } = useDateTime({
    adapter,
    defaultValue: new Date(),
    hourCycle: '12',
  })

  return (
    <div>
      {/* Calendar UI using calendar.state, calendar.getDayProps, etc. */}
      {/* Time UI using timePicker.state, timePicker.getFieldProps, etc. */}
      <p>Combined value: {state.value?.toISOString()}</p>
    </div>
  )
}
```

`state.value` is a single `Date` that joins the selected calendar date with the current time. Date changes keep the time; time changes keep the date.

***

## Constraints

Set minimum and maximum times:

```tsx showLineNumbers
useTimePicker({
  hourCycle: '24',
  minTime: { hour: 9, minute: 0 },
  maxTime: { hour: 17, minute: 0 },
  minuteStep: 15, // 15-minute increments
  secondStep: 5,  // 5-second increments (when showSeconds is true)
})
```

}>
  Next: [Lesson 7 - Styling](/duck-calendar/course/07-styling)