Carbon PHP previousWeekday returns a weekend day - php

I'm using Carbon PHP to build a small API for my project. I need to get the last working day of the month, in my context, this should be the very last weekday of each month.
This is how I'm currently doing it:
$lastWorkingDay = Carbon::parse('2022-04-27')->lastOfMonth();
if ($lastWorkingDay->isWeekend()) {
$lastWorkingDay = Carbon::parse('2022-04-27')->lastOfMonth()->previousWeekday();
}
The problem I've encountered here, is that in April, the last day of the month is on a weekend, so then my previousWeekday method appears to be getting the saturday rather than the friday?

It will be a lot easier if
$lastWorkingDayOfMonth = Carbon::parse('2022-04-27')
->modify('first Day of next Month')
->modify('last weekday');
is used. modify is a method that Carbon inherited from DateTime.
This is also possible without Carbon only with DateTime. Here's a little test.
If the code is required more often in an application, a macro can be defined for it in Carbon.
Carbon::macro('lastWorkingDayOfMonth', function() {
return $this->modify('first Day of next Month')->modify('last weekday');
});
lastWorkingDayOfMonth() can now be used anywhere in Carbon like any other method.
echo Carbon::parse('2022-04-27')->lastWorkingDayOfMonth()->format('l, d F Y');
//Friday, 29 April 2022

Related

Modify DateTime instance to next month

Given a DateTime instance initialized as :
$tgtDateDT = new DateTime('now');
which for example equates to 2023-01-30 when formatted as ->format("Y-m-d"),
I want to advance the month to February (for rendering a calendar) where I was hoping to do:
$nextMonth = $tgtDateDT->add(new DateInterval('P1M'));
Which when formatted with ->format("Y-m-d") yields
2023-03-02
So February has 28 days so I understand it may yield an unpredictable result.
So how can I take a date from any day in one month and advance it to say "the first" of the next month - preferably with DateInterval.
For my calendar rendering the new date can be any day in the next month.
Given any day in a month and needing to advance to the first day of the next month (such as flipping to next month on a calendar) the following can be performed:
$tgtDateDT = new DateTime('now');
// implement "startOfMonth"
$tgtDateDT->setDate($tgtDateDT->format('Y'), $tgtDateDT->format('m'),1);
$tgtDateDT->add(new DateInterval('P1M'));
printf ($tgtDateDT);
So 2023-01-30 yields 2023-02-01.

how to get week +4 in this day with carbon

I have a problem here I want to get the +4 week date from the current date using carbon, the +4 week plan will be dynamic depending on the input entered by the user, how do I make it, I've tried using this code but it's time to step back
$dt = Carbon::now();
dd($dt->week(4)->format('Y-m-d'));
Check Carbon docs, you may use addWeeks():
$dt = Carbon::now();
dd($dt->addWeeks(4)->format('Y-m-d'));
The week() method you've used, sets the week number using given first day of week and first day of year included in the first week.
I am not sure to understand your question, but I guess you just have to use :
$dt = Carbon::now();
$dt->addWeeks(4);
dd($dt->format('Y-m-d');
You don't need carbon for such simple tasks.
With DateTime
echo date_create('+4 weeks')->format("Y-m-d");
or with date and strtotime
echo date("Y-m-d",strtotime('+4 weeks'));

How to set date to nth day of this month when using Carbon of PHP?

From the document page of Carbon library, it is stated that it is possible to use simple words to initialize a Carbon object. For example, Carbon::parse('first day of December 2008') or new Carbon('first day of December 2008')
However, when I am trying to set the date to 10th of this month by the following trials
Carbon::parse('10th day of this month')
Carbon::parse('tenth day of this month')
Carbon::parse('10th of this month')
Carbon::parse('tenth of this month')
Carbon::parse('10 of this month')
Carbon::parse('ten of this month')
All of these fails.
Currently I am able to create my desired Carbon object by Carbon::parse('first day of this month')->addDays(9), but the readability is not good. More code is needed to be read and it is very easy to mistaken as 9th of this month at the first glaze.
So, is there a way I can create the Carbon object with one parse only?
It's a bit ugly, but this should work
Carbon::parse('10th ' . date('M'));

PHP - Parsing String As Past Date

Currently, I'm trying to parse out dates when messages were received into timestamps. I have the month and day but the year is not specified. The event always occurs at the most recent (human) reading of the time. It works great in most cases to do this:
$time = strtotime("Jan 2 8:38pm");
That returns a date for this year, which is correct. Unfortunately, I get problems when I try to do for example:
$time = strtotime("Dec 31 8:38pm");
That returns a date which hasn't happened yet, and wont happen for the whole rest of the year. Obviously, my message was not sent in the future. I need it to return December 31st of last year.
For weekdays, I had a solution by prepending 'last' before the weekday like so:
$time = strtotime("Last Saturday 8:38pm");
That always returned the time of the last Saturday. However, trying to do the same thing here doesn't work:
$time = strtotime("Last Dec 31 8:38pm");
This returns false. I know to decrement a date by 1 year, I can do this:
$time = strtotime("Dec 31 8:38pm -1 year");
And that works great for Dec 31. However, Jan 2 will now fail:
$time = strtotime("Jan 2 8:38pm -1 year");
One solution I thought of was to subtract off a year (86400 * 365) from the resulting value if it is past today's date. However, this result will fail if we passed over February of a leap year. In that case, we would end up with a time that was ahead by a day.
The best solution I came up with so far is this:
$time = strtotime($raw_time);
if ($time > time()) {
$time = strtotime($raw_time." -1 year");
}
It seems kind of wasteful to make two calls to strtotime which I know is probably not a very efficient function. Is this the most elegant solution?
Is anyone aware of an option in strtotime which forces the dates to be in the past instead of in the future?
Is there another way to parse these dates that I should consider?
Efficiency is important for this because I am going to be parsing a lot of dates with it, but I would also like simple and readable code so I can understand it later.
Your approach is fine, as there is no date format to get what you want. Another approach could be using the DateTime class:
$datetime = new DateTime($raw_time);
if ($datetime > new DateTime()) {
$datetime->modify('-1 year');
}
You could test which one of the two approaches is faster. My guess is that this is a micro-optimization that won't make a lot of difference.

this week in PHP 5.3

I try to find an answer but without result
the problem is:
in sunday function return date for Monday next week
$date = new DateTime();
$date->setTimezone(new DateTimeZone('Europe/Moscow'));
$date->setTimestamp(strtotime('Monday this week'));
echo $date->format("d.m.Y");
but in other days (except Sunday) its return correct value of Monday.
I ever set locale manualy , which has a monday - the first day of week, but PHP "think" the Sunday is still firs day. is it bug ?? or i do some wrong ?
There seem to be known idiosyncrasies with strtotime. It's mentioned in the comments:
http://www.php.net/manual/en/datetime.formats.relative.php#108317
They don't mention different locales specifically but it would be extremely unsurprising if strtotime() does not correctly behave for next/this week under different locales.
Try this Monday or next Monday and see if one of those gets what you want.

Categories