一个月后的第一个或最后一个星期五

时间:2021-10-04 01:08:29

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.

$week是一个整数(1,2,3…),$day是一天(Sun, Mon,…)或数字,无论哪个更简单。这个方向有点混乱,因为它做了不同的计算。

For an example, let's call

例如,我们调用

get_date(5, 2009, 1, 'Sun', 'forward');

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

它使用默认设置,并在5月的第一个星期日(2009-05-03)。如果我们称

get_date(5, 2009, 2, 'Sun', 'backward');

get_date(5, 2009, 2, 'Sun', '向后');

, it returns the second last Sunday in May ie 2009-05-24.

,它将于2009年5月的第2个星期日返回。

12 个解决方案

#1


12  

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.

请注意,$direction是1表示前进方向,-1表示后退方向,以使事情变得更容易。

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 ;)

我用了几个例子来测试它,而且似乎总是有效,但一定要仔细检查一下;

#2


20  

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.

要获得一个月的第一天,从这个月的第一天开始:yyyy-mm-01。使用任何可用的函数给出一个对应于星期的数字。从你要找的那天减去这个数字;例如,如果一个月的第一天是星期三(2),你在找星期五(4),4减去2,剩下2。如果答案是否定的,加7。最后把这个加到这个月的第一个月;以我为例,第一个星期五是第三个星期五。

To get the last Friday of the month, find the first Friday of the next month and subtract 7 days.

要得到这个月的最后一个星期五,找到下个月的第一个星期五,然后减去7天。

#3


9  

strtotime() can help you. e.g.

strtotime()可以帮助你。如。

<?php
$tsFirst = strtotime('2009-04-00 next friday');
$tsLast = strtotime('2009-05-01 last friday');
echo date(DATE_RFC850, $tsFirst), " | ", date(DATE_RFC850, $tsLast);
prints
Friday, 03-Apr-09 00:00:00 CEST | Friday, 24-Apr-09 00:00:00 CEST

#4


6  

No need for calculations or loops - this is very easy to do with strtotime():

不需要计算或循环—使用strtotime()非常容易:

Find the the Nth or Last occurrence of a particular day of a particular a month:

找出某一个月某一天的第n个或最后一个事件:

/////////////////////////////////////////////////////////////////
// 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.

#5


5  

PHP's built-in time functions make this simple.

PHP内置的时间函数使这个过程变得简单。

http://php.net/manual/en/function.strtotime.php

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.

请注意,我们总是希望确保我们已经定义了使用strtotime的正确时区,这样PHP就能够理解在哪里计算与机器认为它所在的时区相关的时间戳。

date_default_timezone_set('America/New_York');
$formattedDate = date('F j, Y', strtotime('first wed of last month +1 week'));

#6


4  

echo date('Y-m-d',strtotime('last friday'));

#7


2  

You can use mktime to retrieve the unix timestamp of the first day in the month:

您可以使用mktime检索当月第一天的unix时间戳:

$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.

从那时起,你就可以很容易地走到前面去约会。

#8


1  

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)

这对我来说是可行的,基于语言不可知的版本:-)很不幸,我需要做三角函数(因为如果一个月的最后一天是想要的工作日,我们不需要减去7)

#9


0  

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.

找出第一个和最后一个天月的问题是(即2009年5月1日是星期五,5月31日,2009是一个星期日)我相信大多数PHP函数使用星期一= 0,星期日= 6,因此周五= 4,所以你知道星期天(6)——周五(4)= 2,那么31-2 = 29,这意味着上周五本月29日。对于第一个星期五,如果数字是负数,加7,如果数字是0,这个月从星期五开始。

#10


0  

The same can be accomplished very elegantly using the DateTime class.

使用DateTime类可以非常优雅地完成相同的任务。

$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

#11


0  

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;
}

#12


0  

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.

如果你需要进一步的信息,请告诉我。

#1


12  

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.

请注意,$direction是1表示前进方向,-1表示后退方向,以使事情变得更容易。

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 ;)

我用了几个例子来测试它,而且似乎总是有效,但一定要仔细检查一下;

#2


20  

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.

要获得一个月的第一天,从这个月的第一天开始:yyyy-mm-01。使用任何可用的函数给出一个对应于星期的数字。从你要找的那天减去这个数字;例如,如果一个月的第一天是星期三(2),你在找星期五(4),4减去2,剩下2。如果答案是否定的,加7。最后把这个加到这个月的第一个月;以我为例,第一个星期五是第三个星期五。

To get the last Friday of the month, find the first Friday of the next month and subtract 7 days.

要得到这个月的最后一个星期五,找到下个月的第一个星期五,然后减去7天。

#3


9  

strtotime() can help you. e.g.

strtotime()可以帮助你。如。

<?php
$tsFirst = strtotime('2009-04-00 next friday');
$tsLast = strtotime('2009-05-01 last friday');
echo date(DATE_RFC850, $tsFirst), " | ", date(DATE_RFC850, $tsLast);
prints
Friday, 03-Apr-09 00:00:00 CEST | Friday, 24-Apr-09 00:00:00 CEST

#4


6  

No need for calculations or loops - this is very easy to do with strtotime():

不需要计算或循环—使用strtotime()非常容易:

Find the the Nth or Last occurrence of a particular day of a particular a month:

找出某一个月某一天的第n个或最后一个事件:

/////////////////////////////////////////////////////////////////
// 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.

#5


5  

PHP's built-in time functions make this simple.

PHP内置的时间函数使这个过程变得简单。

http://php.net/manual/en/function.strtotime.php

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.

请注意,我们总是希望确保我们已经定义了使用strtotime的正确时区,这样PHP就能够理解在哪里计算与机器认为它所在的时区相关的时间戳。

date_default_timezone_set('America/New_York');
$formattedDate = date('F j, Y', strtotime('first wed of last month +1 week'));

#6


4  

echo date('Y-m-d',strtotime('last friday'));

#7


2  

You can use mktime to retrieve the unix timestamp of the first day in the month:

您可以使用mktime检索当月第一天的unix时间戳:

$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.

从那时起,你就可以很容易地走到前面去约会。

#8


1  

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)

这对我来说是可行的,基于语言不可知的版本:-)很不幸,我需要做三角函数(因为如果一个月的最后一天是想要的工作日,我们不需要减去7)

#9


0  

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.

找出第一个和最后一个天月的问题是(即2009年5月1日是星期五,5月31日,2009是一个星期日)我相信大多数PHP函数使用星期一= 0,星期日= 6,因此周五= 4,所以你知道星期天(6)——周五(4)= 2,那么31-2 = 29,这意味着上周五本月29日。对于第一个星期五,如果数字是负数,加7,如果数字是0,这个月从星期五开始。

#10


0  

The same can be accomplished very elegantly using the DateTime class.

使用DateTime类可以非常优雅地完成相同的任务。

$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

#11


0  

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;
}

#12


0  

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.

如果你需要进一步的信息,请告诉我。

相关文章