Minutes interval between two times past midnight in php - 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.

Related

DatePeriod does not show 00:00

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

How to find the Time Difference between a PM time and AM time?

In my form there are 2 Time Pickers where user can select a from time and to time. It doesn't have a date associated with it. And for a report generating purpose I've to calculate the time difference between them. It works perfectly to if the From and to Time is "06:00 to 10:00" but if the from and to time is "21:00 to 02:00" I get a time difference of 19 hours. Could you please help me to fix this.
For this case "21:00 to 02:00" the time difference should be 5 hours.
This is the Code
$datetime1 = new \DateTime('09:30 PM');
$datetime2 = new \DateTime('02:00 AM');
$interval = $datetime1->diff($datetime2);
echo $interval->format('%hh');
exit;
The difference becomes negative If $totime is less than $fromtime.
DateInterval->invert == 1 indicates that. This is used with this short solution to correct the result.
$fromtime = '09:30 PM';
$totime = '02:00 AM';
$diff = date_create($fromtime)->diff(date_create($totime));
$hours = $diff->invert ? 24-$diff->h : $diff->h;
echo $hours; //5
Since you have 2 date pickers one for from time and another to time, the former will always be smaller than the latter. Hence when from time is larger than to time it means user has selected to from the next day. If we don't add a date for calculating difference, PHP will assume today's date by default. We can easily fix this by adding a condition to compare the times and prepend the dates accordingly. Below is the updated code.
<?php
$fromtime = '09:30 PM';
$totime = '02:00 AM';
$now = new \DateTime();
$today = $now->format('Y-m-d'); // Store current date
$now->add(new DateInterval('P1D')); // Add one day to current date to get next date
$nextDay = $now->format('Y-m-d'); // Store next date
if($fromtime > $totime) // If from time is bigger than to time, it means to is a next day
{
$fromdatetime = "$today $fromtime";
$todatetime = "$nextDay $totime";
}
else
{
$fromdatetime = "$today $fromtime";
$todatetime = "$today $totime";
}
$datetime1 = new \DateTime($fromdatetime);
$datetime2 = new \DateTime($todatetime);
$interval = $datetime1->diff($datetime2);
echo $interval->format('%hh');
?>

How to perform if statement for a certain timeperiod

I want to perform certain tasks in PHP between Monday 10:00am till Saturday 10:00am and I want to perform other tasks between Saturday 10:30am till Monday 10am. Every week.
I am sorry if that's a silly question. Any help would be highly appreciated.
if you are running a time triggered task run a cron job or if it is a user triggered like website and you want to change page according to day then use if else statement to select task.
you can get the time in weekday and hour:minute::second for if else selection using this
$d = new DateTime('Sunday,23:23:48 '); //set time day time format
echo $d->format('l , H:i:s ');
$date = new DateTime(); // get current datetime
echo $date->format('l , H:i:s '); //php get time in day time format
//output example Sunday , 23:23:48 Sunday , 23:34:47
$currentTime = time();
$time = date('H:i',$currentTime);
$date = date('h:i:s a', time());
$timestamp = strtotime($date);
$day = date('D', $timestamp);
if ( ( ($day == "Sat") && ($time < 11) ) || ($day == "Mon" && $time > 9) )
{
# weekday then truncate table
}

PHP Add two hours to a date within given hours using function

How would I structure the conditions to add two hours only to dates between 08:30 in the morning until 18:30 of the evening, excluding Saturday and Sunday?
In the case that a time near the border (e.g. 17:30 on Tuesday) is given, the left over time should be added to the beginning of the next "valid" time period.
For example: if the given date was in 17:30 on Tuesday, the two hour addition would result in 9:30 on Wednesday (17:30 + 1 hour = 18:30, 8:30 + the remainder 1 hour = 9:30). Or if the given date was in 17:00 on Friday, the result would be 9:00 on Monday (17:00 Friday + 1.5 hours = 18:30, 8:30 Monday + the remainder .5 hours = 9:00)
I know how to simply add two hours, as follows:
$idate1 = strtotime($_POST['date']);
$time1 = date('Y-m-d G:i', strtotime('+120 minutes', $idate1));
$_POST['due_date'] = $time1;
i have tried this this function and it works great except when i use a date like ( 2013-11-26 12:30 ) he gives me ( 2013-11-27 04:30:00 )
the problem is with 12:30
function addRollover($givenDate, $addtime) {
$starttime = 8.5*60; //Start time in minutes (decimal hours * 60)
$endtime = 18.5*60; //End time in minutes (decimal hours * 60)
$givenDate = strtotime($givenDate);
//Get just the day portion of the given time
$givenDay = strtotime('today', $givenDate);
//Calculate what the end of today's period is
$maxToday = strtotime("+$endtime minutes", $givenDay);
//Calculate the start of the next period
$nextPeriod = strtotime("tomorrow", $givenDay); //Set it to the next day
$nextPeriod = strtotime("+$starttime minutes", $nextPeriod); //And add the starting time
//If it's the weekend, bump it to Monday
if(date("D", $nextPeriod) == "Sat") {
$nextPeriod = strtotime("+2 days", $nextPeriod);
}
//Add the time period to the new day
$newDate = strtotime("+$addtime", $givenDate);
//print "$givenDate -> $newDate\n";
//print "$maxToday\n";
//Get the new hour as a decimal (adding minutes/60)
$hourfrac = date('H',$newDate) + date('i',$newDate)/60;
//print "$hourfrac\n";
//Check if we're outside the range needed
if($hourfrac < $starttime || $hourfrac > $endtime) {
//We're outside the range, find the remainder and add it on
$remainder = $newDate - $maxToday;
//print "$remainder\n";
$newDate = $nextPeriod + $remainder;
}
return $newDate;
}
I don't know if you still need this but here it is anyway. Requires PHP 5.3 or higher
<?php
function addRollover($givenDate, $addtime) {
$datetime = new DateTime($givenDate);
$datetime->modify($addtime);
if (in_array($datetime->format('l'), array('Sunday','Saturday')) ||
17 < $datetime->format('G') ||
(17 === $datetime->format('G') && 30 < $datetime->format('G'))
) {
$endofday = clone $datetime;
$endofday->setTime(17,30);
$interval = $datetime->diff($endofday);
$datetime->add(new DateInterval('P1D'));
if (in_array($datetime->format('l'), array('Saturday', 'Sunday'))) {
$datetime->modify('next Monday');
}
$datetime->setTime(8,30);
$datetime->add($interval);
}
return $datetime;
}
$future = addRollover('2014-01-03 15:15:00', '+4 hours');
echo $future->format('Y-m-d H:i:s');
See it in action
Here's an explanation of what's going on:
First we create a DateTime object representing our starting date/time
We then add the specified amount of time to it (see Supported Date and Time Formats)
We check to see if it is a weekend, after 6PM, or in the 5PM hour with more than 30 minutes passed (e.g. after 5:30PM)
If so we clone our datetime object and set it to 5:30PM
We then get the difference between the end time (5:30PM) and the modified time as a DateInterval object
We then progress to the next day
If the next day is a Saturday we progress to the next day
If the next day is a Sunday we progress to the next day
We then set our time to 8:30AM
We then add our difference between the end time (5:30PM) and the modified time to our datetime object
We return the object from the function

Is current date within specified date/time range in PHP

I am creating a website that allow deliveries only within certain delivery time frames.
Here is an example of exactly what I'm looking for:
FakeCompany delivers on Wednesday and allows customers to place orders between Friday and Tuesday with a cutoff time of 11 PM on Tuesday night.
I need to figure out when the customer logs in if ordering is allowed (between Friday - Tuesday 11 PM). I also need to know how much longer they have to order.
I know the PHP date('N') function that Friday is 5:
date('N', strtotime('Friday'));
and Tuesday is 1:
date('N', strtotime('Tuesday'));
These time ranges may change, so I need a simple solution.
Here is what I started with, and now I'm lost on how to do this.
//Set today and get from database start / end days and end time
$today = (int)date('N');
$startDay = (int)date('N', strtotime('Friday'));
$endDay = (int)date('N', strtotime('Tuesday'));
$endDayTime = '11:00:00';
//If today is before start date
if($today >= $startDay && $today <= $endDay){
//This works only if the end date is not the following week
//It also needs to be before end day time!
}
I think I need to get the date of the week based on the DAY (Friday) and convert that to this weeks Friday if Friday has not passed or next weeks Friday and do the same with end date.
Then I need to know if today is between those dates / times.
$now = new DateTime();
$tuesday = new DateTime('last Tuesday');
$friday = new DateTime('Friday 11pm');
if ($tuesday < $now && $now < $friday) {
$interval = $friday->diff($now);
echo $interval->format('%d day %h hours %i minutes left to order');
}
else {
echo "you can't order now";
}
See it in action
Here is a function to check that today is an approved day then if its tuesday also make sure it is before 11pm:
/*
Acceptable days:
5 - friday
6 - saturday
7 - sunday
1 - monday
2 - tuesday
*/
//Can they order today?
if(in_array(date('N'),array(1,2,5,6,7))){
//if today is tuesday is it before 11pm?
if(date('N') == 2){
if(date('H')<23){
//23 = 11pm in 24 hour time
//Then can order
}
else{
//Then CANT order
}
}
//Its not tuesday so we dont care what time it is they can order
}
for the end day I think you could do it like this:
$endDay = (int)date('N', strtotime('Friday') + 3 * 24 * 3600 + 23 * 3600);
strtotime('Friday') to get friday and add 3 days of 24 hours to it, and it'll be Tuesday 0 am. Then you add 23 hours time to it as it finish at 11pm.
$today = (int)date('N');
$startDay = (int)date('N', strtotime('Friday'));
$endDay = (int)date('N', strtotime('Friday') + 3 * 24 * 3600 + 23 * 3600);
//If today is before start date
if($today >= $startDay && $today <= $endDay){
//now it works
}
Here is exactly what I am looking for.
The dates provided may not be this week or even this month, so we need to figure out based on the date what the day of the week was and set the date on this week or next week to same day depending on today (kinda confusing).
See It In Action
//IF USING A DATABASE TO STORE DATE/TIME
//Get route times
//When Using Database: $query = "SELECT * FROM routes WHERE id = '".$user['route_one']."'";
//When Using Database: $result = $this->query($query);
//When Using Database: $route = $this->fetchArray($result);
//Set date vaiables
$thisWeek = new DateTime();
$routeStart = new DateTime(date('Y-m-d H:i:s', strtotime('2013-04-21 00:00:00')));
//When Using Database: $routeStart = new DateTime(date('Y-m-d H:i:s', strtotime($route['start_time'])));
$routeEnd = new DateTime(date('Y-m-d H:i:s', strtotime('2013-04-24 00:00:00')));
//When Using Database: $routeEnd = new DateTime(date('Y-m-d H:i:s', strtotime($route['end_time'])));
$interval = $routeStart->diff($routeEnd);
$numDays = abs($interval->format('%d'));
//Check if today is past or on the start date, else start date is next week, and set day of week
if($thisWeek->format('N') >= $routeStart->format('N')){
$startDate = $thisWeek->modify('last '.$routeStart->format('l'));
}
else{
$startDate = $thisWeek->modify($routeStart->format('l'));
}
//Now that we know the start date add the amount of days to the start date to create the end date
$endDate = new DateTime($startDate->format('Y-m-d H:s:i'));
$endDate->modify('+'.$numDays.' days '.$routeEnd->format('H').' hours');
//Check to see if user is within the time range to order or not
$today = new DateTime();
if($startDate <= $today && $today <= $endDate){
//Find out how much longer ordering can take place
$interval = $endDate->diff($today);
$output = 'Allowed to order!<br>';
$output .= '<div id="orderTimeCounter">'.$interval->format('%d days %h hours %i minutes left to order').'</div>';
}
else{
//If today is before start date set start date to THIS week otherwise NEXT week
if($startDate >= $today){
$startDate = $startDate->modify('this '.$routeStart->format('l'));
}
else{
$startDate = $startDate->modify('next '.$routeStart->format('l'));
}
//Find out how much longer until ordering is allowed
$interval = $today->diff($startDate);
$output = 'Not allowed to order!';
$output .= '<div id="orderTimeCounter">'.$interval->format('%d days %h hours %i minutes until you can order').'</div>';
}
echo $output;

Categories