DateTime converts wrong when system time is 30 March - php

Assume system time is set to 2017-03-30. Then this code will convert the date wrong:
<?php
$dateTime = DateTime::createFromFormat('m-Y', '02-2017');
$converted = $dateTime->format('Y-m');
print_r($converted);
The value of $converted is
2017-03
but only when run from the browser. Run from command line, it gives the correct result 2017-02.
Anyone knows why? February does not have 30 days, so that might be a reason, but still.
Edit: Changed format from 'Y-m-d' to 'Y-m'.
Edit 2: Added information about command line vs browser.

The rules used by DateTime::__construct(), DateTime::createFromFormat() and strtotime() to parse various date & time formats and the values it uses to fill missing components are explained in the documentation.
When it parses an incomplete date, it uses the values from the current date and time for the missing components.
In your specific case, 02-2017 is converted to "February 2017" using the current day of month (30) for the missing day of month. I.e. 30 February 2017 that is then normalized to 2 March 2017.
You can tell DateTime::createFromFormat() to initialize all the components to the Unix epoch (instead of the current date & time) by placing an exclamation mark (!) in the format string:
$dateTime = DateTime::createFromFormat('!m-Y', '02-2017');
print_r($dateTime);
It outputs:
DateTime Object
(
[date] => 2017-02-01 00:00:00.000000
[timezone_type] => 3
[timezone] => UTC
)

What you have here is over-run. The process goes like this:
1) You give the dateTime object a formatted date, but without a day.
2) The dateTime object then can not use null days so instead uses todays date.
3) You state in your question that todays date is 2017-03-30 therefore to apply this to the given date value of 02-2017 would make:
30-02-2017
4) This is obviously not valid so the dateTime object over-runs this value and turns it into 02-03-2017.
You reqest an output format of Year - Month which gives you 2017-03.
Solution:
Always set a day value in your dates.

Related

start date and end date both are off by 1 day in Google Calendar

I have some php code dynamically generating a .ics file for download. I am passing in a start date value of 08/01/2019 and when it succesfully gets imported into ical / google calendar it is off by one day, despite the epoch timestamp being correct. I am not sure what I am missing here.
I have tried reformatting the date to a different date string, than converting it to the format required for ical and that results in jan 1 1969. I am using the WordPress date_i18n() function to format the date in expected value.
$dateVal; // contains 08/01/2019
$dtstart = date_i18n("Ymd\THis\Z", strtotime( $dateVal) );
// output: 20190801T000000Z
When the event goes into the calendar, it shows my date as july 31st, 2019 at 6pm NOT the expected value of august 1st, 2019
Any ideas how I can debug this?
What I think is happening is this:
Your event is supposed to be at 8/01/2019 in your timezone, which based on the apparent offset seems to be UTC+6.
the \Z in your format string is indicating that the event is at 8/1/2019 in UTC, so when you see it on your calendar, it is adjusted to your timezone, so it gets 8 hours subtracted.
Try leaving off the \Z, I think it should just use your local timezone.
Or convert the time to UTC.
$date = new DateTime($dateVal);
$date->setTimezone(new DateTimeZone('UTC'));
$dtstart = $date->format('Ymd\THis\Z');

PHP DateTime::createFromFormat behavoiur

Today I've encountered something confusing for me with the behaviour of the \DateTime::createFromFormat function.
In my case I have a string, representing the date in the following format m/Y (05/2017). When I want to convert the string to DateTime object I've encountered the following issue:
$date = \DateTime::createFromFormat('m/Y', '02/2017');
When I dump the $date variable, the date property inside is '2017-03-03 11:06:36.000000'
But if I add the date before the month $date = \DateTime::createFromFormat('d/m/Y', '01/02/2017'); I get back an object with correct date property. (unfortunately I cant change the format of the date and add the day. It must be m/Y).
The fix I've come up with is to concatenate the first day of the month to the date string I have $date = '01/'.$dateString; but I rather not to do that because it's hardcoded.
What is wrong here? Does the createFromFormat function lack information of how to create the object? I'm quite confused with this. Thanks for everyone's help in advance!
By default, PHP will populate missing date values with those of the current date/time; so
$date = \DateTime::createFromFormat('m/Y', '02/2017');
will populate the missing day value with the current date; and as 31st February is an invalid date, it will roll forward into March. Likewise, hours/minutes/seconds will be populated with the missing time values based on the current time.
If you want to force the behaviour of forcing to the beginning of the month/time, then modify your mask with a leading !
$date = \DateTime::createFromFormat('!m/Y', '02/2017');
This will populate the missing day with the 1st of the month, and the time with 00:00:00
Alternatively, a trailing | will have the same effect
$date = \DateTime::createFromFormat('m/Y|', '02/2017');
You cannot store incomplete dates, not at least in a dedicated date format that can be used for complex date calculations (nothing prevents you from creating your own MonthYear class). So when you create a DateTime() object with incomplete information something needs to happen:
Crash
Use some default values
PHP opts for the second option and makes a decision inherited from the C language date library:
Assume that missing data means "now"
Try to fix automatically the invalid dates that this algorithm can create
In this case, Feb 2017 becomes 31 Feb 2017 (because "now" is 31 May 2017) and PHP follows this reasoning: February only had 28 days in year 2017 but I have three more; the user probably wants to move these three extra days into March. Thus 3 Mar 2017.
I see no reason to avoid hard-coding 01 because, after all, it is a hard-coded value (why the first day of the month and not the last one or any other day?).
$input = '05/2017';
$date = \DateTime::createFromFormat('d/m/Y', "01/$input");

getTimestamp is not giving the correct hour

I have this PHP code:
$from_date = new DateTime('April-22-2016');
$from_date->format( 'Y-m-d 00:00:00' );
$from_date->setTime(0,0,0);
print ' / '. $from_date_unix = $from_date->getTimestamp();
The above code prints a Unix timestamp of 1461356160, which means
GMT: Fri, 22 Apr 2016 20:16:00 GMT
The hours are 20:16:00 - which is strange, since I already set the time to 00:00:00 via
$from_date->setTime(0,0,0);
Is my code wrong? Do I need to check something in php.ini?
The date you provided as first argument to DateTime::__construct() does not use any of the standard date and time formats understood by PHP. Therefore, it tries to identify the date and time components in the string you provided.
A print_r($from_date) immediately after it was created reveals what PHP (mis-)understood from your date:
DateTime Object
(
[date] => 2016-04-22 00:00:00.000000
[timezone_type] => 1
[timezone] => -20:16
)
Before anything else, when it starts parsing a string for date & time, PHP initialize the new DateTime object with the current date, time and timezone. Then it overwrites the components it identifies in your string as follows:
April was correctly identified as the month name;
22 is the day of the month;
for some reason I don't know now, it set the time of the new object to 00:00:00;
the rest of the string (-2016) was used as timezone offset; i.e. -20:16 hours.
Maybe the way it works sounds silly to you but since you provided it a random string, this is the best it could get out of it.
The next line of your code ($from_date->format( 'Y-m-d 00:00:00' );) produces a string and doesn't modify the DateTime object. Because you don't do anything with the string returned by DateTime::format(), the entire line is a no-op.
The next line ($from_date->setTime(0,0,0);) also doesn't have any effect on $from_date because it's time already is 00:00:00.
Now it's clear why $from_date->getTimestamp() returns the time 20:16 GMT: when it's 00:00 at the timezone with offset -20:16, on the GMT timezone there already is 20:16.
In order to get what you want you need to use the DateTime::createFromFormat() static function:
$from_date = DateTime::createFromFormat(
'!F-d-Y',
'April-22-2016',
new DateTimeZone('GMT')
);
print ' / '. $from_date_unix = $from_date->getTimestamp();
Remark the exclamation mark (!) at the start of the format specifier. It tells PHP to reset all the date and time components to the Unix Epoch. This way the generated date already has the time 00:00:00 and there is no need to set it.
Its output is:
1461283200
You can parse the DateTime object with the right format with DateTime::createFromFormat
Use it like this:
$from_date = DateTime::createFromFormat('!F-d-Y', 'April-22-2016');
$from_date->format( 'Y-m-d 00:00:00' );
print ' / '. $from_date_unix = $from_date->getTimestamp();

Why does 0000-00-00 00:00:00 return -0001-11-30 00:00:00? [duplicate]

This question already has answers here:
How do you explain the result for a new \DateTime('0000-00-00 00:00:00')?
(2 answers)
Closed 7 years ago.
Beforehand, I have read this question:
How to prevent PHP to convert a DateTime object with 0000-00-00 value to -0001-11-30
But I dont get why 0000-00-00 00:00:00 changes to -0001-11-30 00:00:00 when I run this code:
$date = date_create('0000-00-00 00:00:00');
echo date_format($date, 'Y-m-d H:i:s');
When I try it with 0001-00-00 00:00:00 I get:
0000-11-30 00:00:00
and with 0001-01-01 00:00:00 I get:
0001-01-01 00:00:00
and with 0000-00-01 00:00:00:
-0001-12-01 00:00:00
Is there any specific reason why it's always a year/day/month before the nonexisting date?
Is there something wrong with the functions date_create or date_format?
I do notice that the time is displayed the right way and that's probably because the time 00:00:00 exists.
It's like #Mark Baker said, 0000-00-00 00:00:00 is an invalid date, because there is no month zero, no day zero.... so it's month 1 (Jan) - 1 (Dec of previous year) and day 1 - 1 (Goes to last day of previous month, giving 30th November).
If you see close enough about this behavior in date_create. It says DateTime will recognize any number up to 12 as a [month], and any number up to 31 as a [day]; it calculates the resulting date to be [day] days after the start of [month]. This means that when a datetime object is created with more days than are found in that month, the date will be beyond the end of the month. This also applies if the date you're create is invalid date. :)
This is a known issue with DateTime function in php. The datetime function does not have a proper error handling.
Other functions like strtotime does handle it properly.
You can refer this for more reference.
Could be your server timezone, or a time adjustment.
Try (re)setting the timezone
<?php
// get the existing timezone
echo date_default_timezone_get();
// set up the correct one for your location
date_default_timezone_set("Europe/Dublin");
// check if new timezone was applied
echo date_default_timezone_get();
?>
http://php.net/manual/en/function.date-default-timezone-set.php

What date format is this in? (PHP Codeigniter File Helper)

I'm trying to work out what format this date is in!
'date' => int 1342640973
Date today is 18.07.2012
I got it from the get_file_info function in the CI File Helper.
It's a unix timestamp, which is the number of seconds that have elapsed since midnight Coordinated Universal Time (UTC), January 1, 1970, not counting leap seconds.
To get the current timestamp in PHP, you can use time and to convert a timestamp into a human-readable format you can use date.
It's a unix timestamp!
The value you have represent a date/time in seconds since the first of January 1970 (in UTC), it's often referred to as a "unix timestamp" because of it's origin.
Handling this time representation is easily done in PHP, there are native functions made to convert back and to the format.
time () will return the current time in the format specified (unix timestamp), to convert this into a readable string you can use date with the appropriate format-string, as in the below example:
$unix_timestamp = 1342640973;
$now_utimestamp = time ();
print_r (
array (
date ("Y-m-d G:i:s", $unix_timestamp),
date ("Y-m-d G:i:s", $now_utimestamp)
)
);
output on my system:
Array
(
[0] => 2012-07-18 21:49:33
[1] => 2012-07-18 22:18:43
)
Unless you have told PHP which timezone it's currently in (using php.ini or equivalent) you'll need to specify this using the function date_default_timezone_set(), passing it the value of date_default_timezone_get() will try to set it according to your system preferences.
If it's unable to find a correct match UTC will be used per default.
in codeigniter use
unix_to_human(TIMESTAMP)
to get the human readable date, it will require to include date helper

Categories