📜 ⬆️ ⬇️

PHP: TO_DAYS () function port from MySQL

Once I needed an analogue of the function TO_DAYS () in PHP. I, naively, thought that among the huge set of functions, there must be an implementation of TO_DAYS () from MySQL. But my searches were in vain. I rummaged Google, but did not find the implementation I needed. Everything I found was from the category

define ("SECONDS_PER_DAY", 86400);
$ now = (int) (time () / SECONDS_PER_DAY);

I did not accept this approach.
First, this solution counted the days relative to the beginning of the UNIX epoch, and in MySQL it is from the date of the 0000-00-00, that is, the numbers, to put it mildly, did not coincide. One could, of course, add the number of days before the beginning of the UNIX epoch, but this would greatly reduce the range of valid dates.
Secondly, it did not take into account the fact that in some days it was 23 hours, and in some days 25 (during the transition to summer and winter time).
In addition, the timestamp can not say exactly what the number is now without knowing the time zone (although this is not a particular problem).
')
The most important criterion was the coincidence of the results of the function with the results of TO_DAYS () from MySQL. Well, if so, then I went to look for this function in the source code of MySQL itself. With a grief in half, I found the calc_daynr function, which the Item_func_to_days :: val_int () function calls to count these days.

After some simple conversion, the code written in C was turned into PHP code. I upgraded the input parameters a bit to reflect the latest trends in working with date in PHP, and got the following function:

<?
define ( "YY_PART_YEAR" , 70 );
define ( "YY_MAGIC_BELOW" , 200 );

function to_days ( DateTime $ date )
{
$ year = $ date -> format ( "Y" );
$ month = $ date -> format ( "m" );
$ day = $ date -> format ( "d" );

if ( $ year == 0 && $ month == 0 && $ day == 0 )
{
return 0 ;
}
if ( $ year < YY_MAGIC_BELOW )
{
if (( $ year = $ year + 1900 ) < 1900 + YY_PART_YEAR )
{
$ year + = 100 ;
}
}
$ delsum = 365 * $ year + 31 * ( $ month - 1 ) + $ day ;
if ( $ month <= 2 )
{
$ year -;
}
else
{
$ delsum - = floor (( $ month * 4 + 23 ) / 10 );
}
$ temp = floor (( floor ( $ year / 100 ) + 1 ) * 3/4 );
return floor ( $ delsum + $ year / 4 - $ temp );
}
?>

If you think that I fully understand this code, then you are mistaken. What is this at least worth:

$ delsum - = floor (( $ month * 4 + 23 ) / 10 );

But this is not required at this stage, the main thing is to work.
I checked for a match with TO_DAYS () from 1700 to 2300 - not a single error.
So if anyone needs, use on health.

PS Now you need to do the same for FROM_DAYS (). Then I will share, if there will be something :)

Source: https://habr.com/ru/post/49537/


All Articles