PHP DateTime and Interval unexpected behavior - php

here is my code (using laravel)
$start = '05-01-2016';
$end = '05-03-2016';
$start_date = new Carbon;
$end_date = new Carbon;
$format = 'm-d-Y';
$begin = Carbon::createFromFormat($format, $start);
$begin->setTime(0, 0, 0);
$end = Carbon::createFromFormat($format, $end);
$end->setTime(59, 59, 59);
//dd($begin,$end);
$interval = new \DateInterval('P1D');
$dateRange = new \DatePeriod($begin, $interval, $end);
foreach ($dateRange as $date) {
$start_time = $start_date->setDateTime($date->format("Y"), $date->format("m"), $date->format("d"), 0, 0, 0)->toDateTimeString();
$end_time =$end_date->setDateTime($date->format("Y"), $date->format("m"), $date->format("d"), 23, 59, 59)->toDateTimeString();
var_dump($start_time);
//var_dump($end_time);
}
expected output would be (atleast for me)
05-01-2016
05-02-2016
it actually gives me
05-01-2016
05-02-2016
05-03-2016
05-04-2016
05-05-2016
I cant understand it... any help is appreciated
here is output

You set 59 hour :) - It is more than two days. Now your end datetime is Thu, 05 May 2016 11:59:59
$end->setTime(59, 59, 59);
Set 23 hours and it will work
$end->setTime(23, 59, 59);

Related

Finding differently lengthed time intervals between two dates

I want users to be able to select a date range and an interval to display results from, such as "show me results between Jan 1, 2017 and Apr 1, 2017, listed by day|week|month"
So if they selected day, I'd group results by Jan 1, 2017; Jan 2, 2017; Jan 3, 2017; etc...
If they selected week, it'd be Jan 1, 2017; Jan 8, 2017; Jan 15, 2017; etc...
The method I'm using now is as follows:
if(isset($chosenInterval) && ($chosenInterval == "week" || $chosenInterval == "day") ) {
$timeFormat = "F j, Y";
} else {
$timeFormat = "F Y";
$chosenInterval = "month";
}
$start = (new DateTime($start))->modify('first day of this month');
$end = (new DateTime($stop))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 '.$chosenInterval);
$period = new DatePeriod($start, $interval, $end);
foreach($period as $dt) {
$dataLabels[] = $dt->format($timeFormat);
}
The problem is that if the user selects Jan 8, 2017 - Jan 20, 2017, it still includes all the dates in January.
Ideally it would show:
Day: Jan 8, 2017; Jan 9, 2017; ... Jan 19, 2017; Jan 20, 2017
Week: Jan 8, 2017; Jan 15, 2017
Month: Jan, 2017
Any suggestions on how to accomplish this? Thanks!
You need to check when adding your DateTime objects to $dataLabels if the date is before the start or after the end. If it is (and the $chosenInterval is not a month), don't add them:
<?php
$start = "2017-01-08";
$stop = "2017-01-20";
$chosenInterval = "week";
function getDates($start, $stop, $chosenInterval = "week") {
$startDT = new DateTime($start); // make a DateTime out of the date to later compare it
$stopDT = new DateTime($stop); // make a DateTime out of the date to later compare it
if(isset($chosenInterval) && ($chosenInterval == "week" || $chosenInterval == "day") ) {
$timeFormat = "F j, Y";
} else {
$timeFormat = "F Y";
$chosenInterval = "month";
}
$begin = (new DateTime($start))->modify('first day of this month');
$end = (new DateTime($stop))->modify('first day of next month');
$interval = DateInterval::createFromDateString('1 '.$chosenInterval);
$period = new DatePeriod($begin, $interval, $end);
foreach($period as $dt) {
if ($chosenInterval !== "month" && ($dt < $startDT || $dt > $stopDT)) continue; // if date is before start or after end, skip
$dataLabels[] = $dt->format($timeFormat);
}
return $dataLabels;
}
var_dump(getDates($start, $stop));
var_dump(getDates($start, $stop, "day"));
var_dump(getDates($start, $stop, "month"));
Demo

Get dates for specific weekdays

I need to get the timestamp for the current week's Wednesday and Saturday at 22:59, and then convert the timestamp to a human-readable date.
I've tried the following:
date_default_timezone_set('America/New_York');
$wednesdayLimit = strtotime('wednesday this week');
$saturdayLimit = strtotime('saturday this week');
$wednesdayLimit->setTime(22,59,0);
$saturdayLimit->setTime(22,59,0);
echo date("Y-m-d H:i:d", $wednesdayLimit);
echo date("Y-m-d H:i:d", $saturdayLimit);
But I get the following error:
Uncaught Error: Call to a member function setTime() on integer
One liner:
print date('Y-m-d H:i:s', strtotime('wednesday this week 22:59:00'));ΒΈ
Yields:
2016-01-27 22:59:00
How about
$wednesday = strtotime('wednesday this week');
$wednesdayStart = $wednesday - ($wednesday % 60*60*24);
$wednesdayEnd = $wednesdayStart + (60 * 60 * 24) - 1;
You could use DateTime and do something like this.
$date = new \DateTime();
$date->setISODate((int)$date->format('o'), (int)$date->format('W'), 3);
$date->setTime(22, 59, 0);
echo $date->format('D d-m-Y H:i:s');
Demo.
Or, if you like one liners.
$date = (new \DateTime())->modify('wednesday this week')->setTime(22, 59, 0);
Demo

How to divide datetime period into separate days in PHP

I need to divide time period for example from:
2015-11-22 11:22:33 to 2015-11-24 02:02:04
into something like this:
2015-11-22 11:22:33 - 2015-11-22 23:59:59
2015-11-23 00:00:00 - 2015-11-23 23:59:59
2015-11-24 00:00:00 - 2015-11-24 02:02:04.
It has to work also for periods shorter than 24h, so for
2015-11-22 11:22:33 to 2015-11-23 02:02:04
I need this:
2015-11-22 11:22:33 - 2015-11-22 23:59:59
2015-11-23 00:00:00 - 2015-11-23 02:02:04.
I found almost perfect piece of code, but it only works for periods longer than 24h and I don't know how to tune it.
<?php
$start_date = '27:04:2013';
$start_time = '16:30';
$end_date = '29:04:2013';
$end_time = '22:30';
// Date input strings and generate a suitable DatePeriod
$start = DateTime::createFromFormat("d:m:Y H:i", "$start_date $start_time");
$end = DateTime::createFromFormat("d:m:Y H:i", "$end_date $end_time");
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $date) {
// Get midnight at start of current day
$date_start = clone $date;
$date_start->modify('midnight');
// Get 23:59:59, end of current day
// (moving to midnight of next day might be good too)
$date_end = clone $date;
$date_end->modify('23:59:59');
// Take care of partial days
$date_start = max($start, $date_start);
$date_end = min($end, $date_end);
// Here you would construct your array of
// DateTime pairs, or DateIntervals, as you want.
printf(
"%s -> %s \n",
$date_start->format('Y-m-d H:i'),
$date_end->format('Y-m-d H:i')
);
}
?>
Try this:
$date1 = '2015-11-22 11:22:33';
$date2 = '2015-11-23 12:22:34';
$f1 = strtotime($date1);
$f2 = strtotime(substr($date1, 0, 10) . " 23:59:59");
while($f2 < strtotime($date2)) {
print(date('Y-m-d H:i:s',$f1) .' - ' .date('Y-m-d H:i:s',$f2).'<br>');
$f1 = strtotime(date('Y-m-d H:i:s', $f2) .' +1 second');
$f2 = strtotime(date('Y-m-d H:i:s', $f2) .' +1 day');
}
print(date('Y-m-d H:i:s',$f1) .' - ' .$date2.'<br>');
See here: http://sandbox.onlinephpfunctions.com/code/77eaae15fdd7c0d2ca1f02a2d225c17199218819
$datetime1 = new DateTime('2015-11-22 11:22:33');
$datetime2 = new DateTime('2015-11-23 02:02:04');
$interval = $datetime1->diff($datetime2);
var_dump($interval->format('%y-%m-%d %h:%i:%s'));
// RESULT: string(14) "0-0-0 14:39:31"
References:
http://php.net/manual/de/datetime.diff.php
http://php.net/manual/de/class.dateinterval.php
http://php.net/manual/de/dateinterval.format.php

Timestamps of start and end of month

How can one get the timestamps of the first and last minutes of any month using PHP?
You can use mktime and date:
$first_minute = mktime(0, 0, 0, date("n"), 1);
$last_minute = mktime(23, 59, 59, date("n"), date("t"));
That is for the current month. If you want to have it for any month, you have change the month and day parameter accordingly.
If you want to generate it for every month, you can just loop:
$times = array();
for($month = 1; $month <= 12; $month++) {
$first_minute = mktime(0, 0, 0, $month, 1);
$last_minute = mktime(23, 59, 59, $month, date('t', $first_minute));
$times[$month] = array($first_minute, $last_minute);
}
DEMO
With PHP 5.3, you can do
$oFirst = new DateTime('first day of this month');
$oLast = new DateTime('last day of this month');
$oLast->setTime(23, 59, 59);
In PHP 5.2
Note: as AllThecode pointed out in the comments below, this next example only works if you do the $oFirst portion first. If you add +1 month to new DateTime the result will jump an extra month ahead on the last day of the month (as of php 5.5.9).
$oToday = new DateTime();
$iTime = mktime(0, 0, 0, $oToday->format('m'), 1, $oToday->format('Y'));
$oFirst = new DateTime(date('r', $iTime));
$oLast = clone $oFirst;
$oLast->modify('+1 month');
$oLast->modify('-1 day');
$oLast->setTime(23, 59, 59);
Use mktime for generating timestamps from hour/month/day/... values and cal_days_in_month to get the number of days in a month:
$month = 1; $year = 2011;
$firstMinute = mktime(0, 0, 0, $month, 1, $year);
$days = cal_days_in_month(CAL_GREGORIAN, $month, $year);
$lastMinute = mktime(23, 59, 0, $month, $days, $year);
I think better then
$first_minute = mktime(0, 0, 0, date("n"), 1);
$last_minute = mktime(23, 59, 0, date("n"), date("t"));
is:
$first_minute = mktime(0, 0, 0, date("n"), 1);
$last_minute = mktime(23, 59, 0, date("n") + 1, 0);
This requires PHP > 5.2 and need adjustement for the "minutes" part
$year = ...; // this is your year
$month = ...; // this is your month
$month = ($month < 10 ? '0' . $month : $month);
$start = new DateTime($year . '-' . $month . '-01 00:00:00');
$end = $start->modify('+1 month -1 day -1 minute'); //perhaps this need 3 "->modify"
echo $start->format('U');
echo $end->format('U');
(not tested)
Ref: http://www.php.net/manual/en/class.datetime.php
$date = new \DateTime('now');//Current time
$date->modify("-1 month");//get last month
$startDate = $date->format('Y-m-01');
$endDate = $date->format('Y-m-t');
Best Way do like this..
$first_day = date('m-01-Y h:i:s',strtotime("-1 months"));
$last_day = date('m-t-Y h:i:s',strtotime("-1 months"));

How to get the timestamp range of this hour?

How to get the UNIX timestamp range of the current hour, i mean one of the first second and the other for the last second. so if it's 18:45 i would get the timestamp of 18:00 and 18:59.
Thanks
You can get the components of the current time with getdate(), and use mktime() to find the timestamps:
$date = getdate();
$start = mktime($date['hours'], 0, 0);
$end = $start + (60*60);
You can also use date(), which is slightly simpler:
$start = mktime(date("H"), 0, 0);
$end = $start + (60*60);
$start = mktime(date('H'), 0, 0);
$end = mktime(date('H'), 59, 59);
Could be generalized for any timestamp, not just the current time, as:
$time = time(); // some timestamp
$start = mktime(date('H', $time), 0, 0, date('n', $time), date('j', $time), date('Y', $time));
$end = mktime(date('H', $time), 59, 59, date('n', $time), date('j', $time), date('Y', $time));

Categories