So, I have the code as it follows:
$dateBase = $amount->getDate();
for ($i = 1; $i <= 3; $i++) {
$installment = new Installment();
if ($i == 1) {
//do stuff
} else {
var_dump('1-'.$dateBase->toString());
$dateBase->addMonth(1);
var_dump('2-'.$dateBase->toString());
}
$installment->setDate($dateBase);
$dataBase = clone $dataBase;
}
And the output is:
string(25) "1-Oct 1, 2014 12:00:00 AM"
string(25) "2-Dec 1, 2014 12:00:00 AM"
string(25) "1-Dec 1, 2014 12:00:00 AM"
string(26) "2-Jan 31, 2015 12:00:00 AM"
You can see that in the second loop(when $i=2), he adds 2 months intead of just one
EDIT1: Doeing some more research, I think there is timezone bug, i changed the code as it follows
$date = new Zend_Date('10/1/2014');
var_dump($date);
$date->addMonth(1);
var_dump($date, $dateBase);
$dateBase->addMonth(1);
var_dump($dateBase);
and the output is at it follows:
object(Zend_Date)#3754 (8) {
["_locale":"Zend_Date":private]=>
string(2) "en"
["_fractional":"Zend_Date":private]=>
int(0)
["_precision":"Zend_Date":private]=>
int(3)
["_unixTimestamp":"Zend_Date_DateObject":private]=>
string(10) "1412114400"
["_timezone":"Zend_Date_DateObject":private]=>
string(12) "Europe/Paris"
["_offset":"Zend_Date_DateObject":private]=>
int(-3600)
["_syncronised":"Zend_Date_DateObject":private]=>
int(0)
["_dst":protected]=>
bool(true)
}
object(Zend_Date)#3754 (8) {
["_locale":"Zend_Date":private]=>
string(2) "en"
["_fractional":"Zend_Date":private]=>
int(0)
["_precision":"Zend_Date":private]=>
int(3)
["_unixTimestamp":"Zend_Date_DateObject":private]=>
int(1414796400)
["_timezone":"Zend_Date_DateObject":private]=>
string(12) "Europe/Paris"
["_offset":"Zend_Date_DateObject":private]=>
int(-3600)
["_syncronised":"Zend_Date_DateObject":private]=>
int(0)
["_dst":protected]=>
bool(true)
}
object(Zend_Date)#3755 (8) {
["_locale":"Zend_Date":private]=>
string(2) "en"
["_fractional":"Zend_Date":private]=>
int(0)
["_precision":"Zend_Date":private]=>
int(3)
["_unixTimestamp":"Zend_Date_DateObject":private]=>
string(10) "1412114400"
["_timezone":"Zend_Date_DateObject":private]=>
string(9) "Etc/GMT-2"
["_offset":"Zend_Date_DateObject":private]=>
int(-7200)
["_syncronised":"Zend_Date_DateObject":private]=>
int(0)
["_dst":protected]=>
bool(true)
}
object(Zend_Date)#3755 (8) {
["_locale":"Zend_Date":private]=>
string(2) "en"
["_fractional":"Zend_Date":private]=>
int(0)
["_precision":"Zend_Date":private]=>
int(3)
["_unixTimestamp":"Zend_Date_DateObject":private]=>
string(10) "1417384800"
["_timezone":"Zend_Date_DateObject":private]=>
string(9) "Etc/GMT-2"
["_offset":"Zend_Date_DateObject":private]=>
int(-7200)
["_syncronised":"Zend_Date_DateObject":private]=>
int(0)
["_dst":protected]=>
bool(true)
}
You can see that there is no difference between $date and $dataBase date, just the timezone, but when we add one month to both, they react differently, $dateBase was added an extra month
Zend Framework 1.12 Documentation Says Something like this:
For example, When adding one month to January 31st, people familiar with SQL will expect February 28th as the result. On the other side, people familiar with Excel and OpenOffice will expect March 3rd as the result. The problem only occurs, if the resulting month does not have the day, which is set in the original date.
Check out this Link if you dont know about this:
http://framework.zend.com/manual/1.12/en/zend.date.overview.html
Related
I want to create a DateTime object from a millisecond timestamp but that does not seem to work:
$timestamp_in_ms = 1546300800000; // int or string no difference
var_dump(DateTime::createFromFormat("Uv", $timestamp_in_ms));
var_dump(DateTime::getLastErrors());
This results in:
bool(false)
array(4) {
["warning_count"]=>
int(0)
["warnings"]=>
array(0) {
}
["error_count"]=>
int(1)
["errors"]=>
array(1) {
[13]=>
string(12) "Data missing"
}
}
However if I use a slightly different notation it does work:
$timestamp_in_ms = "1546300800.000";
var_dump(DateTime::createFromFormat("U\.v", $timestamp_in_ms));
var_dump(DateTime::getLastErrors());
object(DateTime)#1 (3) {
["date"]=>
string(26) "2019-01-01 00:00:00.000000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
Yes I can do something like this:
$timestamp_with_dot = $timestamp_in_ms / 1000 + "." + $timestamp_in_ms % 1000;
The documentation does not provide any insight in this. Both U and v are supported.
Anybody more info on this issue? I am running PHP 7.4.10
With a division by 1000 you can convert your millisecond timestamp as a float in seconds.
$msTimeStamp = 1600790571478;
$floatSec = $msTimeStamp/1000.0;
When using DateTime::createFromFormat, you can also use the "U.u" format. The "u" format should be exactly 6 characters. This can be done with sprintf().
$dateTime = DateTime::createFromFormat("U\.u", sprintf('%1.6F',$floatSec));
//test
echo $dateTime->format('Y-m-d H:i:s.u');
//2020-09-22 16:02:51.478000
//Timezone "+00:00" (UTC)
The millisecond timestamp can also be a float and also contain microseconds.
The above code works on 32-bit systems too.
I need to create one date using only month and year.
I'm using this code:
$mData="1 2003";
$mDate=DateTime::createFromFormat("n Y", $mData);
var_dump($mDate);
Output in this case is fine:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2003-01-10 15:43:33.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
Now I try with one month that not exists:
$mData="21 2003";
$mDate=\DateTime::createFromFormat("n Y", $mData);
var_dump($mDate);
Output is one date of september 2004!:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2004-09-10 15:45:26.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
Why in this case $mDate is not false o any error occours?
It's not possible to create one valid DateTime object in this way controlling erroneus dates.
In my scenario I can't to change the format "n Y" by another format, then I need to achieve this controlling errors? It's possible?
Now I try with one month that not exists 21
21 = 12 + 9 = 1y + 9m
Which is exactly what you are getting
string(26) "2004-09-10 15:45:26.000000"
As the other answer points out, the behavior is the behavior, so you can check yourself:
$mData = "21 2003";
$a = explode(' ', $mData);
var_dump(
checkdate($a[0], 1, $a[1])
);
You can check if the year from the DateTime Object is the same as the year of the input:
$mData = "13 2003";
$mDate = \DateTime::createFromFormat ("!n Y", $mData);
$error = ($mDate === false OR strpos($mData, $mDate->format('Y')) < 2) ;
var_dump($error); //bool(true)
or you use date_get_last_errors(). This function provides a warning that you can evaluate.
$mData = "21 2003";
$mDate = \DateTime::createFromFormat ("!n Y", $mData);
var_dump(date_get_last_errors());
output:
array(4) {
["warning_count"]=>
int(1)
["warnings"]=>
array(1) {
[7]=>
string(27) "The parsed date was invalid"
}
["error_count"]=>
int(0)
["errors"]=>
array(0) {
}
}
Note:
The format "!n Y" results in a date with day 1 and time 00:00.
$mData = "5 2003";
$mDate = \DateTime::createFromFormat ("!n Y", $mData);
$error = ($mDate === false OR strpos($mData, $mDate->format('Y')) < 2) ;
var_dump($mDate,$error);
Output:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2003-05-01 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
string(13) "Europe/Berlin"
}
bool(false)
I need to use date_default_timezone_set for my project and it all worked fine until I started using date_diff, as it is producing good and false results depending on the chosen timezone.
An example:
date_default_timezone_set('America/Los_Angeles');
$first = date_create("2016-10-01");
$last = date_create("2016-10-31");
$diff = date_diff($first, $last);
echo $diff->d;
The result is 30, which is correct.
Now, If I set the timezone to Europe:
date_default_timezone_set('Europe/London');
The result is 0.
What's going on?
If you var_dump($diff) you will see that the days has reset to zero and month has incremented to 1:
object(DateInterval)#3 (15) {
["y"]=>
int(0)
["m"]=>
int(1)
["d"]=>
int(0)
["h"]=>
int(0)
["i"]=>
int(0)
["s"]=>
int(0)
["weekday"]=>
int(0)
["weekday_behavior"]=>
int(0)
["first_last_day_of"]=>
int(0)
["invert"]=>
int(0)
["days"]=>
int(30)
["special_type"]=>
int(0)
["special_amount"]=>
int(0)
["have_weekday_relative"]=>
int(0)
["have_special_relative"]=>
int(0)
}
This is probably due to the fact that London switches back from DST on the last Sunday in October. However the date difference is calculated that apparently makes it a "month" as opposed to 30 days.
You can overcome this by using the days property which is will report 30:
$first = date_create("2016-10-01");
$last = date_create("2016-10-31");
$diff = date_diff($first, $last);
echo $diff->days;
So I'm trying to convert milliseconds to date in PHP and I thought the script I had was working fine but getting odd behaviour for a specific millisecond value (1425318722000).
I've checked this across a few websites and all come back with a valid value...
Monday, March 2, 2015 5:52:02 PM GMT
Mon Mar 02 2015 17:52:02
Mon Mar 02 2015 17:52:02 GMT+0000 (GMT)
Mon, 02 Mar 2015 17:52:02 GMT
Any idea why this occurs, is it a PHP bug perhaps?
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318721999/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:01"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722000/1000));"
bool(false)
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722001/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722002/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722003/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722004/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
php -r "var_dump(DateTime::createFromFormat('U.u', 1425318722005/1000));"
object(DateTime)#1 (3) {
["date"]=>
string(19) "2015-03-02 17:52:02"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+00:00"
}
It's the fact that you're using the 'U.u' mask, but the .u is lost from the value when the result is all 0s after the decimal for that division
for($ms = 1425318721999; $ms <= 1425318722001; ++$ms) {
var_dump(DateTime::createFromFormat('U.u', sprintf('%14.3f', $ms/1000)));
}
Will work, because you're using sprintf() to force those zeroes to be retained after the decimal point
for($ms = 1425318721999; $ms <= 1425318722001; ++$ms) {
var_dump(DateTime::createFromFormat('U', floor($ms/1000)));
}
would also work, but you'd lose the milliseconds precision
By way of some explanation:
public static DateTime DateTime::createFromFormat ( string $format , string $time [, DateTimeZone $timezone ] )
the createFromFormat() expects a string as the second argument, so PHP is loose casting the result of your division to a string, and a float value like 1425318722.000 will be cast to a string of "1425318722" with no decimal point or following zeroes, so it doesn't conform with the U.u mask which requires the decimal point and following digits
I have a string in this format: 2013-07-31T19:20:30.45-07:00 and I want to parse it so that I can, for example, say what day of the week it is. But I'm struggling to cope with the timezone offset. If I do date_parse("2013-07-31T19:20:30.45-07:00") then I end up with something like this:
array(15) {
["year"]=> int(2013)
["month"]=> int(7)
["day"]=> int(31)
["hour"]=> int(19)
["minute"]=> int(20)
["second"]=> int(30)
["fraction"]=> float(0.45)
["warning_count"]=> int(0)
["warnings"]=> array(0) { }
["error_count"]=> int(0)
["errors"]=> array(0) { }
["is_localtime"]=> bool(true)
["zone_type"]=> int(1)
["zone"]=> int(420)
["is_dst"]=> bool(false)
}
It's done something with the timezone, but what do I do with 420 if I want to, for example, show information about the timezone?
In case it matters, I have previously set my default timezone using date_default_timezone_set('UTC').
UPDATE: If the string has a positive timezone, eg 2013-07-31T19:20:30.45+07:00 then the last part of the date_parse() output is:
["is_localtime"]=> bool(true)
["zone_type"]=> int(1)
["zone"]=> int(-420)
["is_dst"]=> bool(false)
}
420 is zone in minutes.
420/60 = 7
I want to parse it so that I can, for example, say what day of the
week it is.
If you want to know what day of the week it is, you have many options. For example you can use date and mktime-functions:
$parsed = date_parse("2013-07-31T19:20:30.45-07:00");
$unix_timestamp = mktime($parsed['hour'], 0, 0, $parsed['month'], $parsed['day'], $parsed['year'], (int)$parsed['is_dst']);
echo date('l', $unix_timestamp);
So you want to show the information about timezone? You can get the time zone name by using timezone_name_from_abbr function:
$name = timezone_name_from_abbr("", -1*$parsed['zone']*60, false); // NB: Offset in seconds!
var_dump($name);
$timezone = new DateTimezone($name);
var_dump($timezone);
2013-07-31T19:20:30.45-07:00
^ y-m-d ^ time ^ timezone offset
I'm guessing the timezone is -7 hours from UTC.
Keep in mind that some countries have half-hour timezones, or even minute timezones. This is probably why you get the timezone in minutes.