watchdog error:
TypeError: round(): Argument #1 ($num) must be of type int|float, string given in round() (line 173 of /xxx_proj_folder/docroot/core/modules/views/src/Plugin/views/field/NumericField.php)
#0 /xxx_proj_folder/docroot/core/modules/views/src/Plugin/views/field/NumericField.php(173): round('2021-06-29', 0)

code:
$value = round($value, $precision);
value is string '2021-06-29' (just example)

if php version is 7, it will return '2021' and no error,
php 8 will throw this error.

related issue:
https://www.drupal.org/project/drupal/issues/3151654

Repro steps

Show the most recent log item that references each event.

1. Create content types for Event and Log.
2. Add a reference field to Log that references Event.
3. Add a date field to the Log.
4. Create a view that lists Logs.
5. Add the Event reference field, formatted as a linked label.
6. Add the Log date field.
7. Enable aggregation.
8. Set Max on the date field.

Here is where views throws the error in the browser console and things start breaking.

Issue fork drupal-3302573

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

  • 3302573-2 Comparecompare
  • 3302573-php8--max Comparecompare

Comments

caohan@ciandt.com created an issue. See original summary.

caohan@ciandt.com’s picture

Add patch for temporary solution.

vlad.dancer’s picture

Status: Active » Needs review
vlad.dancer’s picture

+++ docroot/core/modules/views/src/Plugin/views/field/NumericField.php
@@ -169,6 +169,12 @@
+        $value = date("Y",strtotime($value));

I think you need to cast date result into int: $value = (int) date("Y",strtotime($value));
But that might work only for you because others could have a different date format and separator like "/".

+++ docroot/core/modules/views/src/Plugin/views/field/NumericField.php
@@ -169,6 +169,12 @@
     $value = round($value, $precision);

I would say that it is safe to do casting here instead of creating a new condition because it is exactly what PHP 7 did before and let's follow old code behaviour here.
$value = round((int) $value, $precision);

vlad.dancer’s picture

Status: Needs review » Needs work

Tests failed due to code quality checks failed.

anchal_gupta’s picture

fix cs error #2. Please review it

anchal_gupta’s picture

vlad.dancer’s picture

Status: Needs work » Needs review

Let's trigger tests

ambot112 made their first commit to this issue’s fork.

nanobyt3’s picture

#7 seems to work for me, at least where 'year' is being used.
PHP 8 & MySQL 5.7

nanobyt3’s picture

Just a minor change to date-string check condition, for better coverage.

smustgrave’s picture

Status: Needs review » Needs work

Moving back to NW for a test.

vlad.dancer’s picture

Version: 9.4.x-dev » 9.5.x-dev
StatusFileSize
new659 bytes

I would leave here an alternative fix for date cases like "2021/2022"

nanobyt3’s picture

This would work too.
I would suggest something like:

if (is_string($value)) {
  $value = (int) $value;
}

else we are ignoring $precision completely.

vlad.dancer’s picture

Then it might looks like

if (is_string($value)) {
  if (strtotime($value) !== FALSE) {
    $value = date("Y", strtotime($value));
  }
  else {
    $value = (int) $value;
  }
}

nanobyt3’s picture

Actually, it would be easier to mimic how PHP v7.x handled it.
After doing some tests, it seems a simple type cast should be sufficient.
So as not to handle the string with any assumptions and in a more generalized way.

if (is_string($value)) {
  $value = (float) $value;
}

Attaching the effective patch.

Just some thoughts: Since this is a render/display utility function, there could be a more agreed-upon way to display a string, passed through an aggregating function.

nanobyt3’s picture

narendra.rajwar27’s picture

Status: Needs work » Needs review
StatusFileSize
new612 bytes

Re-rolled patch for Drupal 9.5.x

hipp2bsquare’s picture

I tested patch #18 on Drupal 9.4.6 and php 8.1 and it worked for me -- though my issue was related to a text field rather than date field. Same error message, though.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests, +Needs steps to reproduce, +Needs Review Queue Initiative

This still needs a test case

Also would be helpful to have steps to reproduce this issue.

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

mortona2k’s picture

Issue summary: View changes

I added steps to create a view that triggers the error and is fixed with this patch.

mortona2k’s picture

There are two very different approaches in the patches here.

#11 has:

+    if (is_string($value)) {
+      if (strtotime($value) !== FALSE) {
+        $value = date("Y", strtotime($value));
+      }
+    }

This will convert date strings to year.

#18 has:

+    if (is_string($value)) {
+      $value = (float) $value;
+    }

This will convert a date string to to a number like 2025.0.

A patch in #3338895 has:

+    $value = round((float) $value, $precision);

Basically the same as #18, without the check for a string.

I bundled them all together and came up with this:

    if (is_string($value)) {
      if (strtotime($value) !== FALSE) {
        $value = date("U", strtotime($value));
      }
    }

    $value = round((float) $value, $precision);

Now a date string is converted to a timestamp. However, I'm not sure if this does anything for the max comparison, or if this just rendering the value afterwards.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.