JavaScript – sprawdzanie poprawności daty

No Comments

Będzie krótko i szybko. Problem jest trywialny – użytkownik ma podać datę. Nie ważne, w jaki sposób. Zakładamy, że nie chcemy/nie możemy (niepotrzebne skreślić) używać jakiegoś DatePickera. A nie możemy zostawić tego na głowie użytkownika, bo nawet, jeśli miałaby to być jego data urodzin, w 90% przypadków poda nieprawidłową :)

Najlepiej w ogóle dać użytkownikowi do wyboru (np. z pola SELECT) dni od 1 do 31, wtedy w ok. 50% przypadków powinno być wszystko w porządku :) Jeśli data ma zostać wpisana (a fe, co za rozwiązanie w ogóle?), jest gorzej, ale założenia są te same.

Na początek krótkie wprowadzenie do teorii sprawdzania poprawności daty. Musimy pamiętać o dwóch rzeczach:

  • ilości dni w poszczególnych miesiącach
  • ilości dni w lutym

Z grubsza to tyle. W kwestii rozwinięcia drugiego punktu, w podstawówce uczą nas, że jeśli rok jest przestępny, luty ma 29 dni, w przeciwnym wypadku 28. I że rok przestępny zdarza się co 4 lata…

…a przynajmniej tak było do 1582 roku. Z definicji wiadomo, że rok jest przestępny, jeśli jest podzielny przez 4, ale nie dotyczy to lat podzielnych przez 100, chyba, że są podzielne przez 400. I tego się trzymamy.

Prosty algorytm sprawdzania, czy rok jest przestępny, podany przez Wikipedię, wygląda następująco:

1
2
3
4
5
6
7
8
function czyPrzestępny(rok: integer): boolean;
begin
  if (rok mod 4 = 0) and (rok mod 100 <> 0) or (rok mod 400 = 0)
  then
    czyPrzestępny=true;
  else
    czyPrzestępny=false;
end;

Czyli generalnie po wklepaniu takiej funkcji, moglibyśmy już śmiało pisać algorytm, wyglądający mniej-więcej następująco:

  funkcja DataPoprawna(dzien, miesiac, rok)
  {
    // ogolne sprawdzenie poprawnosci danych
    jesli(!jestLiczba(dzien) || 
          !jestLiczba(miesiac) || 
          !jestLiczba(rok) ||
          dzien < 1 || miesiac < 1 || rok < 1)
      return false;
 
    // sprawdzenie dla poszczegolnych miesiecy
    jesli(miesiac nalezyDo(1, 3, 5, 7, 8, 10, 12) &&
          dzien < 32)
      return true;  // oszczedzamy czas, dzien i tak >= 1
 
    jesli(miesiac nalezyDo(4, 6, 9, 11) &&
          dzien < 31)
      return true;  // jw.
 
    // jesli funkcja jeszcze sie wykonuje, to podano albo
    // luty, albo nieprawdlowa date. Dla wygody:
    jesli(miesiac != 2)
      return false;
 
    // teraz pozostaje tylko luty:
    jesli(czyPrzestepny(rok))
      jesli(dzien < 30)
        return true;
    else jesli(dzien < 29)
      return true;
    return false;  // na wszelki wypadek :)
  }

Zaznaczę od razu, że powyższy “algorytm” nie jest zoptymalizowany, bo jest tylko pisanym na szybko przykładem dla zilustrowania problemu.
No dobrze, po co ja to piszę? Miałem podać rozwiązanie w JavaScript, tak? Po co ten pseudokod?

Z czystej przekory :) JavaScript posiada przydatne mechanizmy pobierania dnia/miesiaca/roku ze stringa z datą. Metody obiektu klady Date, takie jak:

  • .getDate()
  • .getMonth()
  • .getFullYear()

zwrócą albo pożądaną wartość, albo false, jeśli data jest niepoprawna. Raj na Ziemi!

Nagroda dla tych, którzy dotrwali do końca tego wpisu (albo przewinęli):

1
2
3
4
5
6
7
8
9
10
11
12
13
function sprawdzDate(dzien, miesiac, rok)
{
  // inwersja na format "amerykanski" :)
  var date_string = miesiac + "/" + dzien + "/" + rok;
  var date_obj    = new Date(date_string);
 
  if(date_obj.getDate()     != dzien || 
     // JavaScript liczy miesiace od 0 do 11
     date_obj.getMonth()    != (miesiac - 1) ||
     date_obj.getFullYear() != rok)
       return false;
  return true;
}

Szybciej i łatwiej, prawda?

Categories: JavaScript, Zabawy z kodem Tags: Tagi:,

Leave a Reply

Your email address will not be published. Required fields are marked *