.. index:: pair: page; Date and time controls .. _doxid-ui_date_time_pickers: Date and time controls ====================== ``UIDateTimeEdit`` is one segmented ``UITextInput`` surface with date, time, and local date-time modes. ``UIDatePicker`` adds a calendar popup, ``UITimePicker`` configures time mode without a popup, and ``UIDateTimePicker`` combines a calendar and time editor in one popup. ``UICalendar`` can also be used as a standalone widget. .. _doxid-ui_date_time_pickers_1autotoc_md892: Native XML ~~~~~~~~~~ .. ref-code-block:: cpp Values are optional typed civil values: ``CalendarDate``, ``TimeOfDay``, and ``LocalDateTime``, from ````. They do not carry time zones. Use ``setDate()``, ``setTime()``, or ``setDateTime()`` and the corresponding optional getters. ``clear()`` removes a value when ``allow-empty`` is true (the default). Canonical setters clamp to the active mode's bounds and emit ``OnValueChange`` only when the typed value changes. The ``value`` property exposes ISO serialization for ordinary data binding. Hidden seconds and milliseconds remain part of the value; serialization preserves nonzero milliseconds even if they are not displayed. .. _doxid-ui_date_time_pickers_1autotoc_md893: Serialization and Unix timestamps ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ``DateTimeFormatter`` in ```` formats ISO values independently of the display locale and parses them with an explicit pattern: .. ref-code-block:: cpp using namespace :ref:`EE `; using namespace :ref:`EE::System `; const :ref:`CalendarDate ` date{ 2026, 9, 28 }; const std::string storedDate = :ref:`DateTimeFormatter::toISODate `( date ); // "2026-09-28" const auto restoredDate = :ref:`DateTimeFormatter::parseDate `( storedDate, :ref:`DateTimeFormat `( "yyyy-MM-dd" ) ); const :ref:`LocalDateTime ` value{ date, { 20, 14, 32, 125 } }; const std::string storedValue = :ref:`DateTimeFormatter::toISOLocalDateTime `( value, true ); const auto restoredValue = :ref:`DateTimeFormatter::parseDateTime `( storedValue, :ref:`DateTimeFormat `( "yyyy-MM-dd'T'HH:mm:ss.SSS" ) ); // The application knows this value uses UTC-03:00; the types do not store a timezone. const :ref:`Int32 ` utcOffsetSeconds = -3 * 60 * 60; const auto timestamp = value.toUnixTimestampMilliseconds( utcOffsetSeconds ); if ( timestamp ) { const auto restored = :ref:`LocalDateTime::fromUnixTimestampMilliseconds `( *timestamp, utcOffsetSeconds ); } Unix timestamps count seconds or milliseconds since ``1970-01-01T00:00:00Z``, without leap seconds. ``CalendarDate::toUnixTimestamp()`` uses midnight UTC; ``fromUnixTimestamp()`` extracts the UTC date containing that instant. ``LocalDateTime`` conversions default to UTC and accept an offset in seconds, where ``local = UTC + offset``. The offset is not inferred from the system timezone and does not resolve daylight-saving gaps or ambiguous times. Applications using named timezones must resolve the offset for the particular date/time before conversion. The seconds methods discard milliseconds, rounding down even before the epoch. The ``toUnixTimestampMilliseconds()`` / ``fromUnixTimestampMilliseconds()`` methods preserve them. Conversions return ``std::optional`` : invalid civil values, an out-of-range year, or an unrepresentable Int64 millisecond timestamp produce ``std::nullopt``. The full Int32 year range fits in Int64 seconds, but only part of it fits in Int64 milliseconds. These conversions are independent of locale, ``time_t`` size, and the machine's timezone. For a date-only database column, ISO date text or typed date fields preserve its civil meaning directly. .. _doxid-ui_date_time_pickers_1autotoc_md894: Editing ~~~~~~~ Click a section to select it. Left/Right navigate sections; Home/End select the first/last. Up/Down step the active section. Numeric entry automatically advances when a complete value has been entered. Pending digits are shown with underscores, commit on navigation, Enter, focus loss, or timeout, and can be canceled with Escape. Configure the timeout in C++ with ``setPendingDigitTimeout()`` (default: one second). Delete/Backspace clear the value when allowed. Copy and select-all use normal input commands. Paste replaces the whole value, including when only one section is selected, and accepts ISO regardless of the display format. Invalid input preserves the previous valid value. Wheel edits require both focus and ``wheel-editing: true``; wheel editing is disabled by default. ``allow-editing: false`` prevents user mutation. Month/year edits clamp the day at month ends. Time-only arithmetic wraps within the day; local date-time arithmetic carries across date boundaries. AM/PM entry changes the period without advancing the date. Utility arithmetic outside the representable Int32 year range leaves the value unchanged. .. _doxid-ui_date_time_pickers_1autotoc_md895: Locale and properties ~~~~~~~~~~~~~~~~~~~~~ Display defaults come from ``DateTimeLocale::system()`` (Windows regional settings on Windows), with a centralized locale-name fallback for information unavailable through the standard library. ``setLocale()`` accepts explicit date order/separator, hour cycle, month and weekday names, AM/PM labels, and first weekday; this also supports locales unavailable on the host. ``fromLocaleName()`` resolves ordering and cycle fallbacks; applications can supply translated names in the returned structure. ======== ================================================================= Property Meaning ======== ================================================================= Show seconds without milliseconds; default Show milliseconds and seconds; default Positive integer steps Date-mode ISO bounds Time-mode ISO bounds Local date-time ISO bounds Empty-value and focused wheel editing policies Parent picker popup to scene root instead of its window container Inspectable picker open state Calendar weekday: Sunday Calendar Calendar ISO navigation state ======== ================================================================= Date patterns require day, month, and year. Time patterns require one hour token and minutes; 12-hour patterns also require ``a``. Tokens: ``d`` / ``dd``, ``M`` / ``MM``, ``yy`` / ``yyyy``, ``H`` / ``HH``, ``h`` / ``hh``, ``m`` / ``mm``, ``s`` / ``ss``, ``S`` / ``SS`` / ``SSS``, and ``a``. Quote literal text with single quotes inside the pattern. Two-digit years parse into 2000–2099. Standard serialized dates use ``yyyy-MM-dd``, times ``HH:mm:ss[.SSS]``, and local date-times ``yyyy-MM-ddTHH:mm:ss[.SSS]``. Setting a minimum above the maximum moves the maximum to that minimum; setting a maximum below the minimum moves the minimum to that maximum. Empty bound properties remove constraints. Seconds and milliseconds can be toggled separately with ``setShowSeconds()`` and ``setShowMilliseconds()`` or their CSS/XML properties. Both default to hidden. Enabling milliseconds includes seconds; hiding milliseconds leaves seconds enabled. Hiding seconds hides both. These options change display precision without discarding stored precision, and also update the date-time popup footer. An explicit ``time-format`` controls its own sections. .. _doxid-ui_date_time_pickers_1autotoc_md896: Calendar popup ~~~~~~~~~~~~~~ Click the trailing button, press F4, or press Alt+Down. Opening an empty picker displays today without assigning it. Date-only selection updates the value, closes the popup, and restores editor focus. In a date-time picker, selecting a date preserves the time and keeps the popup open so the footer can edit it. Selecting a date into an empty value uses midnight, then applies its constraints. The footer uses the same segmented editing as ``UITimePicker``, with SVG up/down buttons for hour, minute, and any displayed seconds, milliseconds, or AM/PM sections. It follows the field's locale, format, steps, and boundary-date time constraints. Changing these settings while the popup is open updates its controls immediately. Setting the owner read-only closes the popup. Committed edits update the field immediately and preserve hidden precision. ``getPopupTimePicker()`` returns the owned footer editor after the first opening. Enter in the footer closes the popup; Escape cancels pending digits and closes it while preserving already committed changes. Focus leaving the field and its entire popup also closes it. The popup measures both calendar and time footer before choosing its placement, flips above when space permits, and clamps to scene bounds. ``UIPopUp::findBestPosition()`` supplies the shared world-pixel placement calculation used by field popups and ``UIMenu::findBestMenuPos()`` for trigger and cursor menus. Cascading menus retain their menu-specific rules for avoiding the previous menu. Calendar selection and navigation are separate. Arrows move focus by day/week, Home/End move to week boundaries, PageUp/PageDown move by month, and Ctrl+PageUp/PageDown move by year. Enter explicitly selects focus. Click the title to choose a month, then click it again to choose a year. Previous/Next page through those views. Today navigates to today without selecting it. ``OnItemSelected`` reports explicit selection, including re-selection of the same date; ``OnValueChange`` reports a changed selection. The 42 day widgets are reused across navigation. .. _doxid-ui_date_time_pickers_1autotoc_md897: Theme and example ~~~~~~~~~~~~~~~~~ Breeze provides light/dark palette styling. Theme tags include ``datetimeedit``, ``datepicker``, ``timepicker``, ``datetimepicker``, ``datepicker::button``, ``datetimepicker::button``, ``calendar``, and ``calendar::header/previous/next/title/weekdays/weekday/grid/day/today``. The combined popup exposes ``datetimepicker::popup``, ``datetimepicker::time``, and ``datetimepicker::time-up/time-down``; arrow classes identify ``hour``, ``minute``, ``second``, ``millisecond``, and ``am-pm``. CSS controls the footer font, padding, minimum height, and SVG arrow size in ``dp``. Picker buttons use the standard arrow cursor; editable text uses the I-beam. Calendars size to their text metrics by default, with a theme minimum of ``160dp`` set by the ``Calendar`` rule in ``bin/assets/ui/breeze.css`` and ``bin/assets/ui/uitheme.css``. Override ``min-width`` / ``min-height`` to change the preferred size while retaining automatic text fitting. Changing fonts automatically updates the popup size, header, weekday row, and day grid. Explicit fixed width/height remain application overrides; choose enough space for the selected font. Picker buttons use an inline SVG in ``foreground-image``, with ``foreground-size: 12dp 12dp``, centered positioning, and theme-controlled ``foreground-tint``. The SVG uses a white base fill so the native image tint supplies the light/dark and hover colors. No font glyph is required. Calendar previous/next buttons likewise use CSS-supplied left/right SVGs, centered at ``12dp``. Read-only picker buttons use ``[allow-editing=false]`` selectors to mute the calendar icon and remove its hover highlight, while leaving the input text readable and selectable. Day classes are ``selected``, ``today``, ``outside-month``, and ``focused``; constrained cells use normal disabled state. Today uses a border, selection a fill. Build ``eepp-ui-date-time-picker`` and run ``bin/eepp-ui-date-time-picker``; ``--us`` switches to a Sunday-first, 12-hour locale. ``--light``, ``--small-font``, ``--large-font``, and ``--narrow`` exercise theme and sizing variants. F11 opens the inspector. Set ``EEPP_PIXEL_DENSITY=2`` to check scaling, and use the inspector to vary font size, width, and placement. .. _doxid-ui_date_time_pickers_1autotoc_md898: Follow-up scope ~~~~~~~~~~~~~~~ Range selection, named timezone support, and time-list popups remain separate follow-ups. HTML ``input`` types ``date``, ``time``, and ``datetime-local`` now map to these native controls through ``UIHTMLInput``. HTML values are sanitized and serialized independently of the display locale: ``yyyy-MM-dd``, ``HH:mm[:ss[.SSS]]``, and ``yyyy-MM-ddTHH:mm[:ss[.SSS]]``. Local date-time values have no timezone. Valid date/time value attributes retain their ISO spelling; local date-time values normalize their separator to ``T``, omit zero seconds, and trim trailing fractional zeros. The adapter supports ``min``, ``max``, ``step`` (including ``any`` and fractional seconds), ``required``, ``readonly``, and ``disabled``. Range violations remain unchanged and report invalidity; native controls retain their default clamping policy. Time ranges can cross midnight. Step validation uses the minimum, otherwise the value attribute, otherwise the Unix civil epoch as its base. Date steps use days; time and local date-time steps use seconds, defaulting to 60. Use ``UIHTMLInput::getValidity()`` / ``checkValidity()`` and ``UIHTMLForm::checkValidity()`` / ``requestSubmit()`` for the implemented temporal constraints. Clicking a submit control validates; direct ``UIHTMLForm::submit()`` bypasses validation. Anonymous subparts use the light user-agent defaults in ``getHTMLDocumentDefaultsCSS()`` in ``uiwidgetcreator.cpp``, independently of the application theme. The HTML adapter marks private control content with the existing ``UI_IGNORE_GLOBAL_CSS``; stylesheet matching keeps the document's low-priority UA rules and excludes author rules for that content. Popups remain in the document scene and fit its visible viewport. Date/time editors measure their intrinsic width from the displayed text or placeholder plus padding and the calendar button, so author CSS is not required to give an input a usable size. General HTML validity for other input types, validation messages, and ``novalidate`` / ``formnovalidate`` are outside this temporal mapping.