# Selector de fecha

> Un campo de fecha con un calendario desplegable, en el formato que elijas. Componente de Pyzed para GUIs de escritorio en Python, con ejemplos y API.

Source: https://albakore.github.io/pyzed/es/library/date-picker/

:::tip[En pocas palabras]
Una casilla para una fecha. Escríbela, o pulsa el calendarito y haz clic en un día.
:::

`ui.DatePicker` es un campo de texto para una fecha. El botón del calendario (o Alt+↓) abre un [Calendario](https://albakore.github.io/pyzed/es/library/calendar/) debajo, y el usuario también puede escribir la fecha: se lee con `format` al pulsar Enter o al salir del campo. Con el foco en el campo, ↑ y ↓ mueven un día y Re Pág/Av Pág un mes, sin abrir nada. `on_change` recibe un `datetime.date` (o `None` si se vacía el campo) en `event.value`.

`ui.DatePicker` · Categoría: [Fechas y horas](https://albakore.github.io/pyzed/es/library/#fechas-y-horas) · [Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#datepicker)

**Código:**

```python
pz.container(
    ui.DatePicker(value="2026-10-22", format="DD/MM/YYYY", on_change=on_change),
    width=220, height=330, align_y="start")
```

:::note[Nuevo]
Este componente se añadió hace poco. Cuéntanos qué tal te funciona en el [gestor de incidencias](https://github.com/albakore/pyzed/issues).
:::

## Cuándo usarlo

- Para fechas de nacimiento, vencimientos, reservas y cualquier campo de formulario con una fecha.
- `format` acepta tokens (`DD/MM/YYYY`, `MMM D, YYYY`, `dddd D MMMM`) o un patrón de `strftime` (`%d.%m.%Y`). Los nombres de meses y días siguen el idioma de la app.
- `min`, `max` y `disabled_dates` (fechas, `"weekend"` o nombres de días) desactivan días.
- Para dos fechas (desde–hasta), usa [Selector de rango de fechas](https://albakore.github.io/pyzed/es/library/date-range-picker/).

## Uso

```python
import pyzed as pz
from pyzed import ui

import datetime

class Booking(pz.App):
    def __init__(self):
        self.day = datetime.date.today()

    def view(self):
        return pz.column([
            ui.field("Check-in", ui.DatePicker(value=self.day, format="ddd D MMM YYYY",
                                               min=datetime.date.today(), disabled_dates=["sunday"],
                                               on_change=lambda e: setattr(self, "day", e.value))),
            ui.label(f"Booked for {ui.format_date(self.day, 'dddd D MMMM')}"),
        ], spacing=12, width=320)
```

## Variantes

:::note[Sobre estas capturas]
Cada captura la graba pyzed mismo, fuera de pantalla a 2x, en One Dark o One Light según el tema de este sitio, y recortada al componente para que se vea a su tamaño real. El puntero pasa por encima, pulsa o escribe en él; un componente que no reacciona al puntero recorre algunos temas. Con movimiento reducido ves el primer fotograma. Abre **Código** bajo una captura para ver el fragmento que la dibuja; los nombres libres como `on_save` son tus propios callbacks.
:::

### Formato

Tokens: `YYYY` `YY`, `MMMM` `MMM` `MM` `M`, `DD` `D`, `dddd` `ddd`; `[texto]` se copia tal cual.

```python
ui.DatePicker(value="2026-10-22", on_change=on_change)
```

```python
ui.DatePicker(value="2026-10-22", format="DD/MM/YYYY", on_change=on_change)
```

```python
ui.DatePicker(value="2026-10-22", format="MMM D, YYYY", on_change=on_change)
```

```python
ui.DatePicker(value="2026-10-22", format="ddd D MMM", on_change=on_change)
```

### Estados

```python
ui.DatePicker(placeholder="Pick a date", on_change=on_change)
```

```python
ui.DatePicker(value="2026-10-22", invalid=True, on_change=on_change)
```

```python
ui.DatePicker(value="2026-10-22", disabled=True, on_change=on_change)
```

```python
ui.DatePicker(value="2026-10-22", on_change=on_change)
```

## Ejemplos

### Formatos

`ui.format_date` y `ui.parse_date` usan los mismos tokens que el campo, para tus propias etiquetas.

**Código:**

```python
pz.column([
    ui.label(ui.format_date("2026-10-22", "DD/MM/YYYY"), mono=True),
    ui.label(ui.format_date("2026-10-22", "MMM D, YYYY"), mono=True),
    ui.label(ui.format_date("2026-10-22", "dddd, D MMMM YYYY"), mono=True),
    ui.label(ui.format_date("2026-10-22", "[week of] D/M/YY"), mono=True),
], spacing=6)
```

## Eventos

Selector de fecha tiene **4 eventos propios**, en la tabla de abajo. Como todo widget, también tiene los **18 eventos comunes** (`click`, `double_click`, `right_click`, `mouse_enter`, `drag`, `key_down`, `resize`…), que se conectan con `.on(...)`: mira [Eventos](https://albakore.github.io/pyzed/es/guides/events/) y [Eventos de cada componente](https://albakore.github.io/pyzed/es/library/events/).

Es un `pz.Component`, así que también lanza `on_mount` y `on_unmount`, y sus handlers reciben un `pz.Event` cuyo `value` trae el dato.

| Evento | De | El handler recibe | Cuándo |
| --- | --- | --- | --- |
| `on_change` | `ui.DatePicker` | `(event)` | Recibe `event.value`: un `datetime.date` o `None`. |
| `on_open` | `ui.DatePicker` | `(event)` | Se abrió el calendario. |
| `on_close` | `ui.DatePicker` | `(event)` | Se cerró el calendario. |
| `on_dismiss` | `pz.popup` | `()` | Mensaje o función que se envía con un clic fuera o Escape. |

**El handler recibe** es lo que Pyzed le pasa a tu función: `()` es nada. Cualquier handler también puede ser un mensaje (un valor que no se puede llamar), que va a `update()`.

### Manejar los eventos

Los mismos eventos escritos de tres formas. **Imperativa**: métodos de la app que cambian `self`. **Declarativa**: los handlers producen mensajes y un único `update()` decide. **Funcional**: una función pura dibuja un estado inmutable y pide cambios con `set_state(...)`. Mira [Imperativo, declarativo y funcional](https://albakore.github.io/pyzed/es/guides/code-styles/).

**Imperativo:**

```python
import datetime

class Booking(pz.App):
    def __init__(self):
        self.day = datetime.date(2026, 10, 22)

    def changed(self, event):            # on_change: event.value is a datetime.date (or None)
        self.day = event.value

    def view(self):
        return pz.column([
            ui.DatePicker(value=self.day, format="DD/MM/YYYY", on_change=self.changed),
            ui.label(ui.format_date(self.day, "dddd D MMMM") or "No date"),
        ], spacing=8, width=240)
```

**Declarativo:**

```python
import datetime
from dataclasses import dataclass

@dataclass
class Picked:
    day: datetime.date

class Booking(pz.App):
    day = datetime.date(2026, 10, 22)

    def update(self, message):
        match message:
            case Picked(day):
                self.day = day

    def view(self):
        # DatePicker is a pz.Component: its handler gets a pz.Event
        return ui.DatePicker(value=self.day, on_change=lambda e: Picked(e.value))
```

**Funcional:**

```python
import datetime
from dataclasses import dataclass

@dataclass(frozen=True)
class State:
    day: datetime.date = datetime.date(2026, 10, 22)

def view(state, set_state):
    return pz.column([
        ui.DatePicker(value=state.day, format="MMM D, YYYY", on_change=lambda e: set_state(day=e.value)),
        ui.label(f"Week {state.day.isocalendar().week}" if state.day else "No date"),
    ], spacing=8, width=240)
```

## Consejos

:::tip
El calendario se abre en un `pz.popup`, una capa dibujada sobre la ventana: nunca la recorta un scrollable ni un contenedor pequeño, se da la vuelta y sale por encima del campo si abajo no hay sitio, y se cierra con Escape o con un clic fuera.
:::

## Propiedades y API

### `ui.DatePicker`

```python
class DatePicker
```

Un componente: un campo de fecha que abre un calendario debajo, en una ventana emergente que ningún panel recorta. Se puede escribir en `format` (Enter o salir del campo lo lee); tras un clic, ↑/↓ mueven la fecha un día y Re Pág/Av Pág un mes sin abrir nada, Alt+↓ abre el calendario y Escape lo cierra. Ver la página [Selector de fecha](https://albakore.github.io/pyzed/es/library/date-picker/).

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `value` | `None` | La fecha (`datetime.date`, texto ISO o `None`). |
| `format` | `"YYYY-MM-DD"` | Cómo se escribe: `"DD/MM/YYYY"`, `"MMM D, YYYY"`... (ver `format_date`). |
| `placeholder` | `""` | Pista mientras está vacío (por defecto, el formato). |
| `min` | `None` | La primera fecha. |
| `max` | `None` | La última fecha. |
| `disabled_dates` | `()` | Días que no se pueden elegir (como en `Calendar`). |
| `first_weekday` | `"monday"` | `"monday"`, `"sunday"` o `"saturday"`. |
| `week_numbers` | `False` | Muestra los números de semana en el calendario. |
| `clearable` | `True` | Muestra una x que lo vacía. |
| `today_button` | `True` | Añade un enlace Hoy al calendario. |
| `disabled` | `False` | Lo atenúa. |
| `invalid` | `False` | Pinta el borde con el color de error. |

Eventos: `on_change`, `on_open`, `on_close` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#datepicker)

### `ui.format_date`

```python
format_date(value, fmt='YYYY-MM-DD', *, language=None)
```

Escribe una fecha con un patrón de marcas: `YYYY` 2026, `YY` 26, `MMMM` octubre, `MMM` oct, `MM` 10, `M` 10, `DD` 05, `D` 5, `dddd` lunes, `ddd` lun, `HH`/`hh` horas, `mm` minutos, `ss` segundos, `A` AM/PM y `[texto]` tal cual. Un patrón con `%` es de `strftime`. Los nombres de meses y días siguen el idioma de `pyzed.i18n`.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `value` | *obligatorio* | Una fecha, un datetime, texto ISO o `None` (da `""`). |
| `fmt` | `"YYYY-MM-DD"` | El patrón. |
| `language` | `None` | Un idioma para los nombres en lugar del actual. |

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#format_date)

### `ui.parse_date`

```python
parse_date(text, fmt='YYYY-MM-DD', *, language=None)
```

Lee una fecha escrita con un patrón de `format_date` (meses en el idioma actual o en inglés); el ISO `YYYY-MM-DD` siempre funciona. Devuelve `None` si el texto no es una fecha.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `text` | *obligatorio* | El texto. |
| `fmt` | `"YYYY-MM-DD"` | El patrón. |
| `language` | `None` | El idioma de los nombres. |

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/ui/#parse_date)

### `pz.popup`

```python
popup(base, content=None, *, on_dismiss=None, side='bottom', align='start', gap=4.0)
```

Muestra `content` encima de todo junto a `base`, como el menú de un desplegable: no lo recortan los paneles donde está `base`, se pasa al otro lado cuando no cabe y se queda dentro de la ventana. Un clic fuera (y fuera de `base`) o Escape llama a `on_dismiss`. Con `content=None` solo se muestra `base`. Los selectores de fecha abren su calendario con él.

| Propiedad | Por defecto | Descripción |
| --- | --- | --- |
| `base` | *obligatorio* | El widget al que pertenece (un campo, un botón). |
| `content` | `None` | Lo que se abre (un panel, un menú), o `None` mientras está cerrado. |
| `side` | `"bottom"` | `"bottom"`, `"top"`, `"right"` o `"left"` de `base`. |
| `align` | `"start"` | `"start"`, `"center"` o `"end"`: cómo se alinea con `base`. |
| `gap` | `4.0` | Espacio entre `base` y el contenido. |

Eventos: `on_dismiss` ([eventos](#eventos)).

[Referencia completa →](https://albakore.github.io/pyzed/es/reference/widgets/#popup)

## Relacionados

- [Calendario](https://albakore.github.io/pyzed/es/library/calendar/): Una cuadrícula del mes para elegir un día, un rango o varios días, siempre a la vista.
- [Selector de rango de fechas](https://albakore.github.io/pyzed/es/library/date-range-picker/): Dos fechas en un campo, con dos meses lado a lado y rangos rápidos.
- [Selector de hora](https://albakore.github.io/pyzed/es/library/time-picker/): Un campo de hora con columnas de horas y minutos, en 24 o 12 horas.
- [Campo de texto](https://albakore.github.io/pyzed/es/library/input/): Un campo de texto controlado con icono, placeholder y modo contraseña.
