strftime giving wrong month name (February only...) - php

I have the following code, to get the month name of a certain date, and then using to get the name of the month in Hebrew.
$thismonthname = date("F", mktime(0, 0, 0, $thismonthnumber, 10));
date_default_timezone_set('Asia/Tel_Aviv'); // Set timezone to Israel
$locale = 'he_IL.utf8'; setlocale(LC_ALL, $locale); // Set Locale to Hebrew
$thismonthnameheb = strftime('%B', strtotime($thismonthname));
It works perfectly, except for February.
When I print out $thismonthname it says "February" but when I print out $thismonthnameheb it says מרץ (march) in Hebrew.
Going crazy, I can't figure this out.

You're doing too much conversion from time to string and back.
Instead of converting time -> string -> time, simply keep the time value and base the results on that:
$thismonthtime = mktime(0, 0, 0, $thismonthnumber, 10);
$thismonthname = date("F", $thismonthtime);
date_default_timezone_set('Asia/Tel_Aviv'); // Set timezone to Israel
$locale = 'he_IL.utf8'; setlocale(LC_ALL, $locale); // Set Locale to Hebrew
$thismonthnameheb = strftime('%B', $thismonthtime);

This has nothing to do with Hebrew, since, at least on the particular version of PHP I am using (5.3.10),
echo strftime('%d %B', strtotime('February'));
gives
01 March
As suggested in the comments, this arguably unexpected behaviour is due, basically, to PHP's assumption that the day of a given month is the 30th unless the user actually specified a different value. Hence for February we overflow to the 1st of March.
A look at this reference might prove useful.

Note the sequence:
php > $time = mktime(0,0,0,2, 10);
php > echo date('r', $time);
Mon, 10 Feb 2014 00:00:00 -0600 // everything ok here, I'm in UTC-6
php > date_default_timezone_set('Asia/Tel_Aviv');
php > echo date('r', $time);
Mon, 10 Feb 2014 08:00:00 +0200 // note how it's now 8 hours "later"
php > $month = date('F', $time);
php > echo $month;
February
php > $newtime = strtotime($month);
php > echo date('r', $newtime);
Sat, 01 Mar 2014 00:00:00 +0200 // hey! it's march again!
You screwed up by stripping your date down to a simple month name, then expecting PHP to magically be able to guess what you're expecting to do. If you feed it just a month, it's free to pick whatever it wants for the year/day/time values.

Related

PHP : reformat a date in

Good day,
I have the following date that I get from my imap_fetch_overview PHP function :
$overview = imap_fetch_overview($inbox, $email_number, 0);
...
$date_event = $overview[0]->date;
This outputs a date like 'Fri, 30 Jun 2017 16:27:44 +0000 (UTC)'
In the meantime I have set my default timezone as following :
date_default_timezone_set('Europe/Brussels');
What I would like now is to be able to retrieve my $date_event in a format dd.mm.yyyy HH:mm:ss (local time, in my case 30.06.2017 18:27:44).
I have therefore tried :
$date_event_formated = $date_event('dd.mm.YYYY HH:ii:ss');
When calling 'echo $date_event_formated;', the only thing I get is a Fatal error.
So sorry if the question might sound silly, but I don't really understand what I am doing wrong here? Before bothering you, I looked at the reference website http://php.net/manual/fr/function.date.php but I may have missed something.
Thanks very much for your time and appreciated help.
While there is nothing wrong with Jakub's answer, using php 5.3 and up you can also use DateTime::createFromFormat, using an exact mask to parse the incoming date-string.
$oldDate = 'Fri, 30 Jun 2017 16:27:44 +0000 (UTC)';
$date = DateTime::createFromFormat('D, d M Y H:i:s T e', $oldDate);
echo $date->format('Y-m-d');
strtotime() is able to handle the format that you have and convert it into timestamp. Then you can use it to format date in whatever format you want with date() function:
$date_event = 'Fri, 30 Jun 2017 16:27:44 +0000 (UTC)';
echo date('d.m.Y H:i:s',strtotime($date_event));
//outputs: 30.06.2017 18:27:44
Here's working example:
https://3v4l.org/obfNB
use strtotime:
$date_event = 'Fri, 30 Jun 2017 16:27:44 +0000 (UTC)';
echo date('d.m.Y H:i:s',strtotime($date_event));

Is strtotime() having a bug?

Consider this code where we want to add or substract one second:
date_default_timezone_set("Europe/Amsterdam");
$time = 1477789199;
echo $time . ' - ' . date('r', $time) . "\n";
// 1477789199 - Sun, 30 Oct 2016 02:59:59 +0200
This is correct, as this timestamp is still just within DST (daylight savings time / summer time).
But now let's add one second to the timestamp integer, and exit DST:
$new = $time + 1;
echo $new . ' - ' . date('r', $new);
// 1477789200 - Sun, 30 Oct 2016 02:00:00 +0100
Hooray! PHP sees that one second later there is no DST anymore and shows a proper time string.
But what if we didn't add a second to the timestamp integer, but we used strtotime() to add that one second:
$new = strtotime('+1 second', $time);
echo $new . ' - ' . date('r', $new);
// 1477792800 - Sun, 30 Oct 2016 03:00:00 +0100
Yikes! We just went ahead by more than one hour instead of one second. And it doesn't even matter if you add one second, one hour, one day or one year you will always get one extra hour with it. Even if you add multiple years, you will only get one extra hour, which is weird because we enter and exit DST every year but you only get one extra hour regardless of how many years you add
But once we exit DST in October and subtract one second, all goes fine...
But then again. If we were in March and we have just entered DST, and we subtract one second, we observe exactly the same in reverse.
Wait, what ?! So ... ?
echo strtotime('+ 1 second - 1 second', 1477789199); // echoes 1477792799
Whoa ...
To me this sounds like a bug. Or is this 'by design'? Does anyone even know if this is documented somewhere, or whether it needs to be reported?
The behavior is "well documented" .... in a test:
See https://bugs.php.net/bug.php?id=30532 (which also presents your expected result as expected) and the related test file (which asserts that the current behavior is correct) https://github.com/php/php-src/blob/master/ext/date/tests/bug30532.phpt
<?php date_default_timezone_set("America/New_York");
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +1 hour'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +2 hours'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 EDT +3 hours'))."\n";
/* 2004-10-31 01:00:00 EDT
2004-10-31 01:00:00 EST
2004-10-31 02:00:00 EST */
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +1 hour'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +2 hours'))."\n";
echo date('Y-m-d H:i:s T', strtotime('2004-10-31 +3 hours'))."\n";
/* 2004-10-31 01:00:00 EDT
2004-10-31 02:00:00 EST
2004-10-31 03:00:00 EST */
Note that in the former case the timezone (here: EDT) is being passed directly to the string, in the latter case it isn't.
In general strtotime is taking the timestamp (i.e. of 2004-10-31 - or in your specific case: the passed timestamp), converted to a representation with individual parameters, ignoring DST (i.e. individual hours, minutes, seconds, day, month, year etc.), the operation is applied to it and then converted back to the timestamp.
In particular:
echo date('r', strtotime('+ 0 second', 1477789199));
#> Sun, 30 Oct 2016 02:59:59 +0100
strtotime() throws the timezone after conversion away, i.e. only takes
Sun, 30 Oct 2016 02:59:59
and then applies the primary applicable timezone to your timezone location (i.e. Europe/Amsterdam), ending up with CET (primary!) - CEST is also possible, but only second choice.
Now, look back at the test above, just specify the originating timezone explicitly.
Thus, if you wish it to behave the way you need it:
echo date('r', strtotime('CEST', 1477789199));
#> Sun, 30 Oct 2016 02:59:59 +0200
echo date('r', strtotime('CEST + 1 second', 1477789199));
#> Sun, 30 Oct 2016 02:00:00 +0100
In fact, prepending 'CEST ' will be fine for all the times (as it will always fallback to CET if CEST is not matching and there's no overlap on CET -> CEST transition).

PHP - Adjust Hour pulled from RSS feed for Daylight Savings

I've got a PHP script which pulls from an RSS feed and produces a series of outputs based on events. The script was working fine until last week, when daylight savings changed.
The script is working off an RSS feed which has the date in the following structure:
pubDate: Thu, 04 Apr 2013 19:05:00 GMT
I needed to create different php scripts for each day and time, so I used the following:
$expiry = $item->pubDate;
$expiryLenght = strlen("$expiry");
$timeStart = $expiryLenght - 12;
$time = substr("$expiry","$timeStart", 5);
$hour = substr("$time",0, 2);
$day_alpha = substr("$expiry",0, 3);
$day = substr("$expiry",5, 2);
$month = substr("$expiry",8, 3);
$year = substr("$expiry", 12, 4);
$month = strtolower($month);
$month_num = monthNum($month);
The important part for me is the '$hour' line. I need to try and adjust that for daylight savings. The pubDate is always in GMT un-adjusted.
I was thinking of going down the route of defining the daylight savings period, and if it is within the timeframe, add 1 to the hour. However, I'm not sure that that is a good solution.
Any help would be greatly appreciated,
Dave.
After much help from the comments, I ended up using this
$expiry1 = $item->pubDate;
$expiry = date('D, d M Y H:i:s \off', strtotime($expiry1 . " Europe/Dublin"));
Bit of a hackjob, but it put the Expiry back into the format it was previously in, which meant the rest of the code could work off it.
<?php
$expiry = "Thu, 04 Apr 2013 19:05:00 GMT";
echo date('l jS \of F Y h:i:s A', strtotime($expiry . " America/New_York"));
?>
I'm at work right now so can't test this but I believe you want to do something along these lines:
<?php
$timestring = 'Thu, 04 Apr 2013 19:05:00 GMT';
$mytimezone = new DateTimeZone('Pacific/Nauru');
$datetime = date_create_from_format('D, d M Y h:i:s T', $timestring, $mytimezone);
echo $datetime->format('Y-m-d H:i:sP');
This creates a DateTime object from the string formatted as you specified, but with the Timezone you choose. So you choose the Timezone, it parses the date/time from your RSS feed and converts it to the timezone of your choosing.
It's also a lot less code than what you're currently doing. :-)

Project Euler #19 code seems right. What am I missing?

Problem 19:
You are given the following information, but you may prefer to do some
research for yourself.
1 Jan 1900 was a Monday.
Thirty days has September, April, June and
November.
All the rest have thirty-one, Saving February alone, Which
has twenty-eight, rain or shine. And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a
century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)?
I thought that using PHP for this would be a breeze since it has so many built-in time and date functions. My code is really quite simple, so I'm having a hard time seeing what I'm doing that's wrong.
My code:
<?php
echo "<pre>";
$sunday_count = 0;
for( $year = 1901; $year <= 2000; $year++ ) {
for( $month = 1; $month <= 12; $month++ ) {
// Produces a date in format: 1/1/2000
$date = $month . "/1/" . $year;
$time = strtotime( $date );
$is_sunday = ( date( 'l', $time ) == "Sunday" );
echo "$date "
. ( $is_sunday ? 'was a Sunday. ' : '' )
. "<br>";
if( $is_sunday ) $sunday_count++;
}
}
echo "Answer: $sunday_count";
echo "</pre>";
?>
The solution my code comes up with is 169, which is not correct. Any idea?
Edit 1
The solution is supposed to be 171.
Using Wolfram Alpha and my Windows clock, I've doubled checked several of the Sundays which my code reports. All of them check out OK.
So it seems my code is reporting valid and legitimate Sundays, but somehow it has missed two of them.
Edit 2
I made the following minor change to the formatting of the date in my code:
$date = sprintf('%d-%02d-01', $year, $month); // formats yyyy-mm-dd
I then used #MadaraUchiha's code to generate an array containing the 171 correct dates.
After comparing his dates with mine, these are the two missed dates:
1901-09-01
1901-12-01
Edit 3
Codepad also shows that these dates are not Sundays (but they really should be).
And I am certain that the dates are correctly being interpreted as YYYY-MM-DD because one of the dates my code offers to the solution is 2000-10-01, which would only be a Sunday if 10 is the month, not the day.
Edit 4
So apparently if on a 32 bit system, Unix timestamps won't work outside of the range:
Fri, 13 Dec 1901 20:45:54 GMT
to
Tue, 19 Jan 2038 03:14:07 GMT
The reason it might not work on some systems using timestamps is that the range of a Unix timestamp on 32-bit systems is from Fri, 13 Dec 1901 20:45:54 GMT to Tue, 19 Jan 2038 03:14:07 GMT, so you miss almost all months in the first year.
64-bit systems have larger integers which makes the range bigger (in PHP).
I get 171 with this (much shorter, and more readable) code, using DateTime objects:
header("Content-type: text/plain"); //Browser display
$time = new DateTime("1901-01-01");
$end = new DateTime("2000-12-31");
$counter = 0;
while (!$time->diff($end)->invert) { //$time isn't greater than $end
$time->modify("+1 month");
if ($time->format("l") == "Sunday") {
$counter++;
echo $time->format("Y-m-d") . " was a Sunday!\n";
}
}
echo "\nTotal number of Sundays: $counter";
When using DateTime objects, you're treating dates as Dates and not as numbers or strings. This gives you a huge flexibility advantage over any other approaches.
The problem on this code is the line
$date = $month . "/1/" . $year;
this should be
$date = "1/".$month."/" . $year;
You mixed the places of months and days.

Converting from a day of week to unix time in PHP

I'm trying to get the unix time for date strings that are formatted like so:
'second sunday of march 2010'
'first sunday of november 2010'
I was under the impression that strtotime could handle such a string, but apparently not, as this returns false. How can I convert to unix time when given a day of week, which one of those in the month (ie. first, second, etc.), a month and a year.
This should be possible with strtotime. You could try generating a timestamp of the first day of march using mktime() and adding that as a 2nd parameter (leaving just "first sunday" in the string part):
$timestamp = mktime (0,0,0,3,1,2010); // 1st of march
$first_sunday = strtotime("first sunday", $timestamp);
Not sure how this will handle the first day (March 1st) actually being a sunday. Make sure you check that out.
Also, and maybe this more reliable, check this out - the poster says he got good results with the following notation (quoting):
<?php
strtotime('+0 week sun nov 2009'); // first sunday in nov 2009
strtotime('+1 week sun nov 2009'); // second sunday
strtotime('-1 week sun nov 2009'); // last sunday in oct 2009
?>
As always with strtotime, whatever you pick, make sure you test well, especially the edge cases (1st day of month is a sunday, last day of last month was a sunday....)
Your code works for me on PHP 5.3.0. What version of PHP are you using?
<?php
date_default_timezone_set("Europe/Oslo");
$time_march = strtotime('second sunday of march 2010');
$time_november = strtotime('first sunday of november 2010');
echo date("Y-m-d", $time_march) . " (timestamp: $time_march)\n";
echo date("Y-m-d", $time_november) . " (timestamp: $time_november)\n";
?>
gives:
2010-03-14 (timestamp: 1268521200)
2010-11-07 (timestamp: 1289084400)

Categories