I'm trying to write a calendar function like this
function get_date($month, $year, $week, $day, $direction)
{
....
}
$week is a an integer (1, 2, 3...), $day is a day (Sun, Mon, ...) or number, whichever is easier. The direction is a little confusing, because it does a different calculation.
For an example, let's call
get_date(5, 2009, 1, 'Sun', 'forward');
It uses the default, and gets the first Sunday in May ie 2009-05-03. If we call
get_date(5, 2009, 2, 'Sun', 'backward');
, it returns the second last Sunday in May ie 2009-05-24.
The language-agnostic version:
To get the first particular day of the month, start with the first day of the month: yyyy-mm-01. Use whatever function is available to give a number corresponding to the day of the week. Subtract that number from the day you are looking for; for example, if the first day of the month is Wednesday (2) and you're looking for Friday (4), subtract 2 from 4, leaving 2. If the answer is negative, add 7. Finally add that to the first of the month; for my example, the first Friday would be the 3rd.
To get the last Friday of the month, find the first Friday of the next month and subtract 7 days.
Perhaps it can be made quicker...
This was VERY interesting to code.
Please note that $direction is 1 for forward and -1 for backward to ease things up :)
Also, $day begins with a value of 1 for Monday and ends at 7 for Sunday.
function get_date($month, $year, $week, $day, $direction) {
if($direction > 0)
$startday = 1;
else
$startday = date('t', mktime(0, 0, 0, $month, 1, $year));
$start = mktime(0, 0, 0, $month, $startday, $year);
$weekday = date('N', $start);
if($direction * $day >= $direction * $weekday)
$offset = -$direction * 7;
else
$offset = 0;
$offset += $direction * ($week * 7) + ($day - $weekday);
return mktime(0, 0, 0, $month, $startday + $offset, $year);
}
I've tested it with a few examples and seems to work always, be sure to double-check it though ;)
PHP's built-in time functions make this simple.
http://php.net/manual/en/function.strtotime.php
// Get first Friday of next month.
$timestamp = strtotime('first fri of next month');
// Get second to last Friday of the current month.
$timestamp = strtotime('last fri of this month -7 days');
// Format a timestamp as a human-meaningful string.
$formattedDate = date('F j, Y', strtotime('first wed of last month'));
Note that we always want to make sure that we've defined the correct timezone for use with strtotime so that PHP has an understanding of where to compute the timestamp for relative to what time zone the machine thinks it's in.
date_default_timezone_set('America/New_York');
$formattedDate = date('F j, Y', strtotime('first wed of last month +1 week'));
strtotime() can help you. e.g. <?php
$tsFirst = strtotime('2009-04-00 next friday');
$tsLast = strtotime('2009-05-01 last friday');
echo date(DATE_RFC850, $tsFirst), " | ", date(DATE_RFC850, $tsLast);printsFriday, 03-Apr-09 00:00:00 CEST | Friday, 24-Apr-09 00:00:00 CEST
No need for calculations or loops - this is very easy to do with strtotime():
Find the the Nth or Last occurrence of a particular day of a particular a month:
/////////////////////////////////////////////////////////////////
// Quick Code
/////////////////////////////////////////////////////////////////
// Convenience mapping.
$Names = array( 0=>"Sun", 1=>"Mon", 2=>"Tue", 3=>"Wed", 4=>"Thu", 5=>"Fri", 6=>"Sat" );
// Specify what we want
// In this example, the Second Monday of Next March
$tsInMonth = strtotime('March');
$Day = 1;
$Ord = 2;
// The actual calculations
$ThisMonthTS = strtotime( date("Y-m-01", $tsInMonth ) );
$NextMonthTS = strtotime( date("Y-m-01", strtotime("next month", $tsInMonth) ) );
$DateOfInterest = (-1 == $Ord)
? strtotime( "last ".$Names[$Day], $NextMonthTS )
: strtotime( $Names[$Day]." + ".($Ord-1)." weeks", $ThisMonthTS );
/////////////////////////////////////////////////////////////////
// Explanation
/////////////////////////////////////////////////////////////////
// Specify the month of which we are interested.
// You can use any timestamp inside that month, I'm using strtotime for convenience.
$tsInMonth = strtotime('March');
// The day of interest, ie: Friday.
// It can be 0=Sunday through 6=Saturday (Like 'w' from date()).
$Day = 5;
// The occurrence of this day in which we are interested.
// It can be 1, 2, 3, 4 for the first, second, third, and fourth occurrence of the day in question in the month in question.
// You can also use -1 to fine the LAST occurrence. That will return the fifth occurrence if there is one, else the 4th.
$Ord = 3;
////////////////////////////////////////////////////////////////
// We now have all the specific values we need.
// The example values above specify the 3rd friday of next march
////////////////////////////////////////////////////////////////
// We need the day name that corresponds with our day number to pass to strtotime().
// This isn't really necessary = we could just specify the string in the first place, but for date calcs, you are more likely to have the day number than the string itself, so this is convenient.
$Names = array( 0=>"Sun", 1=>"Mon", 2=>"Tue", 3=>"Wed", 4=>"Thu", 5=>"Fri", 6=>"Sat" );
// Calculate the timestamp at midnight of the first of the month in question.
// Remember $tsInMonth is any date in that month.
$ThisMonthTS = strtotime( date("Y-m-01", $tsInMonth ) );
// Calculate the timestamp at midnight of the first of the FOLLOWING month.
// This will be used if we specify -1 for last occurrence.
$NextMonthTS = strtotime( date("Y-m-01", strtotime("next month", $tsInMonth) ) );
// Now we just format the values a bit and pass them to strtotime().
// To find the 1,2,3,4th occurrence, we work from the first of the month forward.
// For the last (-1) occurence,work we work back from the first occurrence of the following month.
$DateOfInterest = (-1 == $Ord) ?
strtotime( "last ".$Names[$Day], $NextMonthTS ) : // The last occurrence of the day in this month. Calculated as "last dayname" from the first of next month, which will be the last one in this month.
strtotime( $Names[$Day]." + ".($Ord-1)." weeks", $ThisMonthTS ); // From the first of this month, move to "next dayname" which will be the first occurrence, and then move ahead a week for as many additional occurrences as you need.
echo date('Y-m-d',strtotime('last friday'));
You can use mktime to retrieve the unix timestamp of the first day in the month:
$firstOfMonth = mktime(0, 0, 0, $month, 1, $year);
When you have the date of the first day of a certain month it's easy to retrieve the weekday for that date using date:
$weekday = date("N", $firstOfMonth);
From there it's rather easy to just step forward to get the date you're after.
function get_date($month, $year, $week, $day) {
# $month, $year: current month to search in
# $week: 0=1st, 1=2nd, 2=3rd, 3=4th, -1=last
# $day: 0=mon, 1=tue, ..., 6=sun
$startday=1; $delta=0;
if ($week < 0) {
$startday = date('t', mktime(0, 0, 0, $month, 1, $year)); # 28..31
$delta=1;
}
$start = mktime(0, 0, 0, $month, $startday, $year);
$dstart = date('w', $start)-1; # last of the month falls on 0=mon,6=sun
$offset=$day-$dstart; if ($offset<$delta){$offset+=7;}
$newday=$startday+$offset+($week*7);
return mktime(0, 0, 0, $month, $newday, $year);
}
This works for me, and based on the language-agnostic version :-)
Only too bad, I needed to do that delta-thing (for if the last day of the month is the wanted week-day, we do not need to subtract 7)
The same can be accomplished very elegantly using the DateTime class.
$time_zone = new DateTimeZone('Europe/Ljubljana');
$first_friday_of_this_month = new DateTime('first Friday of this month', $time_zone);
$last_friday_of_this_month = new DateTime('last Friday of this month', $time_zone);
echo $first_friday_of_this_month->format('Y-m-d'); # 2015-11-06
echo $last_friday_of_this_month->format('Y-m-d'); # 2015-11-27
Just find out what the first and last day of the month in question is (i.e. May 1, 2009 is a Friday and May 31, 2009 is a Sunday) I believe most PHP functions use Monday=0, Sunday=6, thus Friday=4, so you know that Sunday (6) - Friday (4) = 2, then 31-2 = 29, meaning the last friday of this month is on the 29th. For the first Friday, if the number is negative, add 7, if the number is 0, the month starts on Friday.
This seems to work perfect everytime; it takes any date provided and returns the date of the last friday of the month, even in case of 5 friday in the month.
function get_last_friday_of_month($inDate) {
$inDate = date('Y-m-24', strtotime($inDate));
$last_friday = date('Y-m-d',strtotime($inDate.' next friday'));
$next_friday = date('Y-m-d',strtotime($inDate.' next friday'));
if(date('m', strtotime($last_friday)) === date('m', strtotime($next_friday))){
$last_friday = $next_friday;
}else{
//
}
return $last_friday;
}
Below is the quickest solution and you can use in all conditions. Also you could get an array of all day of week if you tweak it a bit.
function findDate($date, $week, $weekday){
# $date is the date we are using to get the month and year which should be a datetime object
# $week can be: 0 for first, 1 for second, 2 for third, 3 for fourth and -1 for last
# $weekday can be: 1 for Monday, 2 for Tuesday, 3 for Wednesday, 4 for Thursday, 5 for Friday, 6 for Saturday and 7 for Sunday
$start = clone $date;
$finish = clone $date;
$start->modify('first day of this month');
$finish->modify('last day of this month');
$finish->modify('+1 day');
$interval = DateInterval::createFromDateString('1 day');
$period = new DatePeriod($start, $interval, $finish);
foreach($period AS $date){
$result[$date->format('N')][] = $date;
}
if($week == -1)
return end($result[$weekday]);
else
return $result[$weekday][$week];
}
$date = DateTime::createFromFormat('d/m/Y', '25/12/2016');
# find the third Wednesday in December 2016
$result = findDate($date, 2, 3);
echo $result->format('d/m/Y');
I hope this helps.
Let me know if you need any further info. ;)
Related
I have a day of the week number 'N' (1 for Monday through 7 Saturday) and a week 'W' and a year 'Y'.
How can i find the date?
Day of the week: 4
Week: 35
Year: 2014
Should output: 2014-08-28 (Thursday)
I have tried using strotime() without any luck.
I cannot seem to find a way to specify the week and year, together with the weekday number.
Just did my own solution. Here is how you could do it.
function getDayDate($day, $week, $year) {
$day -= 1;
$dto = new DateTime();
$dto->setISODate($year, $week);
$dto->format('Y-m-d') . ' 00:00:00'; // start of the week date
$dto->modify('+'.$day.' days'); // add the days
$result = $dto->format('Y-m-d') . ' 23:59:59';
return $result;
}
$getdate = getDayDate(4, 35, 2014);
echo $getdate;
You can use DateTime's setISODate() method for exactly this purpose. Your solution is almost right, but I don't understand why you're not supplying the weekday argument right from the start.
function get_date($weekday, $week, $year) {
return (new DateTime())->setISODate($year, $week, $weekday)->format('Y-m-d');
}
var_dump(get_date(4, 35, 2014));
According to the ISO standar, the 52nd week of 2013, when the week starts on Saturday, starts 2013-12-28 and ends 2014-01-03 (inclusive).
Code:
echo date('Y-m-d', strtotime("2013-W52-6"));//prints 2013-12-28
Now, I am trying to figure out the inverse using PHP. If I have the date 2014-01-03, how to know the ISO weeknumber of that date if the week starts on Saturday?
Use the DateTime class:
createFromFormat() to create the object based on the string you have
then format('W')
$date = "2013-12-28";
$dayofyear = date("z", $date);
$week = floor($dayofyear / 7) + 1;
// I assume week starts with Monday (I think as ISO does?)
// so only weeks that start on sunday will count as "week 0" instead of "week 1"
// I could be wildly wrong, adjust according to your needs
$first_day = date("w", date("Y", $date) . "-01-01");
if ($first_day == 6)
--$week;
echo $week;
$date = "2013-12-28";
$date_array = explode("-", $date);
$date = mktime(0, 0, 0, $date_array[1], $date_array[2], $date_array[0]);
$week_number = date('W', $date);
echo $week_number;
Something like this.
How can I calculate the day of month in PHP with giving month, year, day of week and number of week.
Like, if I have September 2013 and day of week is Friday and number of week is 2, I should get 6. (9/6/2013 is Friday on the 2nd week.)
One way to achieve this is using relative formats for strtotime().
Unfortunately, it's not as straightforward as:
strtotime('Friday of second week of September 2013');
In order for the weeks to work as you mentioned, you need to call strtotime() again with a relative timestamp.
$first_of_month_timestamp = strtotime('first day of September 2013');
$second_week_friday = strtotime('+1 week, Friday', $first_of_month_timestamp);
echo date('Y-m-d', $second_week_friday); // 2013-09-13
Note: Since the first day of the month starts on week one, I've decremented the week accordingly.
I was going to suggest to just use strtotime() in this fashion:
$ts = strtotime('2nd friday of september 2013');
echo date('Y-m-d', $ts), PHP_EOL;
// outputs: 2013-09-13
It seems that this is not how you want the calendar to behave? But it is following a (proper) standard :)
This way its a little longer and obvious but it works.
/* INPUT */
$month = "September";
$year = "2013";
$dayWeek= "Friday";
$week = 2;
$start = strtotime("{$year}/{$month}/1"); //get first day of that month
$result = false;
while(true) { //loop all days of month to find expected day
if(date("w", $start) == $week && date("l", $start) == $dayWeek) {
$result = date("d", $start);
break;
}
$start += 60 * 60 * 24;
}
var_dump($result); // string(2) "06"
How can I get the first week day in a given week number?
I'm making a function in PHP for a calendar app.
The idea: When I click on a link that basically uses strtotime with +1 month it only jumps to that same day of course. I need to get the week numbers correct.
Example: When I use the menu to move from August to September, it shouldn't select the same date I was in in August, but the first day of the first week number in September (Monday, 2th of September, week number 36).
And from September to October: Week number 40, Tuesday the 1th of October.
I found a function that exactly like you want it. This is setISODate
$date = new DateTime();
$date->setISODate(2013, 35, 1);
echo $date->format('Y-m-d');
You can change Y-m-d date format as you want
Output
2013-08-26 // This week number and monday
Usage
setISODate(year, week, day)
Try this code
<?php
$week = 3;
$year = 2009;
$timestamp = mktime( 0, 0, 0, 1, 1, $year ) + ( $week * 7 * 24 * 60 * 60 );
$timestamp_for_monday = $timestamp - 86400 * ( date( 'N', $timestamp ) - 1 );
$date_for_monday = date( 'Y-m-d', $timestamp_for_monday );
?>
Like every1 already said, ISO weeks start with monday. Quote from http://en.wikipedia.org/wiki/ISO_week_date : Weeks start with Monday.
If I understand your problem correctly, you need first-next-date in next month if selected week is in 2 different months?
function getFirstWeekDay($year, $week) {
$dt = (new DateTime)->setISODate($year, $week, 1);
$dtC = clone $dt;
for ($N = $dt->format('N'); $N < 7; $N++) {
$dtC->modify('+1 day');
if ($dt->format('m') !== $dtC->format('m')) {
return $dtC;
}
}
return $dt;
}
echo getFirstWeekDay(2013, 40)->format('W\t\h \w\e\e\k \i\s Y-m-d');
# 40th week is 2013-10-01
echo getFirstWeekDay(2013, 1)->format('W\t\h \w\e\e\k \i\s Y-m-d');
# 1th week is 2013-01-01
How can I find first day of the next month and the remaining days till this day from the present day?
Thank you
Create a timestamp for 00:00 on the first day of next month:
$firstDayNextMonth = strtotime('first day of next month');
The number of days til that date is the number of seconds between now and then divided by (24 * 60 * 60).
$daysTilNextMonth = ($firstDayNextMonth - time()) / (24 * 3600);
$firstDayNextMonth = date('Y-m-d', strtotime('first day of next month'));
For getting first day after two months from current
$firstDayAfterTwoMonths = date('Y-m-d', strtotime('first day of +2 month'));
You can use DateTime object like this to find out the first day of next month like this:
$date = new DateTime('first day of next month');
You can do this to know how many days left from now to the first day of next month:
$date = new DateTime('now');
$nowTimestamp = $date->getTimestamp();
$date->modify('first day of next month');
$firstDayOfNextMonthTimestamp = $date->getTimestamp();
echo ($firstDayOfNextMonthTimestamp - $nowTimestamp) / 86400;
The easiest and quickest way is to use strtotime() which recognizes 'first day next month';
$firstDayNextMonth = date('Y-m-d', strtotime('first day next month'));
Since I googled this and came to this answer, I figured I'd include a more modern answer that works for PHP 5.3.0+.
//Your starting date as DateTime
$currentDate = new DateTime(date('Y-m-d'));
//Add 1 month
$currentDate->add(new DateInterval('P1M'));
//Get the first day of the next month as string
$firstDayOfNextMonth = $currentDate->format('Y-m-1');
You can get the first of the next month with this:
$now = getdate();
$nextmonth = ($now['mon'] + 1) % 13 + 1;
$year = $now['year'];
if($nextmonth == 1)
$year++;
$thefirst = gmmktime(0, 0, 0, $nextmonth, $year);
With this example, $thefirst will be the UNIX timestamp for the first of the next month. Use date to format it to your liking.
This will give you the remaining days in the month:
$now = getdate();
$months = array(
31,
28 + ($now['year'] % 4 == 0 ? 1 : 0), // Support for leap years!
31,
30,
31,
30,
31,
31,
30,
31,
30,
31
);
$days = $months[$now['mon'] - 1];
$daysleft = $days - $now['mday'];
The number of days left will be stored in $daysleft.
Hope this helps!
$firstDayNextMonth = date('Y-m-d', mktime(0, 0, 0, date('m')+1, 1, date('Y')));
As another poster has mentioned the DateInterval object does not give accurate results for the next month when you use dates such as 1/31/2016 or 8/31/2016 as it skips the next month. My solution was to still use the DateInterval object but reformat your current date to be the first day of the current month prior to utilizing the DateInterval.
$currentDate = '8/31/2016';
$date = new DateTime(date("n", strtotime($currentDate))."/1/".date("Y", strtotime($currentDate)));
//add 1 month
$date->add(new DateInterval('P1M'));
$currentDate=$date->format('m/1/Y');
echo($currentDate);
easiest way to get the last day of the month
date('Y-m-d', mktime(0, 0, 0, date('m')+1, 1, date('Y')));
I took mattbasta's approach because it's able to get the 'first day of next month' with a given date, but there is a tiny problem in calculating the $nextmonth. The fix is as below:
$now = getdate();
$nextmonth = ($now['mon'] + 1) % 13 + 1;
$year = $now['year'];
if($nextmonth == 1)
$year++;
else
$nextmonth--;
$thefirst = gmmktime(0, 0, 0, $nextmonth, $year);
I initially thought about using a DateInterval object (as discussed above in another answer) but it is not reliable. For example, if the current DateTime is 31 January and then we add on a month (to get the next month) then it will skip February completely!
Here is my solution:
function start_of_next_month(DateTime $datetime)
{
$year = (int) $datetime->format('Y');
$month = (int) $datetime->format('n');
$month += 1;
if ($month === 13)
{
$month = 1;
$year += 1;
}
return new DateTime($year . '-' . $month . '-01');
}
Even easier way to get first and last day of next month
$first = strttotime("first day of next month");
$last = strttotime("last day of next month");
You could do something like this. To have this functionality, you need to make use of a php library available in https://packagist.org/packages/ishworkh/navigable-date.
With that is really easy to do what you're asking for here.
For e.g:
$format = 'Y-m-d H:i:s';
$Date = \NavigableDate\NavigableDateFacade::create('2017-02-24');
var_dump($Date->format($format));
$resetTime = true;
$resetDays = true;
$NextMonth = $Date->nextMonth($resetTime, $resetDays);
var_dump($NextMonth->format($format));
$DayUntilFirstOfNextMonth = $NextMonth->getDifference($Date);
var_dump('Days left:' . $DayUntilFirstOfNextMonth->format('%d'));
gives you ouput:
string(19) "2017-02-24 00:00:00"
string(19) "2017-03-01 00:00:00"
string(11) "Days left:5"
Note: Additionally this library let you navigate through dates by day(s), week(s), year(s) forward or backward. For more information look into its README.
(PHP 5 >= 5.5.0, PHP 7, PHP 8)
To get the first day of next month a clean solution:
<?php
$date = new DateTimeInmutable('now');
$date->modify('first day of next month');//here the magic occurs
echo $date->format('Y-m-d') . '\n';
Since you just want to calculate it I suggest using DateTimeInmutable class.
using the class DateTime and $date->modify('first day of next month'); will modify your original date value.
$month = date('m')+1;
if ($month<10) {
$month = '0'.$month;
}
echo date('Y-').$month.'-01';
Simplest way to achieve this. You can echo or store into variable.
I came up with this for my needs:
if(date('m') == 12) { $next_month = 1; } else { $next_month = date('m')+1; }
if($next_month == 1) { $year_start = date('Y')+1; } else { $year_start = date('Y'); }
$date_start_of_next_month = $year_start . '-' . $next_month . '-01 00:00:00';
if($next_month == 12) { $month_after = 1; } else { $month_after = $next_month+1; }
if($month_after == 1) { $year_end = date('Y')+1; } else { $year_end = date('Y'); }
$date_start_of_month_after_next = $year_end . '-' . $month_after . '-01 00:00:00';
Please note that instead of getting $date_end_of_next_month I chose to go with a $date_start_of_month_after_next date, it avoids the hassles with leap years and months containing different number of days.
You can simply use the >= comparaision sign for $date_start_of_next_month and the < one for $date_start_of_month_after_next.
If you prefer a timestamp format for the date, from there you will want to apply the strtotime() native function of PHP on these two variables.
You can use the php date method to find the current month and date, and then you would need to have a short list to find how many days in that month and subtract (leap year would require extra work).