Why PHP does not parse “BRST” dates anymore? - php

BRST refers to "Brasília Summer Time"
Before version 7.0.26, PHP could parse this string without any problem:
$date = DateTime("Mon Jan 01 20:00:00 BRST 2017");
After that version, PHP returns:
Fatal error: Uncaught Exception: DateTime::__construct(): Failed to
parse time string (Mon Jan 01 20:00:00 BRST 2017) at position 4 (J):
The timezone could not be found in the database in /in/c6K56:5
Stack trace:
#0 /in/c6K56(5): DateTime->__construct('Mon Jan 01 20:0...')
#1 {main}
thrown in /in/c6K56 on line 5
Process exited with code 255.
I searched in changelogs, but I couldn't find any explanation for that.
Here is the example:
https://3v4l.org/c6K56#v7026

You can see in this commit the timezonemap.h file was updated to remove the references to brst along with many other abbreviations.
The commit message reads:
Update timezonemap.h, which needs to match the bundled TZ db
Digging deeper (thanks #JamesThorpe) you can see the abbreviations were introduced in July 1999 by Paul Eggert. Notably he claims to have invented these himself:
I invented the English-language abbreviations, and I also invented the other rows to be consistent with the -3:00 row.
This tz commit in December 2016 (again by Eggert) removes the abbreviations and replaces them with the following text:
These tables use numeric abbreviations like -03 and -0330 for integer hour and minute UTC offsets. Although earlier editions used alphabetic time zone abbreviations, these abbreviations were invented and did not reflect common practice.

Related

What is the difference between 2 days and 48 hours in php

$new_date = date('Y-m-d', strtotime("+2 days"));
or
$new_date = date('Y-m-d', strtotime("+48 hours"));
Are they same or different
Are they same or different
They are quite different. Objectively speaking, 2 days does not always equal 48 hours.
Consider crossing a daylight-savings boundary.
For example, 2019-04-07T02:00:00+1100 (AEDT -> AEST)
$twoDays = new DateInterval('P2D');
$fortyEightHours = new DateInterval('PT48H');
$ref = new DateTimeImmutable('2019-04-07T01:00:00',
new DateTimeZone('Australia/Melbourne'));
echo 'Reference: ', $ref->format('r'), PHP_EOL;
echo 'Plus 2 days: ', $ref->add($twoDays)->format('r'), PHP_EOL;
echo 'Plus 48 hours: ', $ref->add($fortyEightHours)->format('r'), PHP_EOL;
This produces
Reference: Sun, 07 Apr 2019 01:00:00 +1100
Plus 2 days: Tue, 09 Apr 2019 01:00:00 +1000
Plus 48 hours: Tue, 09 Apr 2019 00:00:00 +1000
Note, HHVM produces a different result for some reason
Demo ~ https://3v4l.org/L4tKo
This list of common date / time related falsehoods is worth checking out ~ https://github.com/kdeldycke/awesome-falsehood#dates-and-time
It's worth pointing out that using the same reference date and manipulating it with strtotime() produces different results to those above.
Demo ~ https://3v4l.org/O6MTd
I suspect this is because its relative time calculations aren't as nuanced as DateInterval.
Semantically they are different, as demonstrated by Phil in the other answer. This means that in some other libraries that account for this the difference is real.
However, the implementation of strtotime() does not take this into account, so given your example, it makes no difference.
I was interested if it can be followed up through source code, so here goes:
Implementation of strtotime() does this:
strtotime() starts, calling timelib_strtotime() to create the initial ts construct
timelib_strtotime() calls scan() to parse the string
it reads the string you've given to it, and one of the tokens it gets is your +2 days or +48 hours, which is considered as relativetext.
for relativetext, among other things, timelib_set_relative() is called
in timelib_set_relative() it does a lookup from using timelib_lookup_relunit(), which uses timelib_relunit_lookup array, finding that you've provided either a construct with type TIMELIB_DAY, value 1, multiplier 2, or construct TIMELIB_HOUR, value 1, multiplier 24
It saves the information from previous call to s->time->relative construct
this construct gets passed on, until strtotime calls timelib_update_ts with it (and with timezone info!)
in timelib_update_ts we call do_adjust_relative() to act on it. We do it without using time zone parameter, which I would think is the critical mistake
do_adjust_relative() calls timelib_do_normalize()
timelib_do_normalize() for hours does do_range_limit(0, 24, 24, &time->h, &time->d), increasing days and decreasing hours if hours are over the hardcoded limit which is 24, and for days does do_range_limit_days(), increasing months and decreasing days if we are over the limit, taking into account leap time (but NOT time zones!).
on returning to timelib_update_ts, we call do_adjust_timezone with timezone parameter, but at this point we've already made all the adjustments and we know no more if it was done with +48 hours or with +2 days. Thus it makes no difference.
TLDR: strtotime() does not take time zones into account when doing the conversion, so in that function it makes no difference, even though it really should.

Strange behavior with the strtotime function passing a wrong date and time format

I'm trying to understand the following behavior of the date function strtotime():
strtotime(1420066800) returns false, as expected.
strtotime(1451602800) returns 26197048320! But expected false as 1451602800 is not a valid date and time format. (same thing with new DateTime(1451602800) as well)
I read the whole Supported Date and Time Formats page, but didn't find any match for this input.
By the way, these are timestamps of 2015-01-01 and 2016-01-01 relatively.
Any insights will be appreciated.
Update:
Different versions test results:
PHP 5.1.6 => false
PHP 5.2.17 => 26197048320
PHP 5.3.29 => 26197048320
PHP 5.4.34 => 26197048320
PHP 5.5.18 => 26197048320
PHP 5.6.2 => 26197048320
PHP 5.6.17 => 26197048320
PHP 7.0.2 => 26197048320
Running on Mac OS X 10.11.3
Let's start with the right way to do it. If you want to pass a timestamp to strtotime you have to prefix it with '#'. It is explained on the Compound Formats page, under "Localized notations" -> "Unix Timestamp".
echo(date('r', strtotime('#1420066800'))."\n");
echo(date('r', strtotime('#1451602800'))."\n");
The output is:
Thu, 01 Jan 2015 01:00:00 +0200
Fri, 01 Jan 2016 01:00:00 +0200
Now, why strtotime() returns false for 1420066800 and 26197048320 for 1451602800?
It expects to receive a string and if it receives a number it doesn't care and converts it to string first. Then it follows some rules and tries to identify the date components into the string. Because neither '1420066800' nor '1451602800' contains any separator for components, it probably tries to guess the order of components.
Today, 2016-02-25, strtotime('1451602800') produces a timestamp that, converted to a printable date looks like: 'Fri, 25 Feb 2800 14:52:00 +0200'
It makes me think it interprets the input string as follows: 14:51:60 is the time, 2800 is the year, the other components (day, month) are initialized from the current time.
The documentation says:
The function expects to be given a string containing an English date format and will try to parse that format into a Unix timestamp (the number of seconds since January 1 1970 00:00:00 UTC), relative to the timestamp given in $now, or the current time if $now is not supplied.
Since the "date" you provide doesn't follow any valid date-time format, strtotime() is free to return any value. It is called "garbage in, garbage out".
1451602800 gives a timestamp of 2800-02-25 14:52:00; and is being interpreted as:
1451602800
------
^
14:51:60 (or 14:52) time
today in the year
1451602800
----
^
2800
but only on 64-bit systems that can handle that date range

php: day of the week from given date using "date" function: getting one day ahead of expected answer

I have just started with php a couple of days ago. I am trying to get day of the week for a particular date.
$firstmonthdate = strtotime("7/1/2015");
//print what my timezone is, for clarity's sake for this question
$myTimezone = date_default_timezone_get();
echo $myTimezone."\n"."first day = ".date("r",$firstmonthdate);
I get following output for this code:
Asia/Singapore
first day = Wed, 01 Jul 2015 00:00:00 +0800
So far so good. My problem is in the next line of code:
echo "first day = ". strtolower(date("D",$firstmonthdate))."\n";
The output for this line of code is :
first day = thu
As seen above, the correct answer is wed but I am getting thu and am completely confused. This could possibly be due to timezone difference between singapore and GMT, but I cant figure out why and how to fix it. As seen above, I have set the local time zone correctly and am running this through CLI interface on local laptop. Local webserver is also picking up the same php.ini file.
Any suggestions on whats going wrong here?
Thanks very much.
Its because you have typo within your variable
echo "first day = ". strtolower(date("D",$firsmonthdate))."\n";
^^
instead it should be
echo "first day = ". strtolower(date("D",$firstmonthdate))."\n";
^^
If your error_reporting is on then you'll get a Notice: Undefined variable: firsmonthdate
You need to take care about dates in php. As over here you were getting
date which is 1970-01-01 and if its used in another representation then its Thu, 01 Jan 1970 00:00:00 +0000

Could not convert database value "1876-01-01 00:00:00-00:00:00" to Doctrine Type datetime

Why doesn't Doctrine like old dates?
Exception was thrown : Could not convert database value "1876-01-01 00:00:00-00:00:00" to Doctrine Type datetime
And another:
Exception was thrown : Could not convert database value "0000-00-00 00:00:00-00:00:00" to Doctrine Type datetime
In my Entity I do override datetime and datetimetz
Type::overrideType('datetime', 'Doctrine\DBAL\Types\VarDateTimeType');
Type::overrideType('datetimetz', 'Doctrine\DBAL\Types\VarDateTimeType');
If I update the date to 1976-01-01 00:00:00-00:00:00 it works fine.
UPDATE:
So I'm running Ubuntu 12.04 64 Bit, I also know that I have the 64 Bit time_t working from these tests:
strtotime() produces different output on 32 and 64 bit systems running
PHP 5.3.3 (as mentioned previously). This affects the "zero date"
("0000-00-00 00:00:00") as well as dates outside the traditional 32
date range.
Tests:
strtotime("0000-00-00 00:00:00") returns FALSE on a 32 bit system.
strtotime("0000-00-00 00:00:00") returns -62169955200 on a 64 bit system.
When executing echo strtotime("0000-00-00 00:00:00"); I get this:
php time_test.php -62169966000
so does Doctrine have the issue?
The epoch in PHP is either 1970 or 1901 depending on your system.
From the PHP manual:
The valid range of a timestamp is typically from Fri, 13 Dec 1901
20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT. (These are the dates
that correspond to the minimum and maximum values for a 32-bit signed
integer). However, before PHP 5.1.0 this range was limited from
01-01-1970 to 19-01-2038 on some systems (e.g. Windows).
http://php.net/manual/en/function.date.php

PHP Date / GMT Weirdness

Either I'm losing my mind, or I've not got the faintest idea what I'm doing. I'm leaning towards the latter.
I'm trying to convert this: 1316826000, which I'm pretty confident should be Sat, 24 Sep 2011 01:00:00 GMT
http://www.onlineconversion.com/unix_time.htm confirms this.
http://www.unixtimestamp.com/index.php tells me 09 / 23 / 11 # 8:00:00pm EST, so far so good. I happen to be in EST, this is the result I'd like to get back from PHP.
When I do date('l, M d, Y, h:ia', $iTime), I get: Friday, Sep 23, 2011, 12:00am, a full 20 hours off.
I've confirmed the server's time is correct using date('c'). date('c') output is: 2012-05-19T03:19:20+00:00. The server is in the central time zone, where it is currently 10:20pm. May 18.
echo date_default_timezone_get() outputs "GMT" (set somewhere else in the script using date_default_timezone_set('GMT'))
What am I missing? Nothing I've read so far can explain how I'm getting a result 20 hours behind what it should be. Were it an hour fast or slow, I could at least wrap my head around it being some sort of DST idiotry, but 20? Crazyness! Thanks for reading!
Check what your php.ini says for date.timezone.
In unix it is usually here: /etc/php.ini
Then use a proper timezone recognized by PHP:
http://www.php.net/manual/en/timezones.php
date.timezone = 'America/New_York'
Then reload your web server.
Unix time just means the number of seconds since epoch. Has nothing to do with timezones. Timezones simply add or subtract 1 hour (3600 seconds) from the unix time for each zone you move away from GMT.
An example:
$userTimezone = new DateTimeZone('America/New_York');
$gmtTimezone = new DateTimeZone('GMT');
$myDateTime = new DateTime('2014-01-22 11:44', $gmtTimezone);
$offset = $userTimezone->getOffset($myDateTime);
echo $offset;
That will output: -14400 or 4 hours. Which is the difference between New York and GMT
Using some Java code with the Joda-Time 2.3 library, as I don't know PHP…
long m = 1316826000L;
DateTime dateTimeUtc = new DateTime( m * 1000L, DateTimeZone.UTC );
DateTime dateTimeNewYork = dateTimeUtc.toDateTime( DateTimeZone.forID( "America/New_York" ) );
System.out.println( "dateTimeUtc: " + dateTimeUtc );
System.out.println( "dateTimeNewYork: " + dateTimeNewYork );
I can tell you that 1316826000 seconds from the beginning of 1970 UTC/GMT (Unix Epoch) is…
dateTimeUtc: 2011-09-24T01:00:00.000Z
dateTimeNewYork: 2011-09-23T21:00:00.000-04:00
So, as the commenter stated, it would be 8 PM in EST but EST was not in effect on that day. DST (Daylight Saving Time) (idiocy, as you correctly noted) was in effect until November 9 of that year (2011). So the time of day is pushed forward one hour, to 9 PM.
In GMT/UTC, that means 1 AM in the morning of the next day.
Standard time in east coast US is 5 hours behind UTC/GMT. With DST it is 4 hours behind UTC/GMT (one hour closer).
Where you got confused:
Your time format/conversion in incorrect.I can't help with that as I don't know PHP.
You should be using a competent date-time library for this kind of work.Date-time work is complicated, tricky, confusing, and error-prone.This question discusses possibilities of Joda-Time (for Java) sorts of libraries for PHP.
You used three-letter time zone codes. Avoid these.Those codes are neither standardized nor unique -- there are common duplicates. Instead, use proper time zone names. In your case of east coast US, "America/New_York". Furthermore, in this case you confused the time zone area and rules (east coast US) with a particular application of those rules (EST). Saying "America/New_York" means "whatever time zone rules were in effect on that date, whereas saying "EST" (if interpreted to mean Eastern Standard Time in US) means "UTC-05:00". So either (a) use a time zone name such as "America/New_York", or (b) use a specific offset such as "-05:00".

Categories