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
| Comment | File | Size | Author |
|---|---|---|---|
| #43 | 3264979-43.patch | 3.81 KB | jsutta |
Issue fork drupal-3264979
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:
Comments
Comment #2
jhedstromFix looks good to me, but the patch fails to apply.
Comment #3
ankithashettyFixed the patch in #1. Issue was with the file path, changed it from
a/lib/Drupal/Component/Datetime/DateTimePlus.phptoa/core/lib/Drupal/Component/Datetime/DateTimePlus.php.Thanks!
Comment #4
daffie commentedI 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.
Comment #5
3liJust 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.
Comment #6
3liComment #8
steinmb commentedPHP 8.1 and Drupal 9.4.5
How to reproduce
Go to
/admin/structure/migrate/manage/migrate_drupal_7/migrationsSeems to be coming from `migrate_tools`.
Installed 3-part migrate_tools
Dependencies prevent me from testing migrate_tools
6.xthat have improved PHP 8.1 support. The wider question is perhaps how core should handle these type of situations?Comment #9
trickfun commentedIt works with drupal 9.5-beta.2
Thank you
Comment #10
dantonmariano commentedHi @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.
Comment #11
solideogloria commentedI agree that the type cast to int can be removed.
Comment #12
smustgrave commentedAppears there are errors in #10
Also was tagged for tests so moving back to NW for both.
Comment #14
anacona16 commentedSeems like #10 does not work for other scenarios like:
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)
Comment #15
anacona16 commentedComment #16
anacona16 commentedSame as #14, fixed to work with a new Drupal installation.
Comment #17
bhanu951 commentedComment #19
bhanu951 commentedRerolled to 10.x and queued for retest.
Still needs tests.
Comment #20
smulvih2#16 works for me on 9.4.9
Comment #21
quadrexdevWe 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
Comment #22
anacona16 commentedBased on the merge in #18 the merge passed the tests.
Comment #23
smustgrave commentedStill needs tests though
Comment #26
volegerAdded test case with different datatypes of the timestamp passed to the static method.
Comment #27
smustgrave commentedTest does cover the scenario.
Ran locally without the fix and got
Comment #28
alexpottGiven this is a public static method it is super tempting to add a typehint to the method and remove the is_numeric check... like
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?
Comment #29
alexpottWe could tidy up this code in migrate plus to not pass in a float.
Because PHP is not going to do the right thing... see https://3v4l.org/HDF4t
Comment #30
smustgrave commentedProbably would make the code cleaner to use typehints vs (int) check.
Tests should still cover that.
Comment #32
dpiMinor formatting.
Can we improve the issue summary a little? such as with standard template
Comment #33
angrytoast commentedPer #32, update issue summary with default template and relevant details
Comment #34
angrytoast commentedI see that the newly added tests are in Functional tests
Drupal\Tests\system\Functional\Datetime\DrupalDateTimeTest, however there are already existing unit tests inDrupal\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?Comment #36
roam2345 commentedthere are a few more references to setTimestamp that have been missed here in this patch
Comment #37
angrytoast commentedRegarding 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
$timestampparameter? 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?
Comment #38
solideogloria commentedWhen it's the return type, you can use the
ReturnTypeWillChangeattribute. I don't think there's something similar for parameters.Also, this seems relevant: #1158720: Improve text for parameter type hinting in function declaration
Comment #39
tobiasbFyi: 8.4 comes with native
\DateTime::createFromTimestamp, which allows int|float. https://github.com/php/php-src/commit/88f2dc626862b4c40ea20b8029838a8d0d....Output in 8.4.6:
So the best is to follow php-core.
Comment #40
tobiasbOk, forget it.
setTimestampwants a int. Unless we are calling the originDateTime::createFromTimestampin >= php8.4.I move the test to the unit test.
Comment #41
smustgrave commentedLooking at the summary it appears to need work.
But I think #28 is still worth following and if a none int is passed throw a deprecation error.
Comment #43
jsutta commentedI rebased the MR against its current target branch (main). Unfortunately that means it's no longer installing for sites on Drupal 10.x. Attaching a Drupal 10.x-compatible patch to this comment in case anyone needs it.