I am trying to set up a search facet that provides a filter by a data range. When I enable this facet, I get the following error:
The website encountered an unexpected error. Please try again later.
InvalidArgumentException: The date cannot be created from a format: in Drupal\Component\Datetime\DateTimePlus::createFromFormat() (line 255 of core/lib/Drupal/Component/Datetime/DateTimePlus.php).
Drupal\facets\Plugin\facets\query_type\SearchApiDate->calculateRangeRelative('2024-01-17', 4) (Line: 86)
Drupal\facets\Plugin\facets\query_type\SearchApiDate->calculateRange('2024-01-17') (Line: 32)
...
Here is the output of \DateTimeImmutable::getLastErrors() if I drop that in Drupal/Component/Datetime/DateTimePlus.php
array (
'warning_count' => 0,
'warnings' => array ( ),
'error_count' => 3,
'errors' => array (
10 => 'Unexpected data found.',
16 => 'Data missing',
),
)
It seems to be due to the fact that the Date string is being matching on the incorrect granularity value in calculateRangeRelative(), which seems consistently one less then what it should be.
In the interest of readability, I've refactored the code in here as the following locally.
https://git.drupalcode.org/project/facets/-/blob/2.0.6/src/Plugin/facets...
$counts = count_chars($value, 1);
$ymd = ($counts[ord('-')] ?? 0);
$t = ($counts[ord('T')] ?? 0);
$hms = ($counts[ord(':')] ?? 0);
$granularity = self::FACETAPI_DATE_YEAR - $ymd - $t - $hms;
So for reference, here are the constants for each granularity level:
FACETAPI_DATE_YEAR = 6;
FACETAPI_DATE_MONTH = 5;
FACETAPI_DATE_DAY = 4;
FACETAPI_DATE_HOUR = 3;
FACETAPI_DATE_MINUTE = 2;
FACETAPI_DATE_SECOND = 1;
When I am trying to use a facet with month granularity, the filter parameter still seems to include the individual day value, so if I am trying to filter by a range ending on 2024-01-17, it calculates as such:
$ymd = 2; // Because there are two dashes in 2024-01-17
$t = = 0;
$hms = 0;
$granularity = 6 - 2 - 0 - 0;
So $granularity ends up being equal to 4. When passed to calculateRangeRelative(), in the switch statement there, matches on the 4 = FACETAPI_DATE_MONTH, so then concatenates:
$value . ':00:00'
And tries to pass that result to $dateTime::createFromFormat(). However, since the $value includes only the day granularity, and this concatenation excludes hours, the date string ends up being "2024-01-17:00:00", which is an invalud date format as it is missing the hours component. Which then leads to the error at the beginning of this issue.
I have not yet recreated this in a clean, sandbox environment, and while I couldn't find any other reports of this exact issue, this one seems similar
#3260349: Date item processor: Non-date value on url query string throws 500 β
. Since the error happens all on it's own, without modifying the date string, I thought it might warrant it's own. But I don't exclude the possibility that some patch I'm using, or some specific configuration in my environment may be causing it. I also haven't confirmed if it's still on the dev branch. But I also don't see any major differences in the dev version, even on the 3.0.x branch.
Modifying the code to subtract an extra 1 from the $granularity value before passing to calculateRangeRelative() seems to avoid the error. But that seems overly simplistic.
Potential solution
I'm assuming this is just an off by one error, and when I have the granularity selected to use "month", then it should match on the FACETAPI_DATE_MONTH value in the switch statement. I haven't tested with other granularity values yet myself. I can do that now. But comparing to the calculateRangeAbsolute(), that does use the T values when matching on FACETAPI_DATE_DAY. So maybe the solution is to include those as well in the relative method?