Date Range granularity throws exception. Off by one error when using relative dates?

Created on 18 July 2023, over 1 year ago
Updated 12 March 2024, 12 months ago

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?

πŸ› Bug report
Status

Needs review

Version

2.0

Component

Code

Created by

πŸ‡ΊπŸ‡ΈUnited States bburg Washington D.C.

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

  • Issue created by @bburg
  • πŸ‡ΊπŸ‡ΈUnited States bburg Washington D.C.

    I did some more testing, and this does seem to be an issue with other dates, and on the 2.0.x branch.

    It just adds the 1 to the granularity value when using the relative date range method. But I understand if the maintainers would prefer to examine how things are handled directly in calculateRangeRelative() instead.

    I also took the liberty of adding a try/catch block to catch the InvalidArgumentException and log that, as well as adding the use statements to import that exception class, and the Drupal class since I used to to log the error.

  • Status changed to Needs review over 1 year ago
  • Open in Jenkins β†’ Open on Drupal.org β†’
    Core: 9.5.x + Environment: PHP 8.0 & MySQL 5.7
    last update over 1 year ago
    424 pass, 2 fail
  • πŸ‡ΊπŸ‡ΈUnited States bburg Washington D.C.
  • πŸ‡¨πŸ‡·Costa Rica alemadlei

    #2 worked for me

Production build 0.71.5 2024