PHP ile Gelişmiş Tarih-Doğrulama

7 Cevap php

Ben mevcut proje ile çok sayıda tarihlerini doğrulamak için var. Ne yazık ki, bu tarihler çılgınca değişebilir. Örnekler şunları içerir:

  1. 1983/07/10 (1970 sonrası)
  2. 1492/10/11 (1970 yılından önce, Unix damgaları yılı - bu bazı sistemlerde () strtotime ortadan kaldırır)
  3. 200 B.C. (Gerçekten eski ...)

Tarihler 9999 bc geçmez, ne de ('bugün' ötesinde) geleceği olacaktır. Ne sunulan değerler gerçekten tarihleri, ve o da uygun tarih olduğunu doğrulamak için en iyi yolu olurdu?

Updates...

Tüm tarihler global listesinde sıralanabilir olmalıdır. Yukarıda tarihleri ​​1 ve 3 Anlam bir-diğeri karşılaştırılabilir olması ve ASC veya DESC sınıflandırılmaktadır gerekir.

Ben geçmişte yer almış takvim değişiklikleri tam olarak farkında değilim, ve bu değişiklikler etrafında karışıklık. Benim proje kullanıcı zaten modern takvim sistemine göre tarihini öğrenmek için uygun kalibrasyon yürüttü varsayar. Ben onlar için bu kalibrasyonu olmayacaktır.

7 Cevap

Nasıl her olası biçimini tanımıyor özenle yazılmış düzenli ifadeler bir dizi hakkında. Eğer biçimini öğrendikten sonra, doğrulamak ve belki de bir üniforma temsili (örneğin, 64-bit time_t) içine koyabilirsiniz.

örneğin,

/(\d{4})-(\d{2})-(\d{2})/
/(\d+)(bc|b.c.|bce|b.c.e)/i
etc.

Her form kendi doğrulama kuralları vardır ve her yerde bulunabilen standart uygulayarak değil gibi geliyor çünkü, ben ayrı ayrı her durumda doğrulayarak sıkışmış düşünüyorum.

Güncelleme:

Tüm tarihler global listesinde sıralanabilir olmalıdır.

Bu sırayla önce belirttiğim gibi, içten, her biri için bir üniforma temsil gerekir farklı biçimlerde görünür tarihleri ​​sıralamak mümkün gibi geliyor bana. > (Giriş gösterimini) eşleştirmeleri - Örneğin, (uniform gösterimi) depolamak için bir çok anahtar sözlüğü (std :: PHP konusunda emin, C + + Multimap değil) kullanın. Kabın uygulanmasına bağlı olarak, aramalarını veya ücretsiz anahtar sipariş ters alabilirsiniz.

Ne Zend_Date kullanma hakkında. Zend's date library çok iyi bir tarih programı kütüphanedir. Bu bağımsız veya diğer Zend Kütüphaneleri ile çalışabilir ve tarihleri ​​otomatik olarak set timezone için ayrıştırıldı ve Unix zaman damgası aralığın dışındaki tarihlere için çalışacak kadar date_default_timezone_set () çalışabilirsiniz. Bu biraz uzun soluklu bazen yazmak için olabilir, ama güçlü yönleri büyük ölçüde kendi zayıflıklarını ağır basmaktadır.

Ben bunun için çalışmak istiyorsunuz emin değilim gibi BC / AD için kendi özel ayrıştırma uygulamak zorunda kalabilirsiniz, ama denemeye değer olabilir.

Pear also has a date library bakarak değer olabilir, ancak, ben kullanmadım ve armut en tarihi paketine Zend_Date tercih bir sürü insan duydum.

Her zaman kendi yazmak, ama neden tekerleği yeniden icat edebilirdi. İstediğiniz şekilde rulo değilse, onu almak ve onun üzerine geliştirmek ;)

Kendi özel DateTime türü sınıf uygulama düşünebilirsiniz. Ben tüm gereksinimleri ne emin değilim, ama ben sizin için tanıdık eğer bir para türü sınıf uygulama çok zor olmamalı biraz düşünce ile vb, biçimlendirme, BC / AD özelliklere sahip görebiliyordu .

Bu önermek nedeni M.Ö. 200 ve 1492/10/07 hatta bilge biçimlendirmek, çok farklı olmasıdır. Eğer BC

Eğer giriş arayüzü kontrolü olduğundan, genelliği kaybetmeden biz (düzgün için doğrulamak ... tamsayı olmak :) Ayrı yıl / ay / gün tamsayı olacağını varsayabiliriz. Kullanıcının o yıl BC göstermek için negatif olacaktır diyelim.

Bu yüzden öncelikle ... bariz (kısmi) cevap: checkdate(). Fonksiyon dokümantasyon dediği gibi bu, yıl> = 1 için sadece iyi.

Sen eğer yıl <= 0 yapmak ne sorunu ile sıkışmış bu nedenle yeniden.

Burada bir side-trek yapalım ve bu büyük bir sorun olabilir neden görmek ...

Yukarıdaki linke Wikipedia göre, Jülyen takvimi M.Ö. 45 yılında yürürlüğe girmiştir. Bu takvim bugün kullandığımız Gregoryen takvime özdeş tüm pratik amaçlar için, olduğunu. Fark aralarında ofset on gün orada olduğunu; Jülyen takviminin son günü Perşembe, Ekim 4, 1582 oldu ve bu Gregoryen takvimin ilk günü izledi, Cuma, 15 Ekim, 1582 (hafta içi çevrim etkilenmedi).

Bu zaten 14 Ekim 1582 aralığında 5 Ekim 1582 tarihler de (dahil) geçersiz if you are following the Gregorian calendar olduğu anlamına gelir; onlar hiçbir zaman yaşamadılar.

Oradan geriye doğru gidiyor, 'M.Ö. 45 yılına kadar iyisin. M.Ö. 46 geriye, Roman calendar Julian yerine kullanılmıştır.

Ben burada bir karışıklık içine gidecek, ama sadece bu takvim Gregoryen oldukça farklı olduğu için, kullanıcıların bir "Roma takvim tarih giriş formu" görmek için hazır olmayacak söz değil 'm. Benim önerim daha iyi teknik olarak doğru daha da app kullanışlı hale vardır.

Onların aklı kimse aslında güne M.Ö. tarihini bilmek, ya da düzgün belirtmek için nasıl olacağı varsayılabilir Eğer onlar olsa bile, keyfi tüm tarihler M.Ö. formu 1/1/YEAR sahip olduğunu varsayalım olabilir . Bir "BC" onay kutusu işaretli ise arayüz nedenle ay / gün kontrollerini devre dışı olabilir, ayrı grup M.Ö. kutuları ve AD, veya uygun başka bir şey var.

Bütün bunlardan sonra geriye kalan tek sorun, ben gördüğünüz gibi, artık yıl boyunca tarihlerini kontrol ediyor. Bu idi introduced with the Julian calendar, but not actually implemented correctly until 8 AD.

4 AD (dahil) artık yıl doğru hesaplanmış değil - 45 MÖ belgelerde yukarıda son halka. Bu tutarsızlık, artı Julian / Gregoryen anahtarı için hesapları A-yıl-sıçrama fonksiyonu olacaktır:

define('YEAR_JULIAN_CALENDAR_INTRODUCED', -45);
define('YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY', 8);
define('YEAR_GREGORIAN_CALENDAR_INTRODUCED', 1582);

function is_leap_year($year) {
    if($year < YEAR_JULIAN_CALENDAR_INTRODUCED) {
        return false; // or good luck :)
    }
    if($year < YEAR_JULIAN_CALENDAR_LEAP_IMPLEMENTED_CORRECTLY) {
        return $year <= -9 && $year % 3 == 0;
    }
    if($year < YEAR_GREGORIAN_CALENDAR_INTRODUCED) {
        return $year % 4 == 0;
    }
    // Otherwise, Gregorian is in effect
    return $year % 4 == 0 && ($year % 100 != 0 || $year % 400 == 0);
}

Bu donanmış, daha sonra doğru her yıl orada kaç gün söyler bir işlev yazabilirsiniz. Tarih çıkarma / ekleme o üzerine inşa edilebilir.

Bütün bu tartışmalardan sonra (Ben bu kadar :) ben sormak zorunda okuma herkesin cesaret hayran yapın:

How much accuracy do you actually need?

Eğer "teknik detaylar" hakkında anal gerekir karar verirseniz, ben şahsen yukarıda belirtilen fonksiyonları uygulamak istiyorum, ve sonra: a) Benim el işi tarih kütüphanesi olarak onları kullanın, veya b) kontrol etmek için bunları kullanın herhangi bir 3-rd taraf kitaplığı Ben is actually implemented correctly ilgileniyorum.

Bunu yapmak için ihtiyacınız yoksa, sadece tüm bu okumak hiç taklit. :)

Önemli olan, bence, tüm posibillities (ya da bir şekilde grup onları) listelemek ve her seçenek için düzenli ifadeler hazırlamak için - ve bu temelde tanımlamak ve anlaştım.

Jonathan'ın soru güncellemeden sonra ikinci cevap:

Basit tarih Karşılaştırma için, '(Ben birini bilmiyorum) tamsayı-gibi bir şey, ya da geri M.Ö. 9999 tarihleri ​​destekleyen bir sınıf kitaplığı kullanmanız gerekir d.

Sadece 1/1/10000 M.Ö. beri saniye sayısına (kendi çağı rulo) gibi kez belirtebiliriz; 64 bit bunun için fazlasıyla yeterli olacaktır. Bunu yapmak için, bir veya iki sorunları çözmek gerekiyor.

A. PHP 64-bit İnts yapmak için nasıl.

PHP tamsayılar için 31 bit sağlamak için garanti edilir. Bu nedenle, aşağıdakilerden birini yapabilirsiniz:

  1. İki özel tamsayı üyeleri bitlerini saklar kendi 62-bit tamsayı sınıf yazın. 62 bit de fazlasıyla vardır.

    Bu acı, ve muhtemelen hızlı olacaktır. Major advantage: you would not be dependent on any PHP extension.

  2. BCMath veya GMP keyfi duyarlıklı tamsayılar yapmak için kullanın.

    Ben taşınabilirliği bir zorunluluk değilse, ilk önce bu deneyin d. Bu olsa, kabul edilebilir daha yavaş olarak kanıtlamak olabilir. Major advantage: you don't risk getting the bit-fiddling code wrong.

Elinde 60-ya-so-bit tamsayı sınıf (ilgili yöntemler veya yardımcı fonksiyonları ile ekleme / çıkarma / karşılaştırma destekleyen), daha sonra tüm gerekli mantığı destekleyen bir CustomDateTime sınıf yazabilirsiniz. Bu sınıf, tüm "tarih-to-int" ve tersi kodu (örneğin inşaat) içerir; Tüm sahip-tamamen-to-do--int-uygulama işlemleri (örneğin karşılaştırma) sadece tamsayı sınıfına iletilecek.

B. veritabanında 64-bit İnts yapmak için nasıl.

Tüm veritabanları sorunsuz bunu. Neredeyse kesinlikle bu olsa yol gitmek gerekiyor çünkü örneğin MySQL MS 1000 önceki tarihleri ​​desteklemiyor. Diğer satıcılar hakkında bilmiyorum.

ne strtotime hakkında (?)