PHP strtotime without leap-years - php

With regards to this thread, I've developed a partial solution:
function strtosecs($time,$now=null){
static $LEAPDIFF=86400;
$time=strtotime($time,$now);
return $time-(round((date('Y',$time)-1968)/4)*$LEAPDIFF);
}
The function is supposed to get the number of seconds given a string without checking leap-years.
It does this calculating the number of leap-years 1970 [(year-1986)/4], multiplying it by the difference in seconds between a leap-year and a normal year (which in the end, it's just the number of seconds in a day).
Finally, I simply remove all those excess leap-year seconds from the calculated time. Here's some examples of the inputs/outputs:
// test code
echo strtosecs('+20 years',0).'=>'.(strtosecs('+20 years',0)/31536000);
echo strtosecs('+1 years',0).'=>'.(strtosecs('+1 years',0)/31536000);
// test output
630676800 => 19.998630136986
31471200 => 0.99794520547945
You will probably ask why am I doing a division on the output? It's to test it out; 31536000 is the number of seconds in a year, so that 19.99... should be 20 and 0.99... should be a 1.
Sure, I could round it all and get "correct" answer, but I'm worried about the inaccuracies.
Edit1: Since it doesn't seem obvious, my problem is with inveteracies; you just don't ask PHP for 20 years and it gives you 19.99..., right?
Edit2: It all seems to boil down to the part about 1968;
1970; found it accurate in all tests I've tried.
1969; Found it used here (...ex: (2008-1969)/4 = 9.75...) as well as mentioned here. Accurate after the 2nd year (+3 years) onwards.
1968; as detailed below, this is "year zero" of leap years from unix time (1970). It sounds "right" (to me) but it isn't accurate, at all.

Could this be related to the inherent inaccuracy experienced when using PHP to manage floating point numbers?
http://php.net/manual/en/language.types.float.php

You should replace 1968 in your calculation (where does it come from ?) by the origine of unix time : 1970 and you will get more accurate results.
Edit
You have to do an intval to count the number of leapyears which must be an integer :
return $time - (intval( (date('Y', $time) - 1969) / 4) * $LEAPDIFF);
This will give you correct results within the range +0 -> +68 , end of unix time on 32bit machine

Related

Generating random number each week in lua (keeping the same number for the whole week)

I am trying to generate a random multiplier in lua so every new week a new multiplier is chosen.
for example
the first week it could be : 1000 * 1.2
the next week it could be : 1000 * 0.8
and should come from math.random(0.8,1.2)
but I want to keep the random number for the whole week.
I have been able to find a way to do this in php, but when trying to format the date in lua I cant find a way to solve it.
I need the ISO-8601 week-numbering year and the week number.
This php code does exactly this:
<?php
mt_srand((int)date('oW')); //this week date('oW') returns 202114
$number = mt_rand(0.8, 1.2); //from the mt_srand above it will always return 1 on this specific week, even if the script is re-executed
$value = 1000 * $number;
echo $value; //current week returns 1000
?>
Are there any smart people that can crack this? I find it very interesting concept.
Note: I do not want to store it in database which is the reason of doing it this way.
Random number generators in Lua and PHP are different. So, if you want to generate the same random number on both Lua and PHP, you should not use standard RNG from the library. You should write such generator manually instead and implement it on Lua and PHP.
For example, you may implement formula
1000000000 % YYYYWW * YYYYWW % 401 + 800
to get pseudo-random number in the range from 800 to 1200.
This is how you can calculate ISO-8601 week number on Lua 5.3+:
function iso_year_week(time)
-- returns two numbers: iso_year, iso_week (1-53)
local t = os.date("*t", time or os.time())
t.day = t.day + (1 - t.wday) % 7 - 3 -- nearest Thursday
os.time(t) -- normalize all the fields
return t.year, math.ceil(t.yday / 7)
end
function get_YYYYWW_number(time)
return tonumber(string.format("%04d%02d", iso_year_week(time)))
end
mt_rand takes an integer as a parameter. If values between 800 and 1200 are required, these can be used directly.
A timestamp is used to test the algorithm for future weeks.
$weekInFuture = 0; //0 this week, 1 next week for test
mt_srand((int)date('Wo',strtotime("$weekInFuture weeks")));
$value = mt_rand(800, 1200);
echo $value;
This week I get the value 1140. For the next few weeks 1104, 916 ..
If you don't like the values, you can generate other values if you use 'WoW' for date.

What is the Dart/Flutter equivalent of PHP's gmmktime()?

I need to calculate the value in Dart/Flutter, as calculated by the gmmktime() function in PHP.
This is what I was trying till now:
var ms = (DateTime.now().toUtc().millisecondsSinceEpoch)/100;
int ms = DateTime.now().toUtc().millisecondsSinceEpoch;
But both of these approaches give a value, which is not expected by this API in its header, here: https://api.kitewalk.com/#authentication
PHP's gmmktime is documented to return "Unix time", which is the number of seconds since the the "Unix epoch".
Your first approach was almost right, but you didn't convert from milliseconds to seconds correctly. There are 1000 milliseconds in a second, so you need to divide by 1000, not 100. Additionally, whatever you're passing the time to probably expects an integral number of seconds and not a floating point value, so you'll need to use integer division or round the quotient afterward.
Also note that the "Unix epoch" is not time-zone dependent; DateTime.millisecondsSinceEpoch already measures against a fixed point in time, so an explicit conversion to UTC isn't necessary (but it doesn't hurt).
A correct version would be:
var unixTime = DateTime.now().millisecondsSinceEpoch ~/ 1000;

Get current timestamp with milliseconds [duplicate]

This question already has answers here:
How to get current time in milliseconds in PHP?
(16 answers)
Closed 7 years ago.
I want to get current timestamp with milliseconds in PHP something like below, in JavaScript I use Date.now()
1436030635348
I tried something like below:
$time = str_replace(".","",microtime(true));
But sometime it is not working properly. Like it prints one or two digits less.
It can print less digits, because it is a float value. So if you get 1234.0005, that `.0005 actually means 500 microseconds. The zeroes after the 5 are lost because it's still an unformatted float value.
The function microtime is based on the system call gettimeofday(), which also isn't accurate to the microsecond. Commonly it's accurate to 10 microseconds. See also Linux - Is gettimeofday() guaranteed to be of microsecond resolution.
-edit- I see the specs in your question have changed from microseconds to milliseconds.
To get the float value you have as an integer, you can multiply by a value. The float value represents seconds. Multiply by 1000 to get milliseconds or 1,000,000 to get microseconds. Since the specs (now) say milliseconds, you should multiply by 1000. 10k will give you accuracy of 1/10ms = 100μs. A millisecond is one thousandth of a second. A microsecond is one millionth of a seconds.
Long story short, to get the time in integer milliseconds, use this:
$milliseconds = intval(microtime(true) * 1000);
Note: there is a reason why you get the time as a string or a float by default. The reason is that on 32 bit systems, PHP's integer is also 32 bits and is not large enough to contain the timestamp including milliseconds and microseconds. So this solution will only work well on a 64 bit system.
$timeStampData = microtime();
list($msec, $sec) = explode(' ', $timeStampData);
$msec = round($msec * 1000);
$result = $sec . $msec;
Something like this
But note, that js date.now() return time in MILLIseconds, not MICROseconds
I think you just need to use this function to get a Timestamp with micro seconds in PHP:
int microtime ( void )
Use it as shown in the following link, following code snippet shows you how I'd altered it according to be helpful to your question:
<?php
function microtime_microseconds()
{
list($usec, $sec) = explode(" ", microtime());
return round(($usec * 1000) + $sec);
}
$micro_time = microtime_microseconds();
echo $micro_time;
?>
And also for reference regarding to that microtime() PHP function, please visit and read this PHP manual page.

date_diff returning crazy things

Banging my head against the wall today working with dates.
I am looping through a bunch of datetimes and comparing them to the current date to determine how far away they are.
So I am returning things like 'tomorow # 4pm' , 'yesterday at 3pm', 'today at 12pm' , '3 days ago', 'in 3 days' etc.
It all works fine until it gets to around today/tomorow/yesterday.
Date diff is returning silly things like -0 and +0 when it gets to these dates.
My theory is that dates that are lets say... 23 hours in the future, or even 10 hours in the future, even if they take place on the 'next day' are returning as 0 instead of 1.
Unfortunately date_diff doesn't appear to return decimals or allow me to do any sort of rounding.
Here is some sample code:
$difference = $meeting_date->diff($current_date);
$difference = $difference->format('%R%a');
I then check this difference integer to see if it is 0, -1, 1, < -1, or > 1.
I handle the preceding + sign where necessary.
The ones that are supposed to be -1 or +1, are sometimes returning as -0 or +0 (..what?)
Also, -0 is not = 0, but is apparently less then -1 according to PHP.
S.O.S, someone help.
I have read all the related questions, this is not a duplicate and it is not related to that random 6015 error. Also using diff->days is not the answer. This always returns an absolute and not negatives which would be a problem.
Hm... My approach here would be to split the time and date display. Something like this:
$meeting_day = DateTime::createFromFormat($meeting_date->format('Y-m-d'));
// set $today to today's date at 0:00
$diff = $meeting_day->diff($today);
That should give you a useable day-based difference (for rendering today, yesterday, tomorrow etc.).
Instead of comparing days, why not compare time() to another datetime which you can format using strtotime()
time()
You can convert whatever datetime you're comparing to with strtotime()
strtotime()
And now you can compare the difference in the two in seconds and divide as you see fit for days, hours etc

How to subtract two dates, ignoring daylight savings time in PHP?

I'm trying to calculate the number of days between two days, but I'm running into issues with Daylight Savings Time. Here's my code:
function date_diff($old_date, $new_date) {
$offset = strtotime($new_date) - strtotime($old_date);
return $offset/60/60/24;
}
Works fine as long as the days are both within the same DST period:
echo date_diff('3/15/09', '3/18/09'); // 3
But not if they're further apart:
echo date_diff('11/15/08', '3/18/09'); // 122.95833333333
I want an even number of days, and don't care about DST. I suppose I could round the result, but that feels kludgy. Is there a better (easy) way? I don't want to have to write a whole day-parsing-and-counting-avoiding-leap-years thing if I can avoid it.
(Note: this has to run under php 5.1.6, so some of the date features in 5.3 may not be available.)
A bit more info: I'm going to take the offset and add it to other datetimes that are in a db, and I want only the day part to change, not the time part. Turns out rounding won't work, anyway, because when I do the adding it gets off by one hour in the other direction. Maybe there's a better approach to the whole problem....
Force the dates to live into a timezone without Daylight Savings Time, GMT/UTC:
function date_diff($old_date, $new_date) {
$offset = strtotime($new_date . " UTC") - strtotime($old_date . " UTC");
return $offset/60/60/24;
}
echo date_diff('3/15/09', '3/18/09'); // 3
echo date_diff('11/15/08', '3/18/09'); // 123
you could use http://ca3.php.net/date_default_timezone_set to set the timezone to GMT so there will be no offset.
Alternately, you can manually add an offset using the date('I',$timetamp)
if ( date("I") == 1 ) { // "WE ARE MDT";
$timeZone = "MDT";
} else {
$timeZone = "MST";
}
You can force rounding in a specific direction by using floor() or ceil().
I tried the 'UTC' code above. Didnt work for me. I stll got decimal values.
When there is daylight saving date within the date range the difference serial decimal portion will be either under .5 or over. when date range has day light saving going on 3/15 the decimal value is > .5 when daylight is going off date decimal < .5. so I just put the difference serial in a round() function and I get the whole numbers i need for number of days.

Categories