Skip to content

Improve date handling in getDate method#37

Merged
ralflang merged 1 commit into
FRAMEWORK_6_0from
fix/getDate
May 29, 2026
Merged

Improve date handling in getDate method#37
ralflang merged 1 commit into
FRAMEWORK_6_0from
fix/getDate

Conversation

@TDannhauer
Copy link
Copy Markdown
Contributor

Handle unparseable IMAP envelope dates in getDate()

Summary

  • Use Horde_Imap_Client_DateTime::getTimestamp() for valid envelope dates instead of casting the object to string.
  • When the envelope date is unparseable (error()), fall back to the message Date header, then to the current time.
  • Treat numeric string "0" as invalid (IMAP client error sentinel), not as a Unix timestamp.

Problem

During ActiveSync Sync, Horde_ActiveSync_Imap_EasMessageBuilder::_setHeaderProperties() sets datereceived from Horde_ActiveSync_Imap_Message::getDate(). If new Horde_Date() throws, the Sync response aborts with HTTP 500 and clients retry indefinitely.

Observed log (German locale):

ERR: Returning HTTP 500 while handling Sync command. Error is: Zeitformat (0) nicht erkannt
...
Horde_ActiveSync_Imap_Message->getDate()
Horde_Date->__construct()

The German message is Horde_Date’s “Failed to parse time string (%s)” — here with %s = 0, not “format id 0”.

Root cause

$this->envelope->date is a Horde_Imap_Client_DateTime. When the IMAP layer cannot parse the envelope date, it stores an internal error value and __toString() returns "0":

// Horde_Imap_Client_DateTime
public function __toString()
{
    return $this->error() ? '0' : strval($this->getTimestamp());
}

Previous getDate() logic (after #15’s fix for numeric timestamp strings):

if (is_string($date) && ctype_digit($date)) {
    return new Horde_Date((int) $date);
}
return new Horde_Date((string) $date);

For an error-state envelope date:

  1. $date is an object → the ctype_digit branch is skipped.
  2. (string) $date"0".
  3. Horde_Date("0") does not accept single-digit timestamp strings → DateTime("0") fails → exception → Sync 500.

This is separate from horde/ActiveSync#15, which fixed valid Unix timestamps passed as 9–11 digit strings (e.g. "1773944669").

Solution

public function getDate()
{
    $date = $this->envelope->date;

    if ($date instanceof Horde_Imap_Client_DateTime) {
        if (!$date->error()) {
            return new Horde_Date($date->getTimestamp());
        }

        $date = $this->getHeaders()->getValue('date') ?: null;
    }

    if (is_string($date) && ctype_digit($date)) {
        $ts = (int) $date;
        if ($ts) {
            return new Horde_Date($ts);
        }
        $date = null;
    }

    if ($date) {
        try {
            return new Horde_Date($date);
        } catch (Horde_Date_Exception $e) {
        }
    }

    return new Horde_Date();
}
Case Behavior
Valid Horde_Imap_Client_DateTime new Horde_Date($timestamp)
Unparseable envelope (error()) Parse Date: header; if that fails, use now
Numeric timestamp string (non-zero) new Horde_Date((int) $string) (#15)
Sentinel "0" Treated as invalid → fallbacks above

Sync can complete even when individual messages have malformed envelope dates; datereceived may be approximate only when both envelope and header dates fail.

Related work

Test plan

  • Sync a mailbox that previously triggered Zeitformat (0) nicht erkannt via Outlook or another EAS client; confirm Sync completes without HTTP 500.
  • Confirm messages with normal envelope dates still get correct datereceived.
  • Test a message with a known-bad envelope date but valid Date: header; confirm the header date is used.
  • Test a message with only a numeric timestamp string envelope (regression for Improve date handling in getDate method #15); confirm sync still works.
  • Check Horde logs: no Horde_Date_Exception from getDate() during Sync for the above cases.

Enhance date handling in getDate method to support Horde_Imap_Client_DateTime and improve timestamp parsing.
@TDannhauer TDannhauer requested a review from ralflang May 29, 2026 06:47
@TDannhauer
Copy link
Copy Markdown
Contributor Author

@ralflang please verify whether this is a valid approach, you are deeper in the date corner.

@ralflang ralflang merged commit cfb8f11 into FRAMEWORK_6_0 May 29, 2026
0 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants