Skip to content

bug(turba): migration to ICU breaks date rendering #47

@TDannhauer

Description

@TDannhauer

Summary

Contact birthday and anniversary fields in Turba can display ICU format pattern text (for example MMM d, yyyy or medium) instead of a formatted date. With German locale and a typical Horde date preference such as %x, the UI may also show a two-digit year (for example 08.08.84) when locale-specific strftime conversion maps to ICU short.

Stored values in the database are usually correct (for example 1984-08-08). The failure is in the web UI display path.

Environment

  • Horde 6 / Turba 5
  • PHP with the intl extension available
  • Turba contact attributes birthday and anniversary use form type monthdayyear
  • Turba Application::_normalizeDateAttributes() supplies:
    • format_in such as yyyy-MM-dd
    • format_out derived from the user Horde date_format preference (converted from strftime to ICU)
    • an IcuFormatter instance
    • locale from the user language preference

Steps to reproduce

  1. Set Horde language to German and a typical date display preference (for example %x).
  2. Open a Turba contact with a birthday stored as 1984-08-08.
  3. View the contact in read-only form rendering (Turba_View_Contact / inactive form display).

Expected behavior

The birthday is shown as a human-readable date in the user locale and chosen date format (for example 08.08.1984 in German).

Actual behavior

The UI may show:

  • the literal ICU pattern text (MMM d, yyyy),
  • the literal shortcut name (medium),
  • or a locale short date with a two-digit year (08.08.84),

instead of a properly formatted date.

Technical analysis

Turba prepares ICU-aware field parameters

In Turba_Application::_normalizeDateAttributes(), Turba rewrites monthdayyear and datetime field params to ICU-oriented format_in / format_out, attaches an IcuFormatter, and passes locale (and a timezone placeholder) into the form layer.

For locale-specific strftime values such as %x, conversion can yield an ICU shortcut such as short or medium, not a strftime pattern.

V3 MonthdayyearVariable does not match the legacy formatter path

When the modern V3 form class exists, Horde Form uses Horde\Form\V3\MonthdayyearVariable.

In the affected upstream code, that class only handled the first five init() parameters (start_year, end_year, picker, format_in, format_out) and rendered dates with:

return $date->strftime($this->_format_out);

Horde_Date::strftime() does not interpret ICU patterns or ICU shortcuts. For example:

  • strftime('MMM d, yyyy') returns the literal string MMM d, yyyy
  • strftime('medium') returns the literal string medium

Turba can therefore pass correct ICU display settings while the V3 field still uses the legacy strftime path.

Legacy PSR-0 type already supports formatter mode

The older Horde_Form_Type_monthdayyear in lib/Horde/Form/Type.php already accepts formatter, locale, and timezone in init() and uses formatter mode in formatDate() when a FormatterInterface is provided:

if ($this->_isFormatterMode()) {
    $locale = $this->_resolveLocale();
    return $date->format($this->_format_out, $this->_formatter, $locale);
}

return $date->strftime($this->_format_out);

The V3 port is incomplete relative to the legacy implementation.

Related: V3 DatetimeVariable

Horde\Form\V3\DatetimeVariable composes an internal MonthdayyearVariable, but its init() only forwards the first five date parameters to the nested object. It does not forward formatter, locale, or timezone.

The legacy Horde_Form_Type_datetime does forward those arguments to the nested month/day/year type.

Turba default contact attributes do not use datetime, but any application that passes ICU formatter settings into datetime fields through the same parameter layout would hit the same gap on the V3 path.

Types that do not appear affected by the same bug

  • monthyear: no ICU format_out display path
  • time / hourminutesecond: separate time handling
  • date (DateVariable): different display mechanism

Suggested fix

  1. Bring Horde\Form\V3\MonthdayyearVariable in line with Horde_Form_Type_monthdayyear:

    • accept formatter, locale, and timezone in init()
    • use formatter mode in formatDate() and storage formatting when a formatter is present
    • keep strftime behavior as fallback when no formatter is configured
  2. Update Horde\Form\V3\DatetimeVariable to forward formatter, locale, and timezone to its nested MonthdayyearVariable, matching the legacy datetime type.

  3. Review locale-specific strftime conversion for %x and similar values so display does not fall back to English-looking ICU defaults or short two-digit years when a full locale date is intended.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions