DatePeriod does not show 00:00 - php

I create an attendance system for employees working in a company and I need to check the time intervals while adding records. So I have to create an array of hours. With the DatePeriod, I output hours in a certain time interval. It works but does not show anything when 00:00 is in two different time intervals.
Normally it should output the following range:
00:00
01:00
02:00
03:00
04:00
But shows nothing.
<?php
$a = '23:00';
$b = '05:00';
$period = new DatePeriod(
new DateTime($a),
new DateInterval('PT1H'),
new DateTime($b),
DatePeriod::EXCLUDE_START_DATE
);
foreach ($period as $date) {
echo $date->format("H:i\n");
}
?>
Thank you

If you dump dates you pass to DatePeriod you will see they are both today so your start date is after the end date. And really you mean in this case: give me hours between today 23:00 and tomorrow 05:00 - so if this happen just add 1 day to your end date.
<?php
$a = '23:00';
$b = '05:00';
$aDate = new DateTime($a);
$bDate = new DateTime($b);
if ($aDate > $bDate) {
$bDate->add(new DateInterval('P1D'));
}
$period = new DatePeriod(
$aDate,
new DateInterval('PT1H'),
$bDate,
DatePeriod::EXCLUDE_START_DATE
);
foreach ($period as $date) {
echo $date->format("H:i\n");
}
Output:
00:00
01:00
02:00
03:00
04:00

Related

Minutes interval between two times past midnight in php

Users are allowed to pick a time for delivery up until the closing time of the store which can be 1am.
The list should should show all times up to 1am even if it is after midnight.
example 1: User arrives at 18:00 they see 18:00, 18:30, 19:00 and so on up until 00:30, 01:00
example 2: user arrives at 00:10 should see
00:30, 01:00 not
01:00, 01:30, 02:00, 02:30 etc because after midnight has become a has become a new day/date.
I am getting 30 minute time intervals between two times, it is fine as long as both times are in the same day e.g. 17:00 and 23:00. If the end time is past midnight I am not able to get the intervals so 17:00 to 01:00 doesn't give any intervals.
I understand 01:00 is another day but not quite sure how to fix it using a dynamic date. I keep thinking current day +1 will be fine unless it is after mindight then it will be an extra day if that makes sense.
Here's my code:
$timestamp = time() + 60*60;
$earliest = date("h:i ",$timestamp);
$period = new DatePeriod(
new DateTime($earliest),
new DateInterval('PT30M'),
new DateTime('01:00')
);
foreach ($period as $date) {
echo '<option value="">'.$date->format("H:i").'</option>';
}
Because 24:00 works as 00:00 I tried 25:00 but that didn't work. Any help appreciated!
UPDATE: following the answer below coverted to dynamic date, if I use date like:
$start = date('Y-m-d H:i');
$startdate = date('Y-m-d');
$end = date('Y-m-d', strtotime($startdate . ' +1 day'))." 01:00";
$period = new DatePeriod(
DateTime::createFromFormat('Y-m-d H:i','2020-04-03 17:00'),
new DateInterval('PT30M'),
DateTime::createFromFormat('Y-m-d H:i','2020-04-04 01:00')
);
After midnight it's another day added on which is problematic.
You also have to mention exact dates and not just time as 01:00. Because this way, it assumes the current date and hence you really can't have a time period between 17:00 and 01:00 on the same day. Below is how you would do it:
<?php
$period = new DatePeriod(
DateTime::createFromFormat('Y-m-d H:i','2020-04-03 17:00'),
new DateInterval('PT30M'),
DateTime::createFromFormat('Y-m-d H:i','2020-04-04 01:00')
);
foreach ($period as $date) {
echo $date->format("H:i"),PHP_EOL;
}
Demo: https://3v4l.org/5sj9Z
Update:
Since you have only times and not dates, you create DateTime objects, compare them, add 1 day to end time if it's smaller and then loop over the intervals using DatePeriod
<?php
$times = [
['18:00','01:00'],
['17:00','23:00'],
['00:10','01:00']
];
foreach($times as $time){
$start_time = DateTime::createFromFormat('H:i',$time[0]);
$end_time = DateTime::createFromFormat('H:i',$time[1]);
if($end_time < $start_time){
$end_time->add(new DateInterval('P1D'));
}
$period = new DatePeriod(
$start_time,
new DateInterval('PT30M'),
$end_time
);
echo $start_time->format('Y-m-d H:i:s'),' ',$end_time->format('Y-m-d H:i:s'),PHP_EOL;
foreach ($period as $date) {
echo $date->format("H:i"),PHP_EOL;
}
echo PHP_EOL;
}
Demo: https://3v4l.org/Ldpst
You can lose the whole timestamp calculation and have it all handled by DateTime:
// here we get the next round delivery time
$nextAvailableHalfHour = getNextHalfHourMark();
$todayMidnight = new DateTime('today'); // this creates today with time 00:00:00
$todayOneOclock = new DateTime('today 01:00'); // this creates today with time 01:00:00
// this condition says if we're now between midnight and 1 o'clock, use today
// otherwise use tomorrow
$endDate = $nextAvailableHalfHour >= $todayMidnight && $nextAvailableHalfHour <= $todayOneOclock
? $todayOneOclock
: new DateTime('tomorrow 01:00'); // create specific time tomorrow
$period = new DatePeriod(
$nextAvailableHalfHour,
new DateInterval('PT30M'),
$endDate
);
/**
* Gets the next available time with round half hour (:00 or :30).
*/
function getNextHalfHourMark(): DateTime
{
$now = new DateTime(); // create current date and time
$currentMinutes = (int) $now->format('i');
// if we are between :00 and :30
if ($currentMinutes > 0 && $currentMinutes < 30) {
// set to :30 minutes of current hour
$now->setTime($now->format('H'), 30);
// else if we are between :30 and :00
} elseif ($currentMinutes > 30 && $currentMinutes <= 59) {
// set to :00 minutes of next hour
$now->setTime($now->format('H') + 1, 00);
}
return $now;
}
The tomorrow and today strings are enabled by relative formats.

how can I create a list of times in php?

I have x.
x is minutes.
I have a string start_time like: 7:00
And I have a string end_time like: 14:00
how can print a list of time with increase x minutes for each loop?
I want print something like this:
if x = 30
7:00 - 7:30
7:30 - 8:00
...
13:30 - 14:00
I try do it with math functions in php like this:
$time = '7:00';
$mm = $hh = 0;
$str = explode(":",$time);
if(($str[1]+ $x) > 60)
{
...
}
but it there a more simple method? can date function in php do it?
You can use DatePeriod together with DateInterval to achieve this.
Create two DateTime intervals with your start and end times, and a DateInterval instance with the number of minutes you need. Then, create a DatePeriod with this information, and iterate over it to show the resulting times:
<?php
$minutes = 15;
$start = "07:00";
$end = "14:00";
$startDate = DateTime::createFromFormat("H:i", $start);
$endDate = DateTime::createFromFormat("H:i", $end);
$interval = new DateInterval("PT".$minutes."M");
$dateRange = new DatePeriod($startDate, $interval, $endDate);
foreach ($dateRange as $date) {
echo $date->format("H:i")."<br>";
}
Demo
Result
07:00
07:15
07:30
07:45
08:00
08:15
08:30
08:45
09:00
09:15
09:30
09:45
10:00
10:15
// etc
You can use the DatePeriod object along with a desired DateInterval object.
Example: https://3v4l.org/lg8QW
$start = new \DateTime('07:00');
$end = new \DateTime('14:00');
$interval = new \DateInterval('PT1M'); //change to desired interval
$periods = new \DatePeriod($start, $interval, $end);
foreach ($periods as $period) {
echo $period->format('H:i') ;
}
Result:
07:00
07:01
07:02
07:03
07:04
07:05
07:06
07:07
07:08
07:09
07:10
07:11
07:12
07:13
07:14
07:15
07:16
07:17
07:18
07:19
07:20
//...
13:59
You can use DateTime object.
just like this:
<?php
$start_time = '7:00';
$date1 = DateTime::createFromFormat('H:i', $start_time);
$old = $start_time;
while (true) {
$date1->modify('+30 min');
echo $old . '-' . $date1->format('H:i').PHP_EOL;
$old = $date1->format('H:i');
if ($old == '14:00') {
break;
}
}
Output:
7:00-07:30
07:30-08:00
08:00-08:30
...
13:30-14:00
More info just see the manual here: DateTime

PHP DatePeriod does not return duplicate hours during DST change?

I am looping over a series of hours using DatePeriod. This works for periods not containing DST changes. It works for a missing hour during switch to DST. But it does NOT work for a double hour during switch to non-DST season.
Base code:
$zone = new DateTimeZone('Europe/Amsterdam');
$start = new DateTime('2016-01-01', $zone);
$end = new DateTime('2016-01-02', $zone);
$int = new DateInterval('PT1H');
$period = new DatePeriod($start, $int, $end);
foreach($period as $point)
echo $point->format('Y-m-d H:i') . "\n";
This gives:
2016-01-01 00:00
2016-01-01 01:00
2016-01-01 02:00
...
2016-01-01 23:00
For $start = '2016-03-27' and $end = '2016-03-28' it gives:
2016-03-27 00:00
2016-03-27 01:00
2016-03-27 03:00
....
This is expected because 02:00 does not exist that day.
But for $start = '2016-10-30' and $end = '2016-10-31' it does not work:
2016-10-30 00:00
2016-10-30 01:00
2016-10-30 02:00
2016-10-30 03:00
....
We expect a double hour. It is not there. Outputting the timestamps using $point->format('U') shows that the timestamps are correct and there is a jump of 7200 seconds between 1 and 2 o'clock instead of the expected 3600.
Why does PHP not follow my specified interval of 1 hour? How can I get the period to include this hour? I have tried $int = 'PT60M' and similar, but that does not change anything.

How can i make chunks of 15 minutes from two terminal points of time stamp

How can i make chunks of 15 minutes from two terminal points of time stamp.Like,i have a given span of time say 6:00 PM to 10:00 PM. I want to divide this time span into chunks of 15 minutes like,
6:00-6:15
6:15-6:30
6:30-6:45 and so on upto 10:00 pm
Please any one can help?
Sounds like you need something like:
$tz = new DateTimeZone('UTC');
$from = new DateTime('2013-11-13 18:00:00', $tz);
$to = new DateTime('2013-11-13 22:00:00', $tz);
$times = array();
while ($from <= $to) {
$times[] = $from->format('r');
$from->modify('+15 minutes');
}
You can use the DatePeriod class:
$begin = new DateTime('6:00 PM');
$end = new DateTime('10:00 PM');
$end = $end->modify('+15 minutes'); // to get the last interval, too
$interval = new DateInterval('PT15M');
$timerange = new DatePeriod($begin, $interval ,$end);
foreach($timerange as $time){
echo $time->format("h:i") . "<br>";
}
Demo!

For loop involving a range of dates

I have a date range in which I want to process between each day. So for example between
2013-03-01 00:00:00 and 2013-04-01 00:00:00 there are 31 days
so my for loop is something like this
$date_next = $date_from;
for($i=0;$i<31-1;$i++)
{
$date_next_str = new DateTime($date_next);
$date_next_1_str = new DateTIme($date_next);
$date_next_1_str->modify("+1 day");
$date_next_1_str->modify("-1 second");
$date_next_1_str->modify("+1 day");
$date_next = $date_next_1_str->date;
}
so in my first loop it will be from 2013-03-01 00:00:00 to 2013-03-01 23:59:59
However when I assign $date_next_1_str->date to $date_next at the end of the for loop, the $date_next still shows 2013-03-01 23:59:59, which was supposed to be 2013-03-02 00:00:00.
Anyone can help me with this? Thanks in advance!
You can do this quite easily using PHP's DateTime, DateInterval and DatePeriod objects:-
$startDate = \DateTime::createFromFormat('Y-m-d H:i:s', '2013-03-01 00:00:00');
$endDate = \DateTime::createFromFormat('Y-m-d H:i:s', '2013-04-01 00:00:00');
$interval = new \DateInterval('P1D');
$endDate->add($interval); //As otherwise last day will be missed off.
$period = new \DatePeriod($startDate, $interval, $endDate);
foreach($period as $date){
//each $date is an instance of DateTime
var_dump($date); // Or whatever you want to do with the DateTime object
}

Categories