I'm new in php.
I want to ask how to make increment loop date every x minus or x hours and repeat until x times.
Example :
I have time : 2016-03-22T23:00:00
I want to increment that time every 30 minutes
And repet until 6 times.
and output will be :
2016-03-22T23:00:00
2016-03-22T23:30:00
2016-03-23T00:00:00
2016-03-23T00:30:00
2016-03-23T01:00:00
2016-03-23T01:30:00
My former code form other question in stackoverflow :
<?php
$startdate=strtotime("next Tuesday");
$enddate=strtotime("+1 weeks",$startdate); //16 weeks from the starting date
$currentdate=$startdate;
echo "<ol>";
while ($currentdate < $enddate): //loop through the dates
echo "<li>",date('Y-m-d', $currentdate),"T";
echo date('H:i:s', $currentdate);
echo "</li>";
$currentdate = strtotime("+30 minutes", $currentdate); //increment the current date
endwhile; // calculate date range
echo "<ol>";?>
On that code the loop stop until desire date.
My problem is how to make increment in time until desire times..., for example 5 , 10, 10, 500 times loop?
How to code that?
PHP's DateTime feature has the perfect option to do what you want:
// Set begin date
$begin = new DateTime('2016-03-17 23:00:00');
// Set end date
$end = new DateTime('2016-03-18 23:00:00');
// Set interval
$interval = new DateInterval('PT30M');
// Create daterange
$daterange = new DatePeriod($begin, $interval ,$end);
// Loop through range
foreach($daterange as $date){
// Output date and time
echo $date->format("Y-m-dTH:i:s") . "<br>";
}
Just use for-loop for this task:
<?php
$desiredtimes = 500; // desired times
$startdate=strtotime("next Tuesday");
$currentdate=$startdate;
echo "<ol>";
for ($i = 0; $i < $desiredtimes; $i++){ //loop desired times
echo "<li>",date('Y-m-d', $currentdate),"T";
echo date('H:i:s', $currentdate);
echo "</li>";
$currentdate = strtotime("+30 minutes", $currentdate); //increment the current date
} // calculate date range
echo "<ol>";?>
Use a DateTime object, then setup a loop that will iterate exactly 6 times.
After printing the current datetime, increase the datetime object by 30 minutes.
Code: (Demo)
$dt = new DateTime("2016-03-22T23:00:00");
for ($i = 0; $i < 6; ++$i, $dt->modify('+30 minutes')) {
echo $dt->format("Y-m-d\TH:i:s") . "\n";
}
Output:
2016-03-22T23:00:00
2016-03-22T23:30:00
2016-03-23T00:00:00
2016-03-23T00:30:00
2016-03-23T01:00:00
2016-03-23T01:30:00
This was inspired by a more complex process that I scripted for CodeReview.
Related
How can I count occurrences of 14th of a month between two dates
For example between 07.05.2018 and 04.07.2018
I have 2 occurrences of the 14th
Try this. Note that I've changed your date format, but you can just do a createFromFormat if you're really keen on your own format.
$startDate = new DateTime('2018-05-07');
$endDate = new DateTime('2018-07-04');
$dateInterval = new DateInterval('P1D');
$datePeriod = new DatePeriod($startDate, $dateInterval, $endDate);
$fourteenths = [];
foreach ($datePeriod as $dt) {
if ($dt->format('d') == '14') { // Note this is loosely checked!
$fourteenths[] = $dt->format('Y-m-d');
}
}
echo count($fourteenths) . PHP_EOL;
var_dump($fourteenths);
See it in action here: https://3v4l.org/vPZZ0
EDIT
This is probably not an optimal solution as you loop through every day in the date period and check whether it's the fourteenth. Probably easier is to modify the start date up to the next 14th and then check with an interval of P1M.
You don't need to loop at all.
Here's a solution that does not loop at all and uses the less memory and performance hungry date opposed to DateTime.
$start = "2018-05-07";
$end = "2018-07-04";
$times = 0;
// Check if first and last month in the range has a 14th.
if(date("d", strtotime($start)) <= 14) $times++;
if(date("d", strtotime($end)) >= 14) $times++;
// Create an array with the months between start and end
$months = range(strtotime($start . "+1 month"), strtotime($end . "-1 month"), 86400*30);
// Add the count of the months
$times += count($months);
echo $times; // 2
https://3v4l.org/RevLg
Here's my code that display date with for loop.
Topic: Im creating a script to generate payment due(from to start).
$y = 1;
$period = 3;
$start = date('m/15/Y');
echo "<table>";
echo '<thead><th>From</th>';
echo '<th>To</th></thead>';
for ($y; $y <= $period; $y++) {
$month_mid = date("m/15/Y", strtotime($start));
$month_last = date("m/t/Y", strtotime($start));
echo '<td>'.$month_mid = date("m/t/Y", strtotime($start)).'</td>';
echo '<td>'.$month_last = date("m/15/Y", strtotime($start)).'</td></tr>';
$start = date("m/d/Y",strtotime($start." +1month"));
}
echo '</table>';
output I get:
09/15/2017 09/30/2017
10/15/2017 10/31/2017
11/15/2017 11/31/2017
I want to appear like this:
09/15/2017 09/30/2017
09/30/2017 10/15/2017
10/15/2017 10/31/2017
Im new in date php hope you can help me with this thanks.
Here you go:
$y = 1;
$period = 5;
$start = date('m/15/Y');
echo "<table>";
echo '<thead><th>From</th>';
echo '<th>To</th></thead>';
for ($y; $y <= $period; $y++) {
$month_mid = date("m/15/Y", strtotime($start));
$month_last = date("m/t/Y", strtotime($start));
echo '<tr><td>'.$month_mid = date("m/t/Y", strtotime($start)).'</td>';
echo '<td>'.$month_last = date("m/15/Y", strtotime($start)).'</td></tr>';
$start = date("m/d/Y",strtotime($start." +1month"));
}
echo "</table>";
You missed the opening and clousure of table and <tr>.
You don't want to be skipping ahead by a month in your loop. Well, not the way you are doing it here.
You should use DatePeriod::getEndDate and DatePeriod::getStartDate, along with DateTime::add to skip by semi-monthly amounts. The idea is that you only get to the next month by letting the datetime API add 15 days to a given start date, and use that to figure out the mid-month and end-month dates.
Keep everything in these date objects until you need to format and print them, and save the second one in the pair as input for the next round of the loop at the end where you just have to calculate the new second value.
I feel like you could write a function that gets the "next" date from any other first or last date of the month to simplify the loop.
(Since this is semi-monthly and not bi-weekly, you can actually just walk the months in your period, hard-coding the 15th for one value and using your end-of-month function for the second. It depends on your requirements and how complicated the API gets.)
Or
For each month in your period, calculated the mid-month (i.e., exactly 15 days from the start of the month) and end-month dates. Save them in a Collection of couplets of some sort.
Write a display routine that takes this Collection and outputs the dates, but saves the previous formatted string made from the second item in the couplet as the first item to be printed (after the first line.)
I actually prefer this one because it separates the presentation from the data abstraction, allowing you freedom to display and format the date how you see fit.
But, at the end of the day (pun not intended, but what a great pun), stop using date strings as input to figure out other dates when you have access to normalized epoch representations. This will only lead to madness.
$y = 1;
$period = 3;
$start = date('m/d/Y');
$end = date('m/t/Y');
echo "<table>";
echo '<thead><th>From</th>';
echo '<th>To</th></thead>';
for ($y; $y <= $period; $y++) {
echo '<tr><td>'.$start.'</td>';
echo '<td>'.$end.'</td></tr>';
$getLast = date('d',strtotime($end));
if($getLast >= 28) {
$start = date("m/t/Y", strtotime($start));
$end = date("m/d/Y", strtotime("+15 day", strtotime($end)));
}else {
$start = date("m/d/Y", strtotime("+15 day", strtotime($start)));
$end = date("m/t/Y",strtotime($end));
}
}
echo "</table>";
Result:
From To
09/15/2017 09/30/2017
09/30/2017 10/15/2017
10/15/2017 10/31/2017
I want to loop a date so that every time date is increment by previous date. my code is here. plz reply anyone, thanks in advance
$today = date('Y-m-d');
for($i=1; $i<=4; $i++){
$repeat = strtotime("+2 day",strtotime($today));
echo $rdate = date('Y-m-d',$repeat);
}
I want result as if today is 2016-04-04 than, 2016-04-06, 2016-04-08, 2016-04-10, 2016-04-12.
actually i want to make a reminder date where user enter reminder. lets a user want to add reminder today and want repeat it 5 time after 2days, 3days or what ever he wants, in next comming day. than how i repeat date with for loop.
Try this:
<?php
$today = date('Y-m-d');
for($i=1; $i<=4; $i++)
{
$repeat = strtotime("+2 day",strtotime($today));
$today = date('Y-m-d',$repeat);
echo $today;
}
Output:
2016-04-06
2016-04-08
2016-04-10
2016-04-12
The easiest way is what answer
aslawin
The below example is to go through the date
$begin = new DateTime($check_in);
$end = new DateTime($check_out);
$step = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($begin, $step, $end);
foreach ($period as $dt)
{
<sample code here>
}
You can try this:
$today = date('Y-m-d');
for($i=1; $i<=8; $i++){
if($i%2 == 0){
$repeat = strtotime("+$i day",strtotime($today));
echo $rdate = date('Y-m-d',$repeat);
}
}
Result:
2016-04-06
2016-04-08
2016-04-10
2016-04-12
In this example, you can use $i%2 == 0 with limit <= 8
Use a for loop with base 2, then directly output your dates:
for( $i=2; $i<9; $i=$i+2 )
{
echo date('Y-m-d', strtotime( "+ $i days" )) . PHP_EOL;
}
Result:
2016-04-06
2016-04-08
2016-04-10
2016-04-12
actually i want to make a reminder date where user enter reminder.
lets a user want to add reminder today and want repeat it 5 time after
2days, 3days or what ever he wants, in next comming day. than how i
repeat date with for loop.
I'll help with the above. First of all I will just say I have a huge personal preference towards the DateTime object over simply using date it's more flexible and a hell of a lot more readable in my opinion, so when working with dates I would always suggest using that over date()
So here is some Code:
$date = new DateTime(); // Pretend this is what the User entered. We got it via $_POST or something.
$interval = 2; // Repeat x times at y day intervals. (Not including the initial)
$repeatAmount = 2; // Repeat the reminder x times
for ($i = 0; $i <= $repeatAmount; ++$i) {
echo $date->format('d/m/Y');
$date->modify('+'. $interval .' day');
}
$date = new DateTime()Imagine this is the date the user entered, this is our starting point, our first reminder will at this time.
$interval and $repeatAmount are the interval in days, i.e. I want this to every 2 days and the amount of times you want it to repeat, in our example 2.
for ($i = 0; $i <= $repeatAmount; ++$i) { We want to loop as many times as the user says they want to repeat. Little note ++$i tends to be a very minor performance boost over $i++ in some scenarios, so it is usually better to default to that unless you specifically need to use $i++
echo $date->format('d/m/Y'); Simply print out the date, i'll let you handle the reminder logic.
$date->modify('+' . $interval . ' day'); Increment the dateTime object by the interval that the user has asked for, in our case increment by 2 days.
Any questions let me know.
I am currently attempting to get a list of dates from a current date using the following format so that I can process it and stick it in my database
Saturday/02-05-2015
So far, i've managed to get the system to output the date correctly, but can not get it to increment in single day values.
My current code to attempt to increment this is the following
$tempStartDateN = ("$splode[0]/$splode[1]/$splode[2]/$splode[3]");
echo $tempStartDateN;
$tempStartDateN = date('l/d/m/Y', strtotime($tempStartDateN . ' + 1 day'));
echo $tempStartDateN;
I am currently using explode to process the data after the increment, which works fine, but can not get the date itself to increment as long as the day name is included.
Currently, the time is got using this code, which is processed afterwords using explode
$OldDateArray = date("Y/m/d/l");
So to keep a long question short, what is the best way to increment a date that requires the day name, day, month then year?
EDIT:
Heres my current code, managed to get this far thanks to SamV
$date = date("l/d/m/Y");
echo $date;
echo ('</br>');
list($weekdayName, $dateString) = explode("/", $date, 2);
$dateObj = new \DateTime($dateString);
for($i=0; $i<=5; $i++){
$dateObj->add(new \DateInterval("P1D")); // P1D stands for "Period 1 Day"
echo $dateObj->format("l/d/m/Y"); // Sunday/03/05/2015
echo ('</br>');
}
What this does however is:
Friday/01/05/2015
Tuesday/06/01/2015
Wednesday/07/01/2015
Thursday/08/01/2015
Friday/09/01/2015
Saturday/10/01/2015
Sunday/11/01/2015
this means that date and month are swapping around, what is causing this?
You don't need to parse the week day name to add days onto a date.
$date = "Saturday/02-05-2015";
list($weekdayName, $dateString) = explode("/", $date, 2); // Parse "02-05-2015"
$dateObj = new \DateTime($dateString);
$dateObj->add(new \DateInterval("P1D")); // P1D stands for "Period 1 Day"
echo $dateObj->format("l/d/m/Y"); // Sunday/03/05/2015
I used the DateTime class, here is the documentation.
I wrote out what you are trying to do yourself, not sure what is causing your issue. This code works though.
$date = "Friday/01-05-2015";
list($weekdayName, $dateString) = explode("/", $date, 2); // Parse "01-05-2015"
$dateObj = new \DateTime($dateString);
for($i = 0; $i < 5; $i++) {
$dateObj->add(new \DateInterval("P1D")); // P1D stands for "Period 1 Day"
echo $dateObj->format("l/d/m/Y") . '<br>';
}
Outputs:
Saturday/02/05/2015
Sunday/03/05/2015
Monday/04/05/2015
Tuesday/05/05/2015
Wednesday/06/05/2015
If strtotime is able to parse a date it returns the timestamp. Why not add to it the number of seconds in a day? Smth. like $timestamp += 24 * 3600;
P.S. As far as I can understand, strtotime may accept timestamp as second argument (http://us2.php.net/manual/en/function.strtotime.php) smth. like $timestamp = strtotime('+1 day', $timestamp);
I have a function to return the difference between 2 dates, however I need to work out the difference in working hours, assuming Monday to Friday (9am to 5:30pm):
//DATE DIFF FUNCTION
// Set timezone
date_default_timezone_set("GMT");
// Time format is UNIX timestamp or
// PHP strtotime compatible strings
function dateDiff($time1, $time2, $precision = 6) {
// If not numeric then convert texts to unix timestamps
if (!is_int($time1)) {
$time1 = strtotime($time1);
}
if (!is_int($time2)) {
$time2 = strtotime($time2);
}
// If time1 is bigger than time2
// Then swap time1 and time2
if ($time1 > $time2) {
$ttime = $time1;
$time1 = $time2;
$time2 = $ttime;
}
// Set up intervals and diffs arrays
$intervals = array('year','month','day','hour','minute','second');
$diffs = array();
// Loop thru all intervals
foreach ($intervals as $interval) {
// Set default diff to 0
$diffs[$interval] = 0;
// Create temp time from time1 and interval
$ttime = strtotime("+1 " . $interval, $time1);
// Loop until temp time is smaller than time2
while ($time2 >= $ttime) {
$time1 = $ttime;
$diffs[$interval]++;
// Create new temp time from time1 and interval
$ttime = strtotime("+1 " . $interval, $time1);
}
}
$count = 0;
$times = array();
// Loop thru all diffs
foreach ($diffs as $interval => $value) {
// Break if we have needed precission
if ($count >= $precision) {
break;
}
// Add value and interval
// if value is bigger than 0
if ($value > 0) {
// Add s if value is not 1
if ($value != 1) {
$interval .= "s";
}
// Add value and interval to times array
$times[] = $value . " " . $interval;
$count++;
}
}
// Return string with times
return implode(", ", $times);
}
Date 1 = 2012-03-24 03:58:58
Date 2 = 2012-03-22 11:29:16
Is there a simple way of doing this, i.e - calculating the percentage of working hours in a week and dividing the difference using the above function - I have played around with this idea and got some very strange figures...
Or is there better way....?
This example uses PHP's built in DateTime classes to do the date math. How I approached this was to start by counting the number of full working days between the two dates and then multiply that by 8 (see notes). Then it gets the hours worked on the partial days and adds them to the total hours worked. Turning this into a function would be fairly straightforward to do.
Notes:
Does not take timestamps into account. But you already know how to do that.
Does not handle holidays. (That can be easily added by using an array of holidays and adding it to where you filter out Saturdays and Sundays).
Requires PHP 5.3.6+
Assumes an 8 hour workday. If employees do not take lunch change $hours = $days * 8; to $hours = $days * 8.5;
.
<?php
// Initial datetimes
$date1 = new DateTime('2012-03-22 11:29:16');
$date2 = new DateTime('2012-03-24 03:58:58');
// Set first datetime to midnight of next day
$start = clone $date1;
$start->modify('+1 day');
$start->modify('midnight');
// Set second datetime to midnight of that day
$end = clone $date2;
$end->modify('midnight');
// Count the number of full days between both dates
$days = 0;
// Loop through each day between two dates
$interval = new DateInterval('P1D');
$period = new DatePeriod($start, $interval, $end);
foreach ($period as $dt) {
// If it is a weekend don't count it
if (!in_array($dt->format('l'), array('Saturday', 'Sunday'))) {
$days++;
}
}
// Assume 8 hour workdays
$hours = $days * 8;
// Get the number of hours worked on the first day
$date1->modify('5:30 PM');
$diff = $date1->diff($start);
$hours += $diff->h;
// Get the number of hours worked the second day
$date1->modify('8 AM');
$diff = $date2->diff($end);
$hours += $diff->h;
echo $hours;
See it in action
Reference
DateTime Class
DatePeriod Class
DateInterval Class
Here's what I've come up with.
My solution checks the start and end times of the original dates, and adjusts them according to the actual start and end times of the work day (if the original start time is before work's opening time, it sets it to the latter).
After this is done to both start and end times, the times are compared to retrieve a DateInterval diff, calculating the total days, hours, etc. The date range is then checked for any weekend days, and if found, one total day is reduced from the diff.
Finally, the hours are calculated as commented. :)
Cheers to John for inspiring some of this solution, particularly the DatePeriod to check for weekends.
Gold star to anyone who breaks this; I'll be happy to update if anyone finds a loophole!
Gold star to myself, I broke it! Yeah, weekends are still buggy (try starting at 4pm on Saturday and ending at 1pm Monday). I will conquer you, work hours problem!
Ninja edit #2: I think I took care of the weekend bugs by reverting the start and end times to the most recent respective weekday if they fall on a weekend. Got good results after testing a handful of date ranges (starting and ending on the same weekend barfs, as expected). I'm not entirely convinced this is as optimized / simple as it could be, but at least it works better now.
// Settings
$workStartHour = 9;
$workStartMin = 0;
$workEndHour = 17;
$workEndMin = 30;
$workdayHours = 8.5;
$weekends = ['Saturday', 'Sunday'];
$hours = 0;
// Original start and end times, and their clones that we'll modify.
$originalStart = new DateTime('2012-03-22 11:29:16');
$start = clone $originalStart;
// Starting on a weekend? Skip to a weekday.
while (in_array($start->format('l'), $weekends))
{
$start->modify('midnight tomorrow');
}
$originalEnd = new DateTime('2012-03-24 03:58:58');
$end = clone $originalEnd;
// Ending on a weekend? Go back to a weekday.
while (in_array($end->format('l'), $weekends))
{
$end->modify('-1 day')->setTime(23, 59);
}
// Is the start date after the end date? Might happen if start and end
// are on the same weekend (whoops).
if ($start > $end) throw new Exception('Start date is AFTER end date!');
// Are the times outside of normal work hours? If so, adjust.
$startAdj = clone $start;
if ($start < $startAdj->setTime($workStartHour, $workStartMin))
{
// Start is earlier; adjust to real start time.
$start = $startAdj;
}
else if ($start > $startAdj->setTime($workEndHour, $workEndMin))
{
// Start is after close of that day, move to tomorrow.
$start = $startAdj->setTime($workStartHour, $workStartMin)->modify('+1 day');
}
$endAdj = clone $end;
if ($end > $endAdj->setTime($workEndHour, $workEndMin))
{
// End is after; adjust to real end time.
$end = $endAdj;
}
else if ($end < $endAdj->setTime($workStartHour, $workStartMin))
{
// End is before start of that day, move to day before.
$end = $endAdj->setTime($workEndHour, $workEndMin)->modify('-1 day');
}
// Calculate the difference between our modified days.
$diff = $start->diff($end);
// Go through each day using the original values, so we can check for weekends.
$period = new DatePeriod($start, new DateInterval('P1D'), $end);
foreach ($period as $day)
{
// If it's a weekend day, take it out of our total days in the diff.
if (in_array($day->format('l'), ['Saturday', 'Sunday'])) $diff->d--;
}
// Calculate! Days * Hours in a day + hours + minutes converted to hours.
$hours = ($diff->d * $workdayHours) + $diff->h + round($diff->i / 60, 2);
As the old saying goes "if you want something done right do it yourself". Not saying this is optimal but its atleast returning the correct amount of hours for me.
function biss_hours($start, $end){
$startDate = new DateTime($start);
$endDate = new DateTime($end);
$periodInterval = new DateInterval( "PT1H" );
$period = new DatePeriod( $startDate, $periodInterval, $endDate );
$count = 0;
foreach($period as $date){
$startofday = clone $date;
$startofday->setTime(8,30);
$endofday = clone $date;
$endofday->setTime(17,30);
if($date > $startofday && $date <= $endofday && !in_array($date->format('l'), array('Sunday','Saturday'))){
$count++;
}
}
//Get seconds of Start time
$start_d = date("Y-m-d H:00:00", strtotime($start));
$start_d_seconds = strtotime($start_d);
$start_t_seconds = strtotime($start);
$start_seconds = $start_t_seconds - $start_d_seconds;
//Get seconds of End time
$end_d = date("Y-m-d H:00:00", strtotime($end));
$end_d_seconds = strtotime($end_d);
$end_t_seconds = strtotime($end);
$end_seconds = $end_t_seconds - $end_d_seconds;
$diff = $end_seconds-$start_seconds;
if($diff!=0):
$count--;
endif;
$total_min_sec = date('i:s',$diff);
return $count .":".$total_min_sec;
}
$start = '2014-06-23 12:30:00';
$end = '2014-06-27 15:45:00';
$go = biss_hours($start,$end);
echo $go;