PHP: get weekday number of the month - php

I'm looking for functionality that would do the opposite of
strtotime("third monday");
i.e. a function that is fed a timestamp and would return the weekday number of the month.
So if today is 18.07.2016, ideally the function should return "3" (i.e. 3rd Monday of July).
I can get the weekday itself by using date("D", [timestamp]), but I'm not sure how to calculate that it is in fact the third one this month.
Has anyone tried doing anything like this before?

You'll want to verify you're working within a valid date range, but this is a relatively simple task:
$today = date('d', time());
echo 1 + floor(($today - 1) / 7); // nth day of month

You should look into the Carbon class. It expands date and time functions to basically everything you'd ever need, including human-readable timestamps (ie. "5 minutes ago")
These two would be useful to you - the day and week of the month.
var_dump($dt->dayOfWeek); // int(3)
var_dump($dt->weekOfMonth); // int(1)
http://carbon.nesbot.com/docs/#api-getters

Related

PHP doesn't give a proper output for month substraction

Code:
$time = strtotime('2020-03-31');
echo date('Y-m-d', strtotime('-1 month', $time));
Expected Result: Any date from Feb 2020
Actual Result: 2020-03-02
Is there any better way to add or subtract a month from a given date?
Months are an awkward interval to work with, because they don't have a fixed length. Should the algorithm assume that by "1 month" you mean "30 days", or "31 days", or should it just try subtracting 1 from the "month" field in the date structure?
The last option is what is happening here: given "2020-03-31", PHP's date library is subtracting 1 from the "03" to give "2020-02-31". Since that's an invalid date (February 2020 had 29 days), it then "normalises" it to a real date - 2 days after the 29th February was the 2nd March.
Probably you want to use a more specific period to subtract, like 30 days - although note that if the initial input is "2020-03-01" that will give you "2020-01-31", not "2020-02-01".
Ultimately, this is a problem with our irregular calendar, rather than with PHP. It's really up to you to define what you mean by "a month before", and use a more specific algorithm that captures that requirement.
You can make code like below
<?php
$time = strtotime('2020-03-1 -32 days');
echo date('M-Y', $time); // output Feb-2020
?>
The above code will return date as you expected

How to get full date from string without having the actual month in the string in PHP?

Is there any way to get the full date from a string that does not actually contain the month?
i am given the date in a format of Wednesday 16th and need to add this to my database with a month,
The application i am making is for lifestyle couriers and they get their manifests in that format and have the last 2 months available, so i need to find out the month?
Assuming that you want to regard the current and the last two months, I can imagine, that there will be no two day numbers of the same week day in that timespan (that should be proven first).
I would iterate back over the last n days using PHP's date function and try to detect your "Wednesday 16th" where n is the aggregate of month days that date with param "t" returns for the current and the last two months.
If you have your match then, you know the month and the year (the year could be the previous year as well if you start in January or February).
You can do it like this:
<?php
$date = 16;
$day = "Wednesday";
$oneMonthAgo = explode(" ",date("m Y F",strtotime("-1 month")));
$twoMonthsAgo = explode(" ",date("m Y F",strtotime("-2 months")));
if (date("l",strtotime($date."-".$oneMonthAgo[0]."-".$oneMonthAgo[1]))==$day) {
echo "Last month: ".$oneMonthAgo[2];
}
else if (date("l",strtotime($date."-".$twoMonthsAgo[0]."-".$twoMonthsAgo[1]))==$day) {
echo "Month before last: ".$twoMonthsAgo[2];
}
else {
echo "Not valid";
}
?>
Explanation
Because you are using PHP, there is an easy way to do this. In other languages, you would have to use a weekday algorithm.
In PHP, we can convert a properly formatted string into a time, from which we can then derive date information. Examples of a properly formatted string is -1 month or -2 months, which return time objects for the previous month or the month before that, respectively.
Using the date() function, we can get the month, year and textual month values for those months. We delimiter these by a space, so that we can explode these values into an array after they are found. Thus, we now have two arrays, $oneMonthAgo and $twoMonthsAgo, which both contain their month's respective number, year and textual month at the 0, 1 and 2 indexes respectively.
Now, we can create another time, by appending the date that we are looking for ($date) onto these values, with the proper delimiters in-between (when using - as the delimiters, PHP assumes a d-m-Y format, when using / PHP assumes a m-d-Y format). Then, by passing that through another date() function, we can find the data that we are looking for: the textual day that took place at that date. Now we can simply compare that to the day that we are looking for, $day. If the textual day is the same, then this is the month which we are looking for, so we can print out the full textual month.
We do this in an if / else statement for both months, and if we still haven't found it, assume that the date is invalid.
Notes
References to the PHP functions used can be found on the PHP Manual: date() function, strtotime() function, Valid dates for strtotime()
Yes and no. Since full date requires month to be known you need to know what to do with lack of that information. If you "guess" the month (be it current one or random, does not matter), then "yes" is close. If you cannot tell what the month we talk about then answer is no (or random).
PS: you may need a year too...
I use a while loop to loop backwards however many months needed to find what is searched for.
$date = 16;
$day = "Wednesday";
$x=0;
$start = date("Y-m-") . $date;
While(date("l", strtotime($start ."-" .$x . "months")) != $day){
$x++;
}
Echo $x . " months ago.";
// Or to output the date:
//Echo date("Y-m-d", strtotime($start ."-" .$x . "months"));
https://3v4l.org/vUYeX
This will output 0 months ago.
But if input $date= 15; it will output 5 months ago (March 2017).

How can I verify that a date range includes a weekend?

I have a date range that comes from MySQL, for example:
2016-01-05 to 2016-01-10. I would like to check if both Saturday and Sunday are inside that date-range, not necessarily consecutive. So far I have found:
function isWeekend($date) {
return (date('N', strtotime($date)) >= 6);
}
So I would have to loop for every single day in the range to see if it's a weekend day.
Are there any better approaches?
You don't need to loop over all the days. You just need to know the length of the date range and the first day's day of the week.
Assuming you have two DateTime objects:
$start = new DateTime('2016-01-05');
$end = new DateTime('2016-01-10');
You can determine if a Saturday and Sunday are contained in the date range by checking if the length of the range plus the numeric weekday of the start date is greater than 6.
function includes_weekend (DateTime $start, DateTime $end) {
return $start->diff($end)->format('%a') + $start->format('w') > 6;
}
format('%a') returns the total number of days in the DateInterval returned by diff, and format('w') returns the numeric day of the week (Sunday = 0).
You would not have to check every single day.
I'll try to explain this with just plain English:
First, check if it starts on a weekend. If it does, you're already done. If the date span is more than 6 days, then you can immediately assume that yes, a weekend day is included. If it's 5 days, then the first day has to be on a Monday, otherwise it contains a weekend day. If it's four, it has to be on a Tuesday... and so on.

php DateTime diff - include both dates in range?

I have been using DateTime Diff (in php) to get various settings for pairs of dates - two formatted dates to display, a difference from the date to now (eg "start date was 3 months 2 days ago"), and a length between the two dates ("length is 2 months 3 days").
The problem is that DateTime Diff ignores one of the days so if the start is yesterday and the end is tomorrow, it gives 2 days whereas I want 3 because both dates should be included in the length. If it was just days, I could simply add 1 to the result, but I wanted to use the years/months/days results from the Diff and these are determined at construct.
The only way I have found to get the desired results is to create a DateTime for start and end (to get the formatted dates and the differences). Then take the end DateTime, add 1 day to it, then work out the length.
It's a bit clunky but there seems to be no way to tell DateTime Diff to include both start and end dates in the result.
DateTime encapsulates a specific moment in time. "yesterday" is not a moment but a time range. The same for "tomorrow".
DateTime::diff() doesn't ignore anything; it just provides you the exact difference (in day, hours, minutes a.s.o.) between two moments in time.
If you want to get the diff between "tomorrow" and "yesterday" as "3 days" you can subtract the first second of "yesterday" from (one second after the last second of "tomorrow").
Like this:
// Always set the timezone of your DateTime objects to avoid troubles
$tz = new DateTimeZone('Europe/Bucharest');
// Some random time yesterday
$date1 = new DateTime('2016-07-08 21:30:15', $tz);
// Other random time tomorrow
$date2 = new DateTime('2016-07-10 12:34:56', $tz);
// Don't mess with $date1 and $date2;
// clone them and do whatever you want with the clones
$yesterday = clone $date1;
$yesterday->setTime(0, 0, 0); // first second of yesterday (the midnight)
$tomorrow = clone $date2;
$tomorrow->setTime(23, 59, 59) // last second of tomorrow
->add(new DateInterval('PT1S')); // one second
// Get the difference; it is the number of days between and including $date1 and $date2
$diff = $tomorrow->diff($yesterday);
printf("There are %d days between %s and %s (including the start and end date).\n",
$diff->days, $date1->format('Y-m-d'), $date2->format('Y-m-d')
);

Month by week of the year?

I'm trying to get the number of the month of the year by the number of a week of the year and the year.
So for example week 1 is in january and returns 1, week 6 is in february so I want 2.
I tried to go with date_parse_from_format('W/Y') but had no success (it's giving me errors).
Is there any way to go with date_parse_from_format() or is there another way?
print date("m",strtotime("2011-W6-1"));
(noting that in 2011, January has six weeks so week 6 (by some definitions) is in month 1).
Just wanted to add a note for the first answer, the week number should be 01-09 for Weeks 1 through 9 (it will always give month 1 if you don't add the leading zero)
date("m",strtotime("2011-W06-1"));
Using PHP DateTime objects (which is the preferred way of dealing with dates see links below for more info) you can accomplish it this way:
$dateTime = new \DateTime();
$dateTime->setISODate($year,$week);
$month = $dateTime->format('n');
Note that the following will not work as week "W" is not a supported format:
$month = \DateTime::createFromFormat("W/Y ", "1/2015")->format('n');
The format used by this method is the same supported by the function you where trying to use date_parse_from_format, hence the errors.
Why PHP DateTime Rocks
DateTime class vs. native PHP date-functions
strtotime notes
PHP/Architect's Guide to Date and Time Programming (Chapter 2)
Something like this will do, this is also tested and works:
function getMonthByNumber($number,$year)
{
return date("F",strtotime('+ '.$number.' weeks', mktime(0,0,0,1,1,$year,-1)));
}
echo getMonthByNumber(27,2011);
Hope this helps

Categories