Carbon add hours issue - php

I'm struggling to understand why Carbon addHours() is not returning the proper time.
This is what i have in my controller :
public function create(Request $request)
{
$locationId = $request->input('location_id');
$beginningDate = $request->input('beginning_date');
$beginningTime = $request->input('beginning_time');
// $beginningDate = $request->input('beginning_date')->format('d-m-Y');
// $beginningTime = $request->input('beginning_time')->format('H:m');
$duration = $request->input('duration');
$totalPrice=PriceList::where('duration_to_hours', $duration)->value('price');
$reservationStartingDate = $beginningDate. ','.$beginningTime;
$calculateReservationDates = Carbon::parse($reservationStartingDate)->addHours($duration);
$endDate= $calculateReservationDates->format('d-m-Y');
$endTime = $calculateReservationDates->format('H:m');
$reservedCount = Reservation::where('beginning_date', '>=', $endDate)
->where('end_date', '>=', $beginningDate )
->where('beginning_time', '<=', $endTime)
->where('end_time', '>=', $beginningTime)
->count();
$totalBoxes = Box::where('location_id', $locationId)->count();
dd($endDate, $endTime);
$available = false;
if($reservedCount < $totalBoxes){
$available = true;
}
return view('checkout', compact('locationId', 'totalPrice', 'endDate', 'endTime', 'beginningDate', 'beginningTime', 'duration', 'available'));
}
But if for example the beginning time is 10:50 am and the duration is one hour, based on my logic it should return the $endTime to be 11.50 but it's only returning 11.04.
I do not get what I'm missing, do you have any idea?
Thank you
UPDATE
Here's the dd() of $reservationStartingDate :
^ "2022-04-22,00:53"

I think the H:m is wrong it's should be like this
$endTime = $calculateReservationDates->format('H:i');
m is refer to month, not minute. For minute, use i.
I hope it's helpful

// Y - year
// m - month - not minutes
// d - day
// H - hours in 24h format default UTC
// i - minutes
// s - seconds
$beginningDate = '2022-04-07';
$beginningTime = '10:30'; // 24h format UTC
// "2022-04-07 10:30" - you need this format
$reservationStartingDate = "$beginningDate $beginningTime";
$result = Carbon::createFromFormat('Y-m-d H:i', $reservationStartingDate)->addHours(1);
Result with an hour added
Carbon\Carbon #1649331000 {#1724
date: 2022-04-07 11:30:00.0 UTC (+00:00),
}

Related

Yii2 - how to get a current quarter without the past quarter?

I've a problem here. I need to get a quarter of the year without the past quarter. F.e:
In my database I have a field created_at, which saves the timestamp of service created. I need to not involve those services, which was made in the past quarter. How should I do that?
I'm trying to write a SQL function like this to not involve those services, which was made in the past quarter:
$services= Service::find()
->where([
'client_service.created' => function ($model) {
return ceil(date('n') / 3) - 4;
But I guess I'm wrong. Thanks for any help.
Edited:
$services= Service::find()
->select(['client.id as client_id'])
->joinWith('client')
->where([
'service.type' => Service::TYPE,
'service.is_archived' => Service::ARCHIVED,])
->andWhere([
'or',
['client_service.status' => ClientService::STATUS_NEGATIVE],
[client_service.created' => function ($model) {
return ceil(date('n') / 3) - 4;]
You are storing timestemp in db for service date , we can find current Quarter start date and end date from current month and use in query.
$current_month = date('m');
$current_year = date('Y');
if($current_month>=1 && $current_month<=3)
{
$start_date = strtotime($current_year.'-01-01 00:00:00');
$end_date = strtotime($current_year.'-03-31 23:59:59');
}
else if($current_month>=4 && $current_month<=6)
{
$start_date = strtotime($current_year.'-04-01 00:00:00');
$end_date = strtotime($current_year.'-06-30 23:59:59');
}
else if($current_month>=7 && $current_month<=9)
{
$start_date = strtotime($current_year.'-07-01 00:00:00');
$end_date = strtotime($current_year.'-09-30 23:59:59');
}
else if($current_month>=10 && $current_month<=12)
{
$start_date = strtotime($current_year.'-10-01 00:00:00');
$end_date = strtotime($current_year.'-12-31 23:59:59');
}
Use this $start_date and $end_date timestemp in Query as below :
$services= Service::find()
->select(['client.id as client_id'])
->joinWith('client')
->where([
'service.type' => Service::TYPE,
'service.is_archived' => Service::ARCHIVED,])
->andWhere([
'or',
['client_service.status' => ClientService::STATUS_NEGATIVE],
['between', 'client_service.created', $start_date, $end_date]
])
Find start and end date of quarter
$date = new \DateTime(); // Current Date and Time
$quarter_start = clone($date);
// Find the offset of months
$months_offset = ($date->format('m') - 1) % 3;
// Modify quarter date
$quarter_start->modify(" - " . $months_offset . " month")->modify("first day of this month");
$quarter_end = clone($quarter_start);
$quarter_end->modify("+ 3 month");
$startDate = $quarter_start->format('Y-m-d');
$endDate = $quarter_end->format('Y-m-d');
Query
$services= Service::find()
->select(['client.id as client_id'])
->joinWith('client')
->where([
'service.type' => Service::TYPE,
'service.is_archived' => Service::ARCHIVED,])
->andWhere([
'or',
['client_service.status' => ClientService::STATUS_NEGATIVE],
['between', 'date_format(FROM_UNIXTIME(client_service.created), "%Y-%m-%d")', $startDate, $endDate]
You can also use mysql Quarter() to achieve the result.

Carbon: Get start and end date of week when knowing week in year and year

Carbon provides the function weekOfYear to get the week of the year as integer. However I need to go the other way round to get the a date based on the year + the week of the year.
Carbon::now()->weekOfYear(); // todays week of the year
E.g.
year: 2016
week of year: 42
As a result i need the start and end date of this given week. However i cannot find a fitting function in the Carbon docs
Carbon is a wrapper for PHP's DateTime, so you can use setISODate:
$date = Carbon::now(); // or $date = new Carbon();
$date->setISODate(2016,42); // 2016-10-17 23:59:59.000000
echo $date->startOfWeek(); // 2016-10-17 00:00:00.000000
echo $date->endOfWeek(); // 2016-10-23 23:59:59.000000
/**
* #return array{0: \DateTime, 1: \DateTime}
*/
public static function getWeekDates(\DateTimeInterface $selectedDate): array
{
$daysFromMonday = (int) $selectedDate->format('N') - 1;
$fromDate = \DateTimeImmutable::createFromInterface($selectedDate)->modify("-{$daysFromMonday} days");
$toDate = $fromDate->modify('+6 days');
return [
\DateTime::createFromImmutable($fromDate),
\DateTime::createFromImmutable($toDate),
];
}
This returns date of Monday and Sunday (iso week number).
If you wish to know dates of Sunday and Saturday, you can easily modify the function (replace 'N' with 'w' in format) and remove -1
$WeekArray = array();
$FirstDate = Carbon::now()->addYears(-2);
$LastDate = Carbon::now()->addYears(2);
while ($FirstDate <= $LastDate) {
$WeekNumber = Carbon::parse($FirstDate)->weekOfYear;
$WeekYear = Carbon::parse($FirstDate)->year;
$StartOfWeek = Carbon::parse($FirstDate)->startOfWeek();
$EndOfWeek = Carbon::parse($FirstDate)->endOfWeek();
$WeekItem = new stdClass;
$WeekItem->WeekNumber = $WeekNumber;
$WeekItem->WeekYear = $WeekYear;
$WeekItem->FirstDate = AppHelper::_DateFormatMysql($StartOfWeek);
$WeekItem->LastDate = AppHelper::_DateFormatMysql($EndOfWeek);
if (count($WeekArray) > 0) {
if (collect($WeekArray)->where('WeekYear', $WeekItem->WeekYear)->where('WeekNumber', $WeekItem->WeekNumber)
->where('FirstDate', $WeekItem->FirstDate)->where('LastDate', $WeekItem->LastDate)->count() == 0)
{
array_push($WeekArray, $WeekItem);
}
}
else {
array_push($WeekArray, $WeekItem);
}
$FirstDate = Carbon::parse($FirstDate)->addDays(1);
}

Random time and date between 2 date values

I'm trying to write a php script (or line of code) to echo a random time and date between 2 dates, eg
2012-12-24 13:03
which would be between my chosen dates of 1st October 2012 and 1st Jan 2013.
Any ideas how best to do this? Thanks in advance.
Easy :) Just choose 2 random dates, convert to EPOCH, and random between these 2 values :)
EPOCH - The time since 1/1/1970, in seconds.
You can use the strtotime() function to make date-strings turn into epoch time, and the date() function to make it the other way back.
function rand_date($min_date, $max_date) {
/* Gets 2 dates as string, earlier and later date.
Returns date in between them.
*/
$min_epoch = strtotime($min_date);
$max_epoch = strtotime($max_date);
$rand_epoch = rand($min_epoch, $max_epoch);
return date('Y-m-d H:i:s', $rand_epoch);
}
You probably want to define a resolution, for example one minute, or three minutes or 15 seconds or one and a half day or what not. The randomness should be applied on the whole period, I've choosen one minute here for exemplary purposes (there are 132480 minutes in your period).
$start = new Datetime('1st October 2012');
$end = new Datetime('1st Jan 2013');
$interval = new DateInterval('PT1M'); // Resolution: 1 Minute
$period = new DatePeriod($start, $interval, $end);
$random = new RandomIterator($period);
list($result) = iterator_to_array($random, false) ? : [null];
This for example gives:
class DateTime#7 (3) {
public $date =>
string(19) "2012-10-16 02:06:00"
public $timezone_type =>
int(3)
public $timezone =>
string(13) "Europe/Berlin"
}
You can find the RandomIterator here. Without it, it will take a little longer (ca. 1.5 the number of iterations compared to the example above) using:
$count = iterator_count($period);
$random = rand(1, $count);
$limited = new LimitIterator(new IteratorIterator($period), $random - 1, 1);
$limited->rewind();
$result = $limited->current();
I also tried with seconds, but that would take quite long. You probably want first to find a random day (92 days), and then some random time in it.
Also I've run some tests and I could not find any benefit in using DatePeriod so far as long as you're on common resolutions like seconds:
$start = new Datetime('1st October 2012');
$end = new Datetime('1st Jan 2013');
$random = new DateTime('#' . mt_rand($start->getTimestamp(), $end->getTimestamp()));
or minutes:
/**
* #param DateTime $start
* #param DateTime $end
* #param int|DateInterval $resolution in Seconds or as DateInterval
* #return DateTime
*/
$randomTime = function (DateTime $start, DateTime $end, $resolution = 1) {
if ($resolution instanceof DateInterval) {
$interval = $resolution;
$resolution = ($interval->m * 2.62974e6 + $interval->d) * 86400 + $interval->h * 60 + $interval->s;
}
$startValue = floor($start->getTimestamp() / $resolution);
$endValue = ceil($end->getTimestamp() / $resolution);
$random = mt_rand($startValue, $endValue) * $resolution;
return new DateTime('#' . $random);
};
$random = $randomTime($start, $end, 60);
Assuming you want to include October 1st, but not include Jan 1st...
$start = strtotime("2012-10-01 00:00:00");
$end = strtotime("2012-12-31 23:59:59");
$randomDate = date("Y-m-d H:i:s", rand($start, $end));
echo $randomDate;
so crazy it just may worK
function randomDate($start_date, $end_date)
{
//make timetamps
$min = strtotime($start_date);
$max = strtotime($end_date);
//random date
$rand_date = rand($min, $max);
//format it
return date('Y-m-d H:i:s', $rand_date);
}
Here's some code to accomplish this:
$randDate=date('Y-m-d', mt_rand(strtotime('2012-10-01'), strtotime('2013-01-01')));
Okay, here's something
$date_start = strtotime('1 October 2012');
$date_end = strtotime('1 January 2013');
$rand_date = rand($date_start, $date_end);
echo(date('d.m.Y H:i', $rand_date));

How to do this countdown

I have a end date in the database
i get the current date, let's suppose is in UTC
class Datecalc
{
public $year;
public $month;
public $day;
public $hour;
public $min;
public $sec;
function diff($start,$end = false)
{
if($start > $end)
{
$this->day = 0;
$this->hour = "00";
$this->min = "00";
$this->sec = "00";
return false;
}
if(!$end) { $end = time(); }
if(!is_numeric($start) || !is_numeric($end)) { return false; }
$start = date('Y-m-d H:i:s',$start);
$end = date('Y-m-d H:i:s',$end);
$d_start = new DateTime($start);
$d_end = new DateTime($end);
$diff = $d_start->diff($d_end);
$this->year = $diff->format('%y');
$this->month = $diff->format('%m');
$this->day = $diff->format('%d');
$this->hour = $diff->format('%H');
$this->min = $diff->format('%I');
$this->sec = $diff->format('%S');
return true;
}
}
I use this function to calculate the difference in time, but the problem is that i cant count days to 99, and when the date is 00:00:00, the days -1, and its sets to 98 and the time 23:59:59, in this code its all good, but if the number of days gets higer than 30, its resets to 01, i think you understand what i am trying to say, please help!!
in other words i need to count the days separately, and the time needs to be binded to that days
The method you use will never allow you to get days > 30 because any days above 30 will be converted to another month...
This might be better approach for you:
http://www.prettyscripts.com/code/php/php-date-difference-in-days
Or
http://www.bizinfosys.com/php/date-difference.html
(Simple google search btw...)
First, you should be checking if $end is false before you check is $start is greater than $end.
That said, the diff method returns a DateInterval object (http://us.php.net/manual/en/class.dateinterval.php), which has a number of options, including total number of days between the dates, as well as years, months, days, etc. You probably want to be using what is already returned by the diff method, rather than the format function.
$diff = $d_start->diff($d_end);
echo 'Total days difference: '.$diff->days;
echo 'Year, Month, Days, time difference: '.
$diff->y.' y, '.$diff->m.' m, '.$diff->d.' d, '.$diff->h.' h, '.$diff->i.' m, '.$diff->s.' s, ';

Next business day of given date in PHP

Does anyone have a PHP snippet to calculate the next business day for a given date?
How does, for example, YYYY-MM-DD need to be converted to find out the next business day?
Example:
For 03.04.2011 (DD-MM-YYYY) the next business day is 04.04.2011.
For 08.04.2011 the next business day is 11.04.2011.
This is the variable containing the date I need to know the next business day for
$cubeTime['time'];
Variable contains: 2011-04-01
result of the snippet should be: 2011-04-04
Next Weekday
This finds the next weekday from a specific date (not including Saturday or Sunday):
echo date('Y-m-d', strtotime('2011-04-05 +1 Weekday'));
You could also do it with a date variable of course:
$myDate = '2011-04-05';
echo date('Y-m-d', strtotime($myDate . ' +1 Weekday'));
UPDATE: Or, if you have access to PHP's DateTime class (very likely):
$date = new DateTime('2018-01-27');
$date->modify('+7 weekday');
echo $date->format('Y-m-d');
Want to Skip Holidays?:
Although the original poster mentioned "I don't need to consider holidays", if you DO happen to want to ignore holidays, just remember - "Holidays" is just an array of whatever dates you don't want to include and differs by country, region, company, person...etc.
Simply put the above code into a function that excludes/loops past the dates you don't want included. Something like this:
$tmpDate = '2015-06-22';
$holidays = ['2015-07-04', '2015-10-31', '2015-12-25'];
$i = 1;
$nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));
while (in_array($nextBusinessDay, $holidays)) {
$i++;
$nextBusinessDay = date('Y-m-d', strtotime($tmpDate . ' +' . $i . ' Weekday'));
}
I'm sure the above code can be simplified or shortened if you want. I tried to write it in an easy-to-understand way.
For UK holidays you can use
https://www.gov.uk/bank-holidays#england-and-wales
The ICS format data is easy to parse. My suggestion is...
# $date must be in YYYY-MM-DD format
# You can pass in either an array of holidays in YYYYMMDD format
# OR a URL for a .ics file containing holidays
# this defaults to the UK government holiday data for England and Wales
function addBusinessDays($date,$numDays=1,$holidays='') {
if ($holidays==='') $holidays = 'https://www.gov.uk/bank-holidays/england-and-wales.ics';
if (!is_array($holidays)) {
$ch = curl_init($holidays);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$ics = curl_exec($ch);
curl_close($ch);
$ics = explode("\n",$ics);
$ics = preg_grep('/^DTSTART;/',$ics);
$holidays = preg_replace('/^DTSTART;VALUE=DATE:(\\d{4})(\\d{2})(\\d{2}).*/s','$1-$2-$3',$ics);
}
$addDay = 0;
while ($numDays--) {
while (true) {
$addDay++;
$newDate = date('Y-m-d', strtotime("$date +$addDay Days"));
$newDayOfWeek = date('w', strtotime($newDate));
if ( $newDayOfWeek>0 && $newDayOfWeek<6 && !in_array($newDate,$holidays)) break;
}
}
return $newDate;
}
function next_business_day($date) {
$add_day = 0;
do {
$add_day++;
$new_date = date('Y-m-d', strtotime("$date +$add_day Days"));
$new_day_of_week = date('w', strtotime($new_date));
} while($new_day_of_week == 6 || $new_day_of_week == 0);
return $new_date;
}
This function should ignore weekends (6 = Saturday and 0 = Sunday).
This function will calculate the business day in the future or past. Arguments are number of days, forward (1) or backwards(0), and a date. If no date is supplied todays date will be used:
// returned $date Y/m/d
function work_days_from_date($days, $forward, $date=NULL)
{
if(!$date)
{
$date = date('Y-m-d'); // if no date given, use todays date
}
while ($days != 0)
{
$forward == 1 ? $day = strtotime($date.' +1 day') : $day = strtotime($date.' -1 day');
$date = date('Y-m-d',$day);
if( date('N', strtotime($date)) <= 5) // if it's a weekday
{
$days--;
}
}
return $date;
}
What you need to do is:
Convert the provided date into a timestamp.
Use this along with the or w or N formatters for PHP's date command to tell you what day of the week it is.
If it isn't a "business day", you can then increment the timestamp by a day (86400 seconds) and check again until you hit a business day.
N.B.: For this is really work, you'd also need to exclude any bank or public holidays, etc.
I stumbled apon this thread when I was working on a Danish website where I needed to code a "Next day delivery" PHP script.
Here is what I came up with (This will display the name of the next working day in Danish, and the next working + 1 if current time is more than a given limit)
$day["Mon"] = "Mandag";
$day["Tue"] = "Tirsdag";
$day["Wed"] = "Onsdag";
$day["Thu"] = "Torsdag";
$day["Fri"] = "Fredag";
$day["Sat"] = "Lørdag";
$day["Sun"] = "Søndag";
date_default_timezone_set('Europe/Copenhagen');
$date = date('l');
$checkTime = '1400';
$date2 = date(strtotime($date.' +1 Weekday'));
if( date( 'Hi' ) >= $checkTime) {
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Saturday'){
$date2 = date(strtotime($date.' +2 Weekday'));
}
if (date('l') == 'Sunday') {
$date2 = date(strtotime($date.' +2 Weekday'));
}
echo '<p>Næste levering: <span>'.$day[date("D", $date2)].'</span></p>';
As you can see in the sample code $checkTime is where I set the time limit which determines if the next day delivery will be +1 working day or +2 working days.
'1400' = 14:00 hours
I know that the if statements can be made more compressed, but I show my code for people to easily understand the way it works.
I hope someone out there can use this little snippet.
Here is the best way to get business days (Mon-Fri) in PHP.
function days()
{
$week=array();
$weekday=["Monday","Tuesday","Wednesday","Thursday","Friday"];
foreach ($weekday as $key => $value)
{
$sort=$value." this week";
$day=date('D', strtotime($sort));
$date=date('d', strtotime($sort));
$year=date('Y-m-d', strtotime($sort));
$weeks['day']= $day;
$weeks['date']= $date;
$weeks['year']= $year;
$week[]=$weeks;
}
return $week;
}
Hope this will help you guys.
Thanks,.
See the example below:
$startDate = new DateTime( '2013-04-01' ); //intialize start date
$endDate = new DateTime( '2013-04-30' ); //initialize end date
$holiday = array('2013-04-11','2013-04-25'); //this is assumed list of holiday
$interval = new DateInterval('P1D'); // set the interval as 1 day
$daterange = new DatePeriod($startDate, $interval ,$endDate);
foreach($daterange as $date){
if($date->format("N") <6 AND !in_array($date->format("Y-m-d"),$holiday))
$result[] = $date->format("Y-m-d");
}
echo "<pre>";print_r($result);
For more info: http://goo.gl/YOsfPX
You could do something like this.
/**
* #param string $date
* #param DateTimeZone|null|null $DateTimeZone
* #return \NavigableDate\NavigableDateInterface
*/
function getNextBusinessDay(string $date, ? DateTimeZone $DateTimeZone = null):\NavigableDate\NavigableDateInterface
{
$Date = \NavigableDate\NavigableDateFacade::create($date, $DateTimeZone);
$NextDay = $Date->nextDay();
while(true)
{
$nextDayIndexInTheWeek = (int) $NextDay->format('N');
// check if the day is between Monday and Friday. In DateTime class php, Monday is 1 and Friday is 5
if ($nextDayIndexInTheWeek >= 1 && $nextDayIndexInTheWeek <= 5)
{
break;
}
$NextDay = $NextDay->nextDay();
}
return $NextDay;
}
$date = '2017-02-24';
$NextBussinessDay = getNextBusinessDay($date);
var_dump($NextBussinessDay->format('Y-m-d'));
Output:
string(10) "2017-02-27"
\NavigableDate\NavigableDateFacade::create($date, $DateTimeZone), is provided by php library available at https://packagist.org/packages/ishworkh/navigable-date. You need to first include this library in your project with composer or direct download.
I used below methods in PHP, strtotime() does not work specially in leap year February month.
public static function nextWorkingDay($date, $addDays = 1)
{
if (strlen(trim($date)) <= 10) {
$date = trim($date)." 09:00:00";
}
$date = new DateTime($date);
//Add days
$date->add(new DateInterval('P'.$addDays.'D'));
while ($date->format('N') >= 5)
{
$date->add(new DateInterval('P1D'));
}
return $date->format('Y-m-d H:i:s');
}
This solution for 5 working days (you can change if you required for 6 or 4 days working). if you want to exclude more days like holidays then just check another condition in while loop.
//
while ($date->format('N') >= 5 && !in_array($date->format('Y-m-d'), self::holidayArray()))

Categories