Problem/Motivation

Per https://wiki.php.net/rfc/implicit-float-int-deprecate, as of PHP8.1, type coercion of a float-like variable to integer will result in a PHP E_DEPRECATED and become TypeError in PHP9.

As of 2023-05, The Drupal\Component\Datetime::createFromTimestamp does not declare a type for its $timestamp parameter and relies on using an is_numeric check, however this does not prevent the float-to-int deprecation case from happening.

Steps to reproduce

This has been documented in contrib projects:

ultimate_cron

Deprecated function: Implicit conversion from float-string to int loses precision in Drupal\Component\Datetime\DateTimePlus->__call()
Drupal\Component\Datetime\DateTimePlus->__call('setTimestamp', Array) (Line: 204)
Drupal\Component\Datetime\DateTimePlus::createFromTimestamp(, Object, Array) (Line: 122)
Drupal\Core\Datetime\DateFormatter->format(, 'short') (Line: 52)
Drupal\ultimate_cron\CronJobListBuilder->buildRow(Object) (Line: 126)
Drupal\Core\Config\Entity\DraggableListBuilder->buildForm(Array, Object)

https://www.drupal.org/project/drupal/issues/3264979#comment-14531035

migrate_tools
https://www.drupal.org/project/drupal/issues/3264979#comment-14642373

Proposed resolution

Current state of MR + patches is to cast the $timestamp variable to an integer but not change the method parameter type.

Comment #28 suggests declaring int $timestamp and rely on typechecking.

Remaining tasks

Decide on more strict type declaration for the ::createFromTimestamp method param.

User interface changes

API changes

TBD

Data model changes

Release notes snippet

Issue fork drupal-3264979

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:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

akasake created an issue. See original summary.

jhedstrom’s picture

Status: Active » Needs work

Fix looks good to me, but the patch fails to apply.

ankithashetty’s picture

Status: Needs work » Needs review
FileSize
632 bytes
1010 bytes

Fixed the patch in #1. Issue was with the file path, changed it from a/lib/Drupal/Component/Datetime/DateTimePlus.php to a/core/lib/Drupal/Component/Datetime/DateTimePlus.php.

Thanks!

daffie’s picture

Status: Needs review » Needs work
Issue tags: +Needs tests

I think that it is better change the first line of the method and throw the exception when the $timestamp is not an integer instead of not numeric. We also need a test.

3li’s picture

Just to add that I believe this issue comes from ultimate_cron module.
Created an issue for it:
#3281350: Deprecated function: Implicit conversion from float-string "<float>" to int loses precision

Though i do think that @daffie is correct this should be changed to throw and error with invalid int though I'm sure that will need more testing and possible cause issues in other places.

3li’s picture

Issue tags: +PHP 8.1

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.15 was released on June 1st, 2022 and is the final full bugfix release for the Drupal 9.3.x series. Drupal 9.3.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.4.x-dev branch from now on, and new development or disruptive changes should be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

steinmb’s picture

PHP 8.1 and Drupal 9.4.5

How to reproduce

Go to /admin/structure/migrate/manage/migrate_drupal_7/migrations

Seems to be coming from `migrate_tools`.

Installed 3-part migrate_tools

"name": "drupal/migrate_tools",
"version": "5.1.0",

Dependencies prevent me from testing migrate_tools 6.x that have improved PHP 8.1 support. The wider question is perhaps how core should handle these type of situations?

Deprecated function: Implicit conversion from float 1658930740.677 to int loses precision in Drupal\Component\Datetime\DateTimePlus->__call() (line 360 of core/lib/Drupal/Component/Datetime/DateTimePlus.php).

Drupal\Component\Datetime\DateTimePlus->__call('setTimestamp', Array) (Line: 204)
Drupal\Component\Datetime\DateTimePlus::createFromTimestamp(1658930740.677, Object, Array) (Line: 122)
Drupal\Core\Datetime\DateFormatter->format(1658930740.677, 'custom', 'Y-m-d H:i:s') (Line: 201)
Drupal\migrate_tools\Controller\MigrationListBuilder->buildRow(Object) (Line: 219)
Drupal\Core\Entity\EntityListBuilder->render() (Line: 23)
Drupal\Core\Entity\Controller\EntityListController->listing('migration')
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 564)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 158)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 80)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 58)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 709)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
trickfun’s picture

It works with drupal 9.5-beta.2
Thank you

DantonMariano’s picture

Status: Needs work » Needs review
FileSize
844 bytes
722 bytes

Hi @daffie, I have changed is_numeric to is_int to verify whether the number is an integer, perhaps we could remove the typecast below as logically it would never reach that point if it were not an integer. Testing still needs work.

solideogloria’s picture

I agree that the type cast to int can be removed.

smustgrave’s picture

Status: Needs review » Needs work

Appears there are errors in #10

Also was tagged for tests so moving back to NW for both.

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

Drupal 9.4.9 was released on December 7, 2022 and is the final full bugfix release for the Drupal 9.4.x series. Drupal 9.4.x will not receive any further development aside from security fixes. Drupal 9 bug reports should be targeted for the 9.5.x-dev branch from now on, and new development or disruptive changes should 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.

anacona16’s picture

FileSize
718 bytes

Seems like #10 does not work for other scenarios like:

InvalidArgumentException: The timestamp must be numeric. in Drupal\Component\Datetime\DateTimePlus::createFromTimestamp() (line 201 of core/lib/Drupal/Component/Datetime/DateTimePlus.php).
Drupal\Core\Datetime\DateFormatter->format('1670531360', 'medium', '', 'America/New_York', 'en') (Line: 183)
Drupal\Core\Field\Plugin\Field\FieldFormatter\TimestampFormatter->viewElements(Object, NULL) (Line: 89)

The timestamp is valid, but it's a string. So we can check if it's numeric a if it's cast the value to (int)

anacona16’s picture

anacona16’s picture

Same as #14, fixed to work with a new Drupal installation.

Bhanu951’s picture

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

Bhanu951’s picture

Rerolled to 10.x and queued for retest.
Still needs tests.

smulvih2’s picture

#16 works for me on 9.4.9

quadrexdev’s picture

We also used a patch from #10 on our project and it caused a fatal error: InvalidArgumentException: The timestamp must be numeric. in Drupal\Component\Datetime\DateTimePlus::createFromTimestamp() (line 201 of core/lib/Drupal/Component/Datetime/DateTimePlus.php).

Applying a patch from #16 fixed this issue. Thanks, @anacona16

anacona16’s picture

Status: Needs work » Needs review

Based on the merge in #18 the merge passed the tests.

smustgrave’s picture

Status: Needs review » Needs work

Still needs tests though

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

voleger’s picture

Status: Needs work » Needs review

Added test case with different datatypes of the timestamp passed to the static method.

smustgrave’s picture

Status: Needs review » Reviewed & tested by the community
Issue tags: -Needs tests +Needs Review Queue Initiative

Test does cover the scenario.
Ran locally without the fix and got

Unsilenced deprecation notices (2)

  1x: Implicit conversion from float-string "87654321.1" to int loses precision
    1x in DrupalDateTimeTest::testTimestampArgumentTypes from Drupal\Tests\system\Functional\Datetime

  1x: Implicit conversion from float 87654321.1 to int loses precision
    1x in DrupalDateTimeTest::testTimestampArgumentTypes from Drupal\Tests\system\Functional\Datetime
alexpott’s picture

Status: Reviewed & tested by the community » Needs review

Given this is a public static method it is super tempting to add a typehint to the method and remove the is_numeric check... like

  public static function createFromTimestamp(int $timestamp, $timezone = NULL, $settings = []) {
    $datetime = new static('', $timezone, $settings);
    $datetime->setTimestamp($timestamp);
    return $datetime;
  }

Going to ping release managers and ask for a thought. Also FWIW the calling code could cast to an integer from a float. It shouldn't be passing floats in here. Why is a float being passed in here?

alexpott’s picture

We could tidy up this code in migrate plus to not pass in a float.

        $row['last_imported'] = $date_formatter->format($last_imported / 1000,
          'custom', 'Y-m-d H:i:s');

Because PHP is not going to do the right thing... see https://3v4l.org/HDF4t

smustgrave’s picture

Status: Needs review » Needs work

Probably would make the code cleaner to use typehints vs (int) check.

Tests should still cover that.

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

dpi’s picture

Issue summary: View changes
Issue tags: +Needs issue summary update

Minor formatting.

Can we improve the issue summary a little? such as with standard template

angrytoast’s picture

Issue summary: View changes

Per #32, update issue summary with default template and relevant details

angrytoast’s picture

I see that the newly added tests are in Functional tests Drupal\Tests\system\Functional\Datetime\DrupalDateTimeTest, however there are already existing unit tests in Drupal\Tests\Component\Datetime\DateTimePlusTest::testTimestamp. This looks more appropriate to add to the unit test class as they would be better grouped and much faster?

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.

lathan’s picture

there are a few more references to setTimestamp that have been missed here in this patch

angrytoast’s picture

Regarding comments #28-30 that suggest using type hinting, wouldn't this cause issues for code out in the wild that call the method and currently does not cast the first $timestamp parameter? If we go down this route, should it have a BC layer to warn and eventually enforce the parameter strict typing?

IMO the current approach in https://git.drupalcode.org/project/drupal/-/merge_requests/3254 is more accommodating and would cause less issues for existing implementations.

Thoughts?

solideogloria’s picture

When it's the return type, you can use the ReturnTypeWillChange attribute. I don't think there's something similar for parameters.

Also, this seems relevant: #1158720: Improve text for parameter type hinting in function declaration