OP'nin bunun sezgiye aykırı ve sinir bozucu olduğu düşüncesine katılıyorum, ancak +1 month
bunun gerçekleştiği senaryolarda ne anlama geldiğini belirlemek de öyle . Şu örnekleri düşünün:
2015-01-31 ile başlıyorsunuz ve bir e-posta bülteni göndermek için bir zamanlama döngüsü almak üzere 6 kez bir ay eklemek istiyorsunuz. OP'nin ilk beklentileri göz önünde bulundurulduğunda, bu şu sonuca varacaktır:
- 2015-01-31
- 2015-02-28
- 2015-03-31
- 2015-04-30
- 2015-05-31
- 2015-06-30
Hemen, +1 month
demek istediğimizi last day of month
veya alternatif olarak her yineleme için 1 ay eklemeyi beklediğimizi , ancak her zaman başlangıç noktasına referans olarak aldığımızı unutmayın . Bunu "ayın son günü" olarak yorumlamak yerine "gelecek ayın 31. günü veya o ayın son günü" olarak okuyabilirdik. Bu, 30 Mayıs yerine 30 Nisan'dan 31 Mayıs'a atladığımız anlamına geliyor. Bunun "ayın son günü" olmasından değil, "başlangıç ayının tarihine en yakın kullanılabilirliği" istediğimizden kaynaklandığını unutmayın.
Öyleyse, kullanıcılarımızdan birinin 2015-01-30 tarihinde başlayacak başka bir bültene abone olduğunu varsayalım. Sezgisel tarih ne için +1 month
? Yorumlardan biri "gelecek ayın 30'uncu günü veya mevcut en yakın" olacaktır ve şunu döndürür:
- 2015-01-30
- 2015-02-28
- 2015-03-30
- 2015-04-30
- 2015-05-30
- 2015-06-30
Bu, kullanıcımızın aynı gün her iki haber bültenini de alması dışında iyi olur. Bunun talep tarafı yerine arz tarafı sorunu olduğunu varsayalım Kullanıcının aynı gün içinde 2 haber bülteni almasından rahatsız olacağından endişelenmiyoruz, bunun yerine posta sunucularımızın iki kat daha fazla gönderim için bant genişliğini karşılayamayacağından endişe etmiyoruz. birçok haber bülteni. Bunu aklımızda tutarak, "+1 ay" ın "her ayın ikinci gününden son gününe kadar gönder" şeklindeki diğer yorumuna geri dönüyoruz ve bu da şunu döndürür:
- 2015-01-30
- 2015-02-27
- 2015-03-30
- 2015-04-29
- 2015-05-30
- 2015-06-29
Şimdi ilk setle herhangi bir örtüşmeyi önledik, ancak aynı zamanda 29 Nisan ve Haziran ile son buluyoruz, ki bu, mümkün olan tüm aylar için +1 month
basitçe geri dönmesi gereken m/$d/Y
veya çekici ve basit m/30/Y
olan orijinal sezgilerimizle kesinlikle eşleşiyor . Şimdi +1 month
her iki tarihi de kullanmanın üçüncü bir yorumunu ele alalım :
31 Ocak
- 2015-01-31
- 2015-03-03
- 2015-03-31
- 2015-05-01
- 2015-05-31
- 2015-07-01
30 Ocak
- 2015-01-30
- 2015-03-02
- 2015-03-30
- 2015-04-30
- 2015-05-30
- 2015-06-30
Yukarıda bazı sorunlar var. Şubat atlandı, bu hem arz sonu (örneğin aylık bir bant genişliği tahsisi varsa ve Şubat boşa gidiyorsa ve Mart iki katına çıkıyorsa) hem de talep sonunda (kullanıcılar Şubat'tan aldatıldığını hissediyor ve fazladan Mart'ı algılıyorsa) bir sorun olabilir. hatayı düzeltme girişimi olarak). Öte yandan, iki tarihin belirlendiğine dikkat edin:
- asla örtüşme
- o ayın tarih olduğu her zaman aynı tarihtedir (bu nedenle 30 Ocak seti oldukça temiz görünür)
- tümü "doğru" tarih olarak kabul edilebilecek tarihin 3 günü (çoğu durumda 1 gün) içindedir.
- haleflerinden ve seleflerinden en az 28 gün (bir ay), bu yüzden çok eşit bir şekilde dağıtıldı.
Son iki set göz önüne alındığında, bir sonraki ayın dışına çıkarsa tarihlerden birini basitçe geri almak (ilk sette 28 Şubat ve 30 Nisan'a geri dönün) ve hiç uykunuzu kaybetmemek zor olmayacaktır. "ayın son günü" ile "ayın ikinci günü ile son günü" kalıbıyla ara sıra örtüşme ve sapma. Ancak kütüphaneden "en güzel / doğal", "02/31 ve diğer ayın taşmalarının matematiksel yorumu" ve "ayın ilkine veya geçen aya göre" arasında bir seçim yapmasını beklemek, her zaman birinin beklentilerinin karşılanmaması ile sona erecektir ve "yanlış" yorumun getirdiği gerçek dünya sorunundan kaçınmak için "yanlış" tarihi ayarlamaya ihtiyaç duyan bazı programlar.
Öyleyse yine, +1 month
aslında önümüzdeki ay olan bir tarihi geri getirmeyi beklerken , sezgiler kadar basit değil ve seçenekler verildiğinde, web geliştiricilerinin beklentilerinin üzerinde matematikle gitmek muhtemelen güvenli seçimdir.
İşte yine de herhangi biri kadar hantal olan alternatif bir çözüm, ancak bence güzel sonuçları var:
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);
}
Optimal değil, ancak temel mantık şudur: 1 ay eklemek, önümüzdeki ay beklenenden farklı bir tarihle sonuçlanırsa, o tarihi iptal edin ve bunun yerine 4 hafta ekleyin. İşte iki sınav tarihinin sonuçları:
31 Ocak
- 2015-01-31
- 2015-02-28
- 2015-03-31
- 2015-04-28
- 2015-05-31
- 2015-06-28
30 Ocak
- 2015-01-30
- 2015-02-27
- 2015-03-30
- 2015-04-30
- 2015-05-30
- 2015-06-30
(Kodum bir karmaşa ve çok yıllı bir senaryoda işe yaramaz. Temel önermeye dokunulmadan kaldığı sürece, yani +1 ay ilginç bir tarih döndürürse, çözümü daha zarif bir kodla yeniden yazmaya davet ediyorum. Bunun yerine +4 hafta.)