# Cómo crear un campo de fecha u hora con picker

> Campo que abre el DatePicker o TimePicker al ser tocado y formatea según el locale.

Source: https://crossfly.dev/es/docs/cookbook/forms/data-e-hora — CrossFly documentation. Full docs as one file: https://crossfly.dev/llms-full.txt

# Cómo crear un campo de fecha u hora con picker

**Propósito.** Crear un campo que, al recibir un toque, abre el `DatePicker` (calendario) o el `TimePicker` (reloj) y rellena el campo formateado conforme al locale. El usuario también puede escribir directamente con máscara.

## APIs usadas
- `campo.setMode(EditMode.DATE, true)` — modo fecha con `maskedEdit`. Deriva la máscara del locale: `LocaleFormats.dateFormat == YMD → "9999-99-99"`, si no `"99/99/9999"` (usando `LocaleFormats.dateSeparator`); `validChars = "0123456789"`; `keyboard = DATE`. Al tocar, abre el `DatePicker`.
- `campo.setMode(EditMode.TIME, true)` — modo hora con máscara `"99:99"` (usando `LocaleFormats.timeSeparator`); `keyboard = TIME`. Al tocar, abre el `TimePicker`.
- `TextField.getText()` — texto formateado con separadores (`"15/03/2024"`, `"14:30"`).
- `TextField.getTextWithoutMask()` — solo los dígitos (`"15032024"`, `"1430"`).

Comportamiento interno (automático, sin código extra):
- Al abrir, el campo pre-popula el picker con el valor actual, si es parseable (`DateTimeUtils.parseDate` para fecha; dígitos `hhmm` para hora).
- Al confirmar en el picker, el `onSelect` interno llama a `setText(...)` con el valor formateado y restaura el foco al final del texto (`restoreFocusAtEnd`).
- El `DatePicker`/`TimePicker` se crea una vez por instancia (lazy) y se reutiliza.

> Para abrir los pickers manualmente (fuera de un campo), usa `new DatePicker().onSelect(...).show()` o `new TimePicker().onSelect(...).show()`. Getters útiles: `DatePicker.getSelectedDay()/getDisplayMonth()/getDisplayYear()`, `TimePicker.getHour()/getMinute()/getTimeText()`.

## Ejemplo completo (copiar, pegar y ejecutar)
```java
package com.exemplo;

import dev.crossfly.ui.*;
import dev.crossfly.ui.layout.*;
import dev.crossfly.ui.style.*;   // TextFieldStyle (config en el estilo)

/** Pantalla principal ejecutable. Apunta el launcher (classname) y corre: gradlew :lwjgl3:run */
public class MainWindow extends Window
{
   @Override
   public void onShow() throws Exception
   {
      super.onShow();
      setLayout(new VerticalLayout());

      // Campo de fecha — abre el DatePicker al tocar
      TextField data = new TextField("");
      data.caption("Data");
      data.setMode(EditMode.DATE, true);

      // Campo de hora — abre el TimePicker al tocar
      TextField hora = new TextField("");
      hora.caption("Hora");
      hora.setMode(EditMode.TIME, true);

      Label resultado = new Label("");

      Button salvar = new Button("Salvar");
      salvar.onAction(o ->
      {
         String dataFmt = data.getText();            // "15/03/2024"
         String horaFmt = hora.getText();            // "14:30"
         if (dataFmt.isEmpty() || horaFmt.isEmpty())
         {
            Hint.show("Preencha data e hora", 2000);
            return;
         }
         resultado.setText("Agendado para " + dataFmt + " às " + horaFmt);
      });

      add(LAY_FILL, data);
      add(LAY_FILL, hora);
      add(LAY_AUTO, salvar);
      add(LAY_FILL, resultado);
   }
}
```

> El fragmento de abajo muestra **solo el núcleo**. Para ejecutarlo, colócalo en el esqueleto `MainWindow` de arriba.

## Fragmento mínimo
```java
import dev.crossfly.ui.*;
import dev.crossfly.ui.style.*;
import static dev.crossfly.ui.UIConstants.EditMode;

// Campo de fecha — abre el DatePicker al tocar
TextField data = new TextField("");
data.caption("Data");
data.setMode(EditMode.DATE, true);

// Campo de hora — abre el TimePicker al tocar
TextField hora = new TextField("");
hora.caption("Hora");
hora.setMode(EditMode.TIME, true);

Button salvar = new Button("Salvar");
salvar.onAction(o ->
{
   String dataFmt = data.getText();            // "15/03/2024"
   String horaFmt = hora.getText();            // "14:30"
   String dataDig = data.getTextWithoutMask(); // "15032024"
   // ... persiste
});
```

## Profundiza
- [DatePicker](/docs/ui/widgets/datepicker) · [Máscaras y teclados](/docs/ui/forms-and-input/masks-and-keyboards)
- Recetas hermanas: [Máscara de CPF/CEP/fecha](/docs/cookbook/forms/mascara-cpf) · [Teclado numérico](/docs/cookbook/forms/teclado-numerico)
