<?php

final class PhabricatorSearchDateField
  extends PhabricatorSearchField {

  protected function newControl() {
    return new AphrontFormTextControl();
  }

  protected function getValueFromRequest(AphrontRequest $request, $key) {
    return $request->getStr($key);
  }

  public function getValueForQuery($value) {
    return $this->parseDateTime($value);
  }

  protected function validateControlValue($value) {
    if (!strlen($value)) {
      return;
    }

    $epoch = $this->parseDateTime($value);
    if ($epoch) {
      return;
    }

    $this->addError(
      pht('Invalid'),
      pht('Date value for "%s" can not be parsed.', $this->getLabel()));
  }

  protected function parseDateTime($value) {
    if (!strlen($value)) {
      return null;
    }

    // If this appears to be an epoch timestamp, just return it unmodified.
    // This assumes values like "2016" or "20160101" are "Ymd".
    if (is_int($value) || ctype_digit($value)) {
      if ((int)$value > 30000000) {
        return (int)$value;
      }
    }

    return PhabricatorTime::parseLocalTime($value, $this->getViewer());
  }

  protected function newConduitParameterType() {
    return new ConduitEpochParameterType();
  }

}

<?php

final class PhabricatorSearchDateField
  extends PhabricatorSearchField {

  protected function newControl() {
    return id(new AphrontFormTextControl())
      ->setPlaceholder(pht('"2022-12-25" or "7 days ago"...'));
  }

  protected function getValueFromRequest(AphrontRequest $request, $key) {
    return $request->getStr($key);
  }

  public function getValueForQuery($value) {
    return $this->parseDateTime($value);
  }

  protected function validateControlValue($value) {
    if (!strlen($value)) {
      return;
    }

    $epoch = $this->parseDateTime($value);
    if ($epoch) {
      return;
    }

    $this->addError(
      pht('Invalid'),
      pht('Date value for "%s" can not be parsed.', $this->getLabel()));
  }

  protected function parseDateTime($value) {
    if (!strlen($value)) {
      return null;
    }

    // If this appears to be an epoch timestamp, just return it unmodified.
    // This assumes values like "2016" or "20160101" are "Ymd".
    if (is_int($value) || ctype_digit($value)) {
      if ((int)$value > 30000000) {
        return (int)$value;
      }
    }

    return PhabricatorTime::parseLocalTime($value, $this->getViewer());
  }

  protected function newConduitParameterType() {
    return new ConduitEpochParameterType();
  }

}

Add a discovery format hint for date fields in SearchEngine UIs
Add a discovery format hint for date fields in SearchEngine UIs

Summary:
See PHI316. Maniphest and other applications currently have controls like `Created After: [_____]` where you just get an empty text field.

Although most formats work -- including relative formats like "3 days ago" -- and we validate inputs so you get an error if you enter something nonsensical, this still isn't very user friendly.

T8060 or some other approach is likely the long term of this control.

In the meantime, add placeholder text to suggest that `YYYY-MM-DD` or `X days ago` will work.

Test Plan: Viewed date inputs, saw placeholder text.

Reviewers: amckinley

Reviewed By: amckinley

Differential Revision: https://secure.phabricator.com/D18942
