I'm trying to get my head round someone else's code which they've written for handling the dates of when news stories are published. The problem has come up because they are using this line -
$date = strtotime("midnight", strtotime($dateString));
to process a date selected using a jquery calendar widget. This works fine for future dates, but when you try to use a date which is in the previous calendar year, it uses the current year instead. I think this is due to "midnight" finding the closest instance of the selected day and month.
I could remove the "midnight", but I'm not sure what the repercussions of this would be - is there a reason that the midnight could be there?
EDIT: this is the full block of code which handles the date. The date contains the time, which allows the user to publish an item at a specific time.
$array['display_date'] = '24 October, 2011 17:30';
$string = $array['display_date'];
$dateString = substr($string, 0, -5);
$timeArray = explode(':', substr($string, -5));
$hours_in_secs = 60 * 60 * $timeArray[0];
$mins_in_secs = $timeArray[1];
$date = strtotime("midnight", strtotime($dateString));
$timestamp = $date + $hours_in_secs + $mins_in_secs;
//assign timestamp to validation array
$array['display_date'] = $timestamp;
echo $array['display_date']; // Output = 1351094430 (Oct 24 2012 17:00:30)
This really depends on what $dateString contains. Assuming your jQuery widget delivered the time portion as well, your colleague likely wanted to remove the time portion. Compare the following:
echo date(DATE_ATOM, strtotime('2010-10-01 17:32:00'));
// 2010-10-01T17:32:00+02:00
echo date(DATE_ATOM, strtotime("midnight", strtotime('2010-10-01 17:32:00')));
// 2010-10-01T00:00:00+02:00
If your widget doesnt return the time portion, I dont see any reason for setting the date to midnight, because it will be midnight automatically:
echo date(DATE_ATOM, strtotime('2010-10-01'));
// 2010-10-01T00:00:00+02:00
Note that all these are dates in the past and they will result in the given year in the past, not the current year like you say. If they do in your code, the cause must be somewhere else.
Will there be repercussions when you change the code? We cannot know. This is just one line of code and we have no idea of any context. Your unit-tests should tell you when something breaks when you change code.
EDIT after update
The codeblock you show makes no sense whatsoever. Ask the guy who wrote it what it is supposed to do. Not only will it falsely return the current year for past years, but it will also give incorrect results for the minutes, e.g.
24 March, 2010 17:30 will be 2012-03-24T17:00:30+01:00
I assume this was an attempt at turning 24 March, 2010 17:30 into a valid timestamp, which is in a format strtotime does not recognize. But the approach is broken. When you are on PHP5.3 use
$dt = DateTime::createFromFormat('d F, Y H:i', '24 March, 2010 17:30');
echo $dt->format(DATE_ATOM); // 2010-03-24T17:30:00+01:00
If you are not on 5.3 yet, go through https://stackoverflow.com/search?q=createFromFormat+php for alternate solutions. There is a couple in there.
Related
Currently, I'm trying to parse out dates when messages were received into timestamps. I have the month and day but the year is not specified. The event always occurs at the most recent (human) reading of the time. It works great in most cases to do this:
$time = strtotime("Jan 2 8:38pm");
That returns a date for this year, which is correct. Unfortunately, I get problems when I try to do for example:
$time = strtotime("Dec 31 8:38pm");
That returns a date which hasn't happened yet, and wont happen for the whole rest of the year. Obviously, my message was not sent in the future. I need it to return December 31st of last year.
For weekdays, I had a solution by prepending 'last' before the weekday like so:
$time = strtotime("Last Saturday 8:38pm");
That always returned the time of the last Saturday. However, trying to do the same thing here doesn't work:
$time = strtotime("Last Dec 31 8:38pm");
This returns false. I know to decrement a date by 1 year, I can do this:
$time = strtotime("Dec 31 8:38pm -1 year");
And that works great for Dec 31. However, Jan 2 will now fail:
$time = strtotime("Jan 2 8:38pm -1 year");
One solution I thought of was to subtract off a year (86400 * 365) from the resulting value if it is past today's date. However, this result will fail if we passed over February of a leap year. In that case, we would end up with a time that was ahead by a day.
The best solution I came up with so far is this:
$time = strtotime($raw_time);
if ($time > time()) {
$time = strtotime($raw_time." -1 year");
}
It seems kind of wasteful to make two calls to strtotime which I know is probably not a very efficient function. Is this the most elegant solution?
Is anyone aware of an option in strtotime which forces the dates to be in the past instead of in the future?
Is there another way to parse these dates that I should consider?
Efficiency is important for this because I am going to be parsing a lot of dates with it, but I would also like simple and readable code so I can understand it later.
Your approach is fine, as there is no date format to get what you want. Another approach could be using the DateTime class:
$datetime = new DateTime($raw_time);
if ($datetime > new DateTime()) {
$datetime->modify('-1 year');
}
You could test which one of the two approaches is faster. My guess is that this is a micro-optimization that won't make a lot of difference.
I am working on project (a Google Transit feed) where I am required to provide the times for each stop on a bus route in the following common format: 21:00:00 and so forth.
Problem is, if times continue past midnight for a given trip, they require it to continue the hour counting accordingly. They explain quite specifically that 02:00:00 should become 26:00:00 and 03:45:00 should become 27:45:00 etc.
I am baffled on how to display such with any of the date() or strtotime() functions.
The only thing I can think of in my particular situation would be to function match and replace any strings in my output between 00:00:00 and 04:00:00, as that would clearly mean (again, for me only) that these are trips originating before midnight, but I don't feel that's the correct way.
Well seeing as it's only displaying on the page, you can
firstly get your date from where ever
Let's say $date = 00:00:00
$exploded_date = explode(":", $date);
This takes $date and puts it into an array so
$exploded_date[0] is hh
$exploded_date[1] is mm
$exploded_date[2] is ss
Then what you can do is use ltrim() to remove the leading 0 from 00 to 04 $exploded_date[0] - This makes it comparable in the if statement I'll do after
if($exploded_date[0] <= 4) {
$exploded_date[0] = ltrim($exploded_date[0], "0");
$exploded_date[0] = $exploded_date[0]+24;
}
Then you can implode the array back together into one string
$date = implode(":", $exploded_date);
// if the hour is 00 to 04 it will come out as 24 to 28
// e.g. 24:35:30
echo $date;
Despite giving you an answer. It's a silly thing to be doing, but it's not your choice so here you go :)
The way you display something doesn't necesarily has to be the same way you store something.
I don't know how you calculate the times, but assuming you have a start date and time, and some interval, you could calculate the end time as follows:
date_default_timezone_set('Europe/London');
$start_datetime = new DateTime('2014-11-11T21:00:00');
$next_stop = new DateTime('2014-11-12T02:00:00');
echo $start_datetime->format('Y-m-d H:i'); // 2014-11-11 21:00
echo $next_stop->format('Y-m-d H:i'); // 2014-11-12 02:00
$interval = $start_datetime->diff($next_stop);
// display next stop: 2014-11-11 26:00
echo ($start_datetime->format('Y') + $interval->y) .'-'
. ($start_datetime->format('m') + $interval->m) .'-'
. ($start_datetime->format('d') + $interval->d) .' '
. ($start_datetime->format('H') + $interval->h) .':'
. ($start_datetime->format('i') + $interval->i);
What I'm doing: create the start date (& time) and the datetime of the next stop. With the DateTime::diff() function I'm calculating the difference, and then, only for display (!) I add up each year, month, day, hour and minute to the datetime year, month etc. of the next stop.
This way you can still store your dates and times in a way every human being and computer system will understand (because let's be honest; to represent a time as 27:45 PM is quite ridiculous...)
I don't know if you only want the hours to be added up and roll over the 24 hour, or also days in a month etc. It's up to you how you handle these cases. Good luck!
$string = file_get_contents("http://domain.com/api/data?after=1412640000");
My PHP code displays the json data based on the epoch time. This time is always at 00:00:00 UTC. I need the time in the url to change at different time frames like 1 day when it is available.
I can put a variable in the url to get the current time but Im lost on the setting it to 00:00:00 UTC for when the new day would roll over.
Ive searched and I keeping getting partial results but not quite what I need. First time posting here. Thanks for the help.
Edit: I got this to work for daily changes but I need two other time frames like one week and a month.
Heres the code:
$daily = gmdate(strtotime('yesterday'));
$string = file_get_contents("http://domain.com/api/data?after={$daily}");
The gmdate is what did the trick for UTC. Now for a week time frame. An example would be displaying the date of the 2nd of the month until the week rolls over then it displays the new weekly date from the 9th.
strtotime is more powerful than you think, just the naive way works:
strtotime("-1 week")
strtotime("-1 month")
Ok so finally figured it out. Here is the code to enter epoch from certain date time intervals of daily, weekly and monthly all in UTC.
$daily = gmdate(strtotime('yesterday'));
$string = file_get_contents("http://domain.com/api/data?after={$daily}");
$weekly = mktime(23, 59, 59, date('n'), date('j'), date('Y')) - ((date('N'))*3600*24);
$string = file_get_contents("http://domain.com/api/data?after={$weekly}");
$monthly = mktime(0, 0, 0, date('m'), 1, date('Y'));
$string = file_get_contents("http://domain.com/api/data?after={$monthly}");
$daily is the simplest and easiest. $weekly will start with Mondays and will give that time until the next Monday comes around and thats also how $monthly works but with on the 1st.
I need help.. Is this right?
Start Date: Mar 16, 2014
End Date: Mar 19, 2014
Results: 2 Days
$plantEnd = get_the_author_meta('plantEnd', $sellerID );
$plantStart = get_the_author_meta('plantStart', $sellerID );
$future = $plantEnd;
$d = new DateTime($future);
echo $d->diff(new DateTime())->format('%a').' Days';
Why does it says 2 days? Isn't it 3 days? Im confused..
Since you aren't actually using $plantStart in your code and instead using the current time, you're basically getting a difference between now (the time the script was run, on server's time zone) and the start of Mar 19, 2014 (0h:0m:0s). So what you are really getting is something like 2 days 5 hours 3 minutes 25 seconds (depending on when you run it vs. server time.
for example, when I run this locally:
$d->diff(new DateTime())->format('%d:%H:%i:%s');
I get 2:04:59:25
So there's more to it than just getting that "2" returned.. you're just not formatting for it.
And again, you aren't actually using the $plantStart anywhere either. So if you were to do this:
<?php
$plantEnd = '2014-03-19';//get_the_author_meta('plantEnd', $sellerID );
$plantStart = '2014-03-16'; //get_the_author_meta('plantStart', $sellerID );
$future = $plantEnd;
$d = new DateTime($future);
echo $d->diff(new DateTime($plantStart))->format('%d:%H:%i:%s');
?>
You will see it outputs 3:00:0:0 (or you could continue to just use %d and get the "3"). This is because $plantStart (presumably - based on your post) just specifies yyyy-mm-dd, so passing just the yyyy-mm-dd value will put the hh:mm:ss at 0:0:0 (beginning of day) , so it will be a full day's calculation, which has the effect of "rounding up" to the whole day increment.
I have a feeling that it's actually 2 days, someodd hours, and someodd minutes, or something to that effect. Because you're formatting to just do days, you're losing the nuances. I'd change the code to say "2.4 days" (and for the life of me I can't remember how I did this in the past...)
EDIT: in the past I have simply used date() instead of DateTime().
I did a little research, and you might want format('%d')." Days";
I need some help wrapping my head around this. I am trying to develop something that does monthly, weekly, quarterly, yearly subscriptions. I need to figure out when the next charge date is. But I'm getting confused getting through the logic. I can easily calculate when a year is from the original transaction (<? echo date("Y-m-d",strtotime($charge_interval, strtotime($original_charge_time))); ?>), where $charge_interval is '+3 months' or '+1 month', etc. But.. if 3 months have passed, I can't just use that equation, because it will show the "next" date as one month from the original. Any advice?
EDIT: more precision. My data is stored in a DB, and I need to ensure its getting the "next" month rather than a month from original date. Say transaction took place Nov 15th. Its now July 6th. I want "next transaction" to say July 15th, NOT Dec 15th (which is what the above code would accomplish), and to say "we have already have 7 charges before".
strtotime is little-know, but can show itself to be very useful for this kind of use.
EDIT: here may be a clue:
$charges = 0;
$now = time();
$next_charge_time = strtotime($original_charge_time);
while ($next_charge_time < $now)
{
$charges++;
$next_charge_time = strtotime($charge_interval, $next_charge_time);
}
$next_charge_time = date("m/d/Y", $next_charge_time);
echo "You have been charged $charges times since $original_charge_time.";
echo "<br/>";
echo "Next charge will be on $next_charge_time";
Doesn't php have a dateadd function of some kind to add a number of months to a date?
Like this one?
http://php.net/manual/en/function.date-add.php
Use DateTime() with http://us3.php.net/manual/en/datetime.add.php
Try mktime(0, 0, 0, strftime("%d", $origtime), date("m")+1, date("Y"));
that would mean midnight of course (first three parms are H, M, S, you could use strftime for those too if you want)
that would work for the next calendar month, you could just remove the "+1" for the same month if you work out the day falls later than the current day.