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.
Related
Awkward problem -> I'm trying to get current date&time in ISO 8601 format (like this: 2022-02-11 12:30:02.846108).
When I run $time = new Time('now', 'Europe/Amsterdam') in CI4, $time returns this:
object(CodeIgniter\I18n\Time)#79 (6)
{ ["timezone":protected]=> object(DateTimeZone)#80 (2)
{ ["timezone_type"]=> int(3)
["timezone"]=> string(16) "Europe/Amsterdam"
}
["locale":protected]=> string(2) "en"
["toStringFormat":protected]=> string(19) "yyyy-MM-dd HH:mm:ss"
["date"]=> string(26) "2022-02-11 12:30:02.846108"
["timezone_type"]=> int(3)
["timezone"]=> string(16) "Europe/Amsterdam"
}
but when i try to get $time->date returns NULL.
Any ideea how to access date string in order to get the current time with microseconds?
Found out there is no ->date attribute in the DateTime object, which is why $time->date returns NULL.
The proper way to get the date with microseconds is:
$time->format('Y-m-d\TH:i:s.u')
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'm using the following format Y-m-d\TH:i:s.v\Z to follow the JavaScript toISOString implementation (2011-10-05T14:48:00.000Z).
Everything works fine if I have a DateTime and I want to format it, however I cannot parse a string that uses this format.
$format = 'Y-m-d\TH:i:s.v\Z';
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create_from_format($format,$stringDateTime));
I'm using PHP 7 and I have tested the code above with PHP 7.0,7.1 and 7.2. The return that I expect in line 3 is a DateTime class, however I'm getting a false due to there is a parse problem.
I hope someone can clarify this behavior.
Thanks
Datetime will handle it fine, you won't need to create from format.
<?php
$format = 'Y-m-d\TH:i:s.v\Z';
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create($stringDateTime));
https://3v4l.org/phLE1
Result:
object(DateTime)#1 (3) {
["date"]=>
string(26) "2018-03-13 18:07:30.005000"
["timezone_type"]=>
int(2)
["timezone"]=>
string(1) "Z"
}
This also works:
<?php
$format = 'Y-m-d\TH:i:s.u\Z';
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create_from_format($format, $stringDateTime));
$format = \DateTime::ISO8601;
$stringDateTime = (new \DateTime())->format($format);
var_dump(date_create_from_format($format, $stringDateTime));
https://3v4l.org/FcUqe
object(DateTime)#1 (3) {
["date"]=>
string(26) "2018-03-13 18:15:10.011717"
["timezone_type"]=>
int(3)
["timezone"]=>
string(16) "Europe/Amsterdam"
}
object(DateTime)#1 (3) {
["date"]=>
string(26) "2018-03-13 18:15:10.000000"
["timezone_type"]=>
int(1)
["timezone"]=>
string(6) "+01:00"
}
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
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.