나는 이것이 반 직관적이고 실망 스럽다는 OP의 감정에 동의하지만 무엇을 +1 month
, 이것이 발생하는 시나리오에서 의미 기도합니다. 다음 예를 고려하십시오.
2015-01-31로 시작하여 한 달을 6 번 추가하여 이메일 뉴스 레터를 보내기위한 일정주기를 얻으려고합니다. OP의 초기 기대치를 염두에두고 다음을 반환합니다.
- 2015-01-31
- 2015-02-28
- 2015-03-31
- 2015-04-30
- 2015-05-31
- 2015-06-30
바로 시작점을 기준으로 반복 당 1 개월을 추가하거나 +1 month
의미 할 것으로 예상 됩니다 last day of month
. 이것을 "월의 마지막 날"로 해석하는 대신 "다음 달의 31 일 또는 해당 달의 마지막 사용 가능 날짜"로 읽을 수 있습니다. 즉, 5 월 30 일이 아니라 4 월 30 일에서 5 월 31 일로 점프합니다. 이것은 "마지막 날"이기 때문이 아니라 "시작 월의 날짜에 가장 가까운 날짜"를 원하기 때문입니다.
따라서 사용자 중 한 명이 2015-01-30에 시작하기 위해 다른 뉴스 레터를 구독한다고 가정합니다. 직관적 인 날짜는 무엇입니까 +1 month
? 한 가지 해석은 "다음 달의 30 일 또는 가장 가까운 사용 가능 날짜"이며 다음을 반환합니다.
- 2015-01-30
- 2015-02-28
- 2015-03-30
- 2015-04-30
- 2015-05-30
- 2015-06-30
사용자가 같은 날 두 뉴스 레터를받는 경우를 제외하고는 괜찮습니다. 이것이 수요 측이 아닌 공급측 문제라고 가정 해 보겠습니다. 사용자가 같은 날 뉴스 레터 2 개를받는 데 짜증이 날 것이라 걱정하지 않지만 대신 메일 서버가 두 번 전송하는 대역폭을 감당할 수 없습니다. 많은 뉴스 레터. 이를 염두에두고 "+1 개월"을 "매월 두 번째에서 마지막 날까지 보내기"라는 다른 해석으로 돌아가서 다음을 반환합니다.
- 2015-01-30
- 2015-02-27
- 2015-03-30
- 2015-04-29
- 2015-05-30
- 2015-06-29
이제 우리는 첫 번째 세트와의 겹침을 피했지만 4 월과 6 월 29 일로 끝납니다. 이것은 +1 month
단순히 돌아와야 하는 원래의 직관 m/$d/Y
이나 m/30/Y
가능한 모든 달 동안 매력적이고 단순한 것과 일치 합니다. 이제 +1 month
두 날짜 를 사용 하는 세 번째 해석을 고려해 보겠습니다 .
1 월 31 일
- 2015-01-31
- 2015-03-03
- 2015-03-31
- 2015-05-01
- 2015-05-31
- 2015-07-01
1 월 30 일
- 2015-01-30
- 2015-03-02
- 2015-03-30
- 2015-04-30
- 2015-05-30
- 2015-06-30
위는 몇 가지 문제가 있습니다. 2 월은 건너 뛰기 때문에 공급 단 (예 : 월별 대역폭 할당이 있고 2 월이 낭비되고 3 월이 두 배가되는 경우)과 수요 단 (사용자가 2 월에 속임을 느끼고 추가 3 월을 인식하는 경우) 모두 문제가 될 수 있습니다. 실수를 수정하려는 시도). 반면에 두 개의 날짜 세트는 다음과 같습니다.
- 겹치지 않음
- 그 달에 날짜가있는 날짜는 항상 같은 날짜입니다 (1 월 30 일 세트는 꽤 깔끔해 보입니다)
- 모두 "올바른"날짜로 간주 될 수있는 날짜로부터 3 일 (대부분의 경우 1 일) 이내입니다.
- 후임자 및 전임자로부터 모두 최소 28 일 (음력)이므로 매우 고르게 분포되어 있습니다.
마지막 두 세트를 감안할 때 실제 다음 달이 아닌 경우 날짜 중 하나를 롤백하고 (첫 번째 세트에서 2 월 28 일 및 4 월 30 일로 롤백) "월 말일"과 "월의 두 번째 날에서 말일"패턴이 가끔씩 겹치고 발산됩니다. 그러나 도서관이 "가장 예쁘고 자연스러운", "02/31 및 다른 달의 수학적 해석 넘침", "월 1 일 또는 지난달에 상대적"중에서 선택하기를 기대하는 것은 항상 누군가의 기대를 충족하지 못하고 끝날 것입니다. "잘못된"해석으로 인해 발생하는 실제 문제를 피하기 위해 "잘못된"날짜를 조정해야하는 일정.
다시 말하지만 +1 month
실제로 다음 달의 날짜를 반환 할 것으로 예상 하지만 직관만큼 간단하지 않고 선택 사항이 주어지면 웹 개발자의 기대를 뛰어 넘는 수학을 사용하는 것이 안전한 선택 일 것입니다.
다음은 여전히 어색하지만 좋은 결과가 있다고 생각하는 대체 솔루션입니다.
foreach(range(0,5) as $count) {
$new_date = clone $date;
$new_date->modify("+$count month");
$expected_month = $count + 1;
$actual_month = $new_date->format("m");
if($expected_month != $actual_month) {
$new_date = clone $date;
$new_date->modify("+". ($count - 1) . " month");
$new_date->modify("+4 weeks");
}
echo "* " . nl2br($new_date->format("Y-m-d") . PHP_EOL);
}
최적은 아니지만 기본 논리는 다음과 같습니다. 1 개월을 추가 한 결과 다음 달 예상 날짜가 아닌 경우 해당 날짜를 스크랩하고 대신 4 주를 추가합니다. 두 테스트 날짜의 결과는 다음과 같습니다.
1 월 31 일
- 2015-01-31
- 2015-02-28
- 2015-03-31
- 2015-04-28
- 2015-05-31
- 2015-06-28
1 월 30 일
- 2015-01-30
- 2015-02-27
- 2015-03-30
- 2015-04-30
- 2015-05-30
- 2015-06-30
(내 코드는 엉망이고 다년간의 시나리오에서는 작동하지 않습니다. 기본 전제가 그대로 유지되는 한, 즉 +1 개월이 펑키 한 날짜를 반환하는 한, 더 우아한 코드로 솔루션을 다시 작성하는 사람을 환영합니다. 대신 +4 주.)