Różnica czasowa to zmora dla tych co mają serwer np. w stanach. Nagle okazuje się, że nic się nie zgadza. W tym tutorialu napiszemy klase ktora zastapi nam funkcje date(), z ktorej, jesli nie uzywamy fizycznego serwera a tylko wirtualnego, musimy jak najszybciej zrezygnować!
Dlaczego? Łatwiej bedzie mi to wyjasnic jesli wyjaśnijmy sobie jak dzialaja podstawowe funkcje czasu i daty.
podstawa jest tu oczywiscie time() - ktory zwraca nam tzw. znacznik (stamp) unixowy. Nie jest to zadna data, a raczej rodzaj kalendarza (dziala podobnie jak kalendarz astronomiczny, tyle ze mniej dokladnie), ktorego dana chwila jest zapisywana w postaci liczby calkowitej wyrazajacej ilosc sekund jakie minely od dnia 1 stycznia 1970 roku o godzinie 0.00 czasu GMT. I tu od razu nalezy unikac pokusy, ktorej ja sam swego czasu nie uniknalem, by dodawac roznice czasowa do tej funkcji. To najgorszy blad! Dowiedza sie o tym Ci, ktorzy zmienia serwer na serwer w innej strefie czasowej. Przy funkcji time() nie trzeba nic robic, poniewaz w kazdej strefie czasowej w jakiej moglby byc serwer zawsze zwroci te sama wartosc.
Problemem jest funkcja date(), ktora na podstawie znacznika zwraca nam date jaka byla(jest) w danej strefie. Musielibysmy uzyc funkcji gmdate(), ktora zwraca nam date zawsze ta sama, date strefy GMT. Wystraczyloby dodac tylko godzinke i byloby po robocie, ale... niestety strefa gmt nie pzrewiduje czasu letniego. Jesli jednak, co nie jest trudne, zrobimy to funkcja, to spotka nas zawod: jesli mamy serwer w stanach - czas letni tam jest wprowadzany tydzien pozniej niz u nas! To tez, choc trudniej, mozna spacyfikowac, ale dostaniemy juz funkcje potworka. Lepiej zrobic cos uniwersalnego. Dzieki czemy bedziemy mogli skakac latwo po strefach.

Zaczynamy:

tworzymy klase w osobnym pliku, ja go nazwalem jak klase udate.php
w nim ostwieramy klase i definiujemy zmienne:


  1. <?php
  2. class udate
  3. {
  4. var $czl;
  5. var $czl_styl_klient;
  6. var $czl_styl_serwer;
  7. var $strefa;
  8. var $format;
  9.  
  10. }
  11. ?>


:arrow: $czl przyjmuje wartości 0 lub 1. 0 - nie uwzgledniamy czasu letniego, 1 - uwzgledniamy
:arrow: $czl_styl_klient przyjmuje wartości "US" lub "UE". "US" - czas letni ma byc brany pod uwage jak w USA, gdzie zaczyna się w pierwsza niedziele kwietnia, "UE" - tak jak w krajach Unii, gdzie zaczyna sie w ostatnia niedziele marca. Czas letni w obu stylach konczy sie w tym samym dniu.
:arrow: $czl_styl_serwer przyjmuje wartości "US" lub "UE". musimy ustawic tak aby zgadzal sie z polozeniem serwera. jezeli serwer jest w kraju gdzie czas letni rozpoczyna sie w ostatnia niedziele marca wybieramy wartosc "UE", jesli w pierwsza niedziele kwietnia to "US".
:arrow: $strefa, wartosci w zakresie -12 do 12. okresla w jakiej strefie przebywamy, lub z jakiej strefy chcemy uzyskac czas. dla Polski jest to 1 a np,. dla Nowego Yorku -5
:arrow: $format, format daty. np: "Y-m-d".

Teraz ustawimy wartosci standardowe. To znaczy dla tych, dla ktorychi nie okreslimy wartosci przy wywolaniu klasy. Robimy tzw. konstruktora czyli funkcje o takiej samej nazwie jak klasa. Dzieki temu bedzie ona sie wywolywac automatycznie:

  1. <?php
  2. function udate()
  3. {
  4. $this->czl=1;
  5. $this->czl_styl_klient=&#092;"UE\";
  6. $this->czl_styl_serwer=&#092;"UE\";
  7. $this->strefa=1;
  8. $this->format=&#092;"Y-m-d H:i\";
  9. }
  10.  
  11. ?>


tu chyba wszytko jasne. Teraz musimy stworzyc funkcje, ktorymi bedziemy zmieniac nasze wartosci:

  1. <?php
  2. function ustaw_czl($set)
  3. {
  4. if ($set==|| $set==0)
  5. {
  6.  $this->czl=$set;
  7. }
  8. else
  9. {
  10.  $this->czl=$this->czl;
  11. }
  12. }
  13.  
  14. function ustaw_czl_styl_klient($set)
  15. {
  16. if ($set==&#092;"US\" || $set==\"UE\")
  17. {
  18.  $this->czl_styl_klient=$set;
  19. }
  20. else
  21. {
  22.  $this->czl_styl_klient=$this->czl_styl_klient;
  23. }
  24. }
  25.  
  26. function ustaw_czl_styl_serwer($set)
  27. {
  28. if ($set==&#092;"US\" || $set==\"UE\")
  29. {
  30.  $this->czl_styl_serwer=$set;
  31. }
  32. else
  33. {
  34.  $this->czl_styl_serwer=$this->czl_styl_serwer;
  35. }
  36. }
  37.  
  38. function ustaw_strefa($set)
  39. {
  40. if ($set<12 || $set>-12)
  41. {
  42.  $this->strefa=$set;
  43. }
  44. else
  45. {
  46.  $this->strefa=$this->strefa;
  47. }
  48. }
  49.  
  50. function ustaw_format($set)
  51. {
  52. $this->format=$set;
  53. }
  54.  
  55. ?>


Oprocz zmiennej $format, kazda inna ma ma zabezpiedczenie - jesli podamy mu wartosc spoza dopuszczalnego zakresu zwroci nam wartosci zdefinowane na poczatku.

Teraz przechodzimy do sedna. Glowna funkcja:

  1. <?php
  2. function pokaz_date($stamp)
  3. {
  4.  $chk_dls=date(&#092;"I\",$stamp);
  5.  $year=gmdate(&#092;"Y\",$stamp);
  6. ///
  7.  
  8.  if ($this->czl_styl_klient==&#092;"UE\")
  9.  {
  10. $day=25;
  11. while ($dow!=&#092;"Sun\")
  12. {
  13.  $a=gmmktime (1,0,0,3,$day,$year);
  14.  $dow=gmdate(&#092;"D\",$a);
  15.  $day++;
  16. }
  17. $border=$a;
  18.  }
  19.  elseif($this->czl_styl_klient==&#092;"US\")
  20.  {
  21. $day=1;
  22. while ($dow!=&#092;"Sun\")
  23. {
  24.  $a=gmmktime (1,0,0,4,$day,$year);
  25.  $dow=gmdate(&#092;"D\",$a);
  26.  $day++;
  27. }
  28. $border=$a;
  29.  }
  30.  
  31. ///
  32.  if ($this->czl==1)
  33.  {
  34. if (($this->czl_styl_klient==&#092;"US\" && $this->czl_styl_serwer==\"US\")||($this->czl_styl_klient==\"UE\" && $this->czl_styl_serwer==\"UE\"))
  35. {
  36.  if ($chk_dls==1){$dat=gmdate($this->format,$stamp+(($this->strefa*3600)+3600));
  37.  }
  38.  else
  39.  {
  40.  $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  41.  }
  42. }
  43. elseif($this->czl_styl_klient==&#092;"US\" && $this->czl_styl_serwer==\"UE\")
  44. {
  45.  if ($chk_dls==&& $stamp>=$border)
  46.  {
  47.  $dat=gmdate($this->format,$stamp+(($this->strefa*3600)+3600));
  48.  }
  49.  else
  50.  {
  51.  $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  52.  }
  53. }
  54. elseif($this->czl_styl_klient==&#092;"UE\" && $this->czl_styl_serwer==\"US\")
  55. {
  56.  if ($chk_dls==|| ($stamp>=$border && $stamp<$border+(7*24*3600)))
  57.  {
  58.  $dat=gmdate($this->format,$stamp+(($this->strefa*3600)+3600));
  59.  }
  60.  else
  61.  {
  62.  $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  63.  }
  64. }
  65.  }
  66.  elseif($this->czl==0)
  67.  {
  68. $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  69.  }
  70.  
  71. print $dat;
  72. }
  73.  
  74. ?>


Wyjasnie po krotce co sie tu dzieje:
:arrow: linia 2: paramtr $stamp to oczywiscie znacznik unixowy., ktory w danym momencie zostal zwrocony przez funkcje time()
:arrow: linia 4: tu sprawdzamy czy na serwerze jest juz czas letni.
:arrow: linia 8-29: musimy wiedziec kiedy dokladnie przechodzimy w danym roku na czas letni w US lub UE. Chodzi o to, zebysmy odpowiednio zkorektowali to co dostalismy w lini 4.
:arrow: od lini 32: tworzymy date za pomoca funkcji gmdate(), dodajac/odejmujac do/od znacznika odpowiednia liczbe sekund. wynika to ze zmiennej "strefa". W przypadku kiedy musimy wziac pod uwage czas letni, mamy trzy warunki: serwer i klient znajduja sie w takiej strefie gdzie czas letni zaczyna sie w tym samym dniu, serwer znajduje sie w strefie gdzie rozpoczecie czasu letniego jest w roznych dniach (2 przypadki).

Teraz kilka przykladow. Bierzemy na tapete stamp z chwili przejscia na czas letni: 985482000 to 2001-03-25 02:00 wg czasu CET (np. Polska) a 2001-03-25 03:00 uwzgledniajac przejscie na czas letni. Byla to chwila kiedy z gdziny 2.00 przesunelismy zegarki na godzine 3.00

jesli mamy serwer w Polsce:
  1. <?php
  2. include &#092;"udate.php\";
  3. $udate=new udate();
  4. $udate->pokaz_date(&#092;"985482000\");
  5. ?>


zwroci nam: "2001-03-25 03:00"

jesli w stanach:

  1. <?php
  2. include &#092;"udate.php\";
  3. $udate=new udate();
  4. $udate->ustaw_czl(1);
  5. $udate->ustaw_czl_styl_klient(&#092;"UE\");
  6. $udate->ustaw_czl_styl_serwer(&#092;"US\");
  7. $udate->ustaw_strefa(1);
  8. $udate->pokaz_date(&#092;"985482000\");
  9.  
  10. ?>


zwroci nam znowu "2001-03-25 03:00", uzylem wszytkich dostepnych medod w celach pokazowych, niektorych nie trzeba bylo, bo i tak zawieraja wartosci juz zadeklarowane w konstruktorze

a jaka jest godzina w NY?:

  1. <?php
  2. include &#092;"udate.php\";
  3. $udate=new udate();
  4. $udate->ustaw_czl(1);
  5. $udate->ustaw_czl_styl_klient(&#092;"US\");
  6. $udate->ustaw_czl_styl_serwer(&#092;"UE\");
  7. $udate->ustaw_strefa(-5);
  8. $udate->pokaz_date(&#092;"985482000\");
  9.  
  10. ?>


otrzymamy date: "2001-03-24 20:00"

=====

oto jednolita klasa:

  1. <?php
  2. class udate{
  3. var $czl;
  4. var $czl_styl_klient;
  5. var $czl_styl_serwer;
  6. var $strefa;
  7. var $format;
  8.  
  9. function udate()
  10. {
  11. $this->czl=1;
  12. $this->czl_styl_klient=&#092;"UE\";
  13. $this->czl_styl_serwer=&#092;"UE\";
  14. $this->strefa=1;
  15. $this->format=&#092;"Y-m-d H:i\";
  16. }
  17.  
  18. function ustaw_czl($set)
  19. {
  20. if ($set==|| $set==0)
  21. {
  22.  $this->czl=$set;
  23. }
  24. else
  25. {
  26.  $this->czl=$this->czl;
  27. }
  28. }
  29.  
  30. function ustaw_czl_styl_klient($set)
  31. {
  32. if ($set==&#092;"US\" || $set==\"UE\")
  33. {
  34.  $this->czl_styl_klient=$set;
  35. }
  36. else
  37. {
  38.  $this->czl_styl_klient=$this->czl_styl_klient;
  39. }
  40. }
  41.  
  42. function ustaw_czl_styl_serwer($set)
  43. {
  44. if ($set==&#092;"US\" || $set==\"UE\")
  45. {
  46.  $this->czl_styl_serwer=$set;
  47. }
  48. else
  49. {
  50.  $this->czl_styl_serwer=$this->czl_styl_serwer;
  51. }
  52. }
  53.  
  54. function ustaw_strefa($set)
  55. {
  56. if ($set<12 || $set>-12)
  57. {
  58.  $this->strefa=$set;
  59. }
  60. else
  61. {
  62.  $this->strefa=$this->strefa;
  63. }
  64. }
  65.  
  66. function ustaw_format($set)
  67. {
  68. $this->format=$set;
  69. }
  70.  
  71. function pokaz_date($stamp)
  72. {
  73.  $chk_dls=date(&#092;"I\",$stamp);
  74.  $year=gmdate(&#092;"Y\",$stamp);
  75. ///
  76.  
  77.  if ($this->czl_styl_klient==&#092;"UE\")
  78.  {
  79. $day=25;
  80. while ($dow!=&#092;"Sun\")
  81. {
  82.  $a=gmmktime (1,0,0,3,$day,$year);
  83.  $dow=gmdate(&#092;"D\",$a);
  84.  $day++;
  85. }
  86. $border=$a;
  87.  }
  88.  elseif($this->czl_styl_klient==&#092;"US\")
  89.  {
  90. $day=1;
  91. while ($dow!=&#092;"Sun\")
  92. {
  93.  $a=gmmktime (1,0,0,4,$day,$year);
  94.  $dow=gmdate(&#092;"D\",$a);
  95.  $day++;
  96. }
  97. $border=$a;
  98.  }
  99.  
  100. ///
  101.  if ($this->czl==1)
  102.  {
  103. if (($this->czl_styl_klient==&#092;"US\" && $this->czl_styl_serwer==\"US\")||($this->czl_styl_klient==\"UE\" && $this->czl_styl_serwer==\"UE\"))
  104. {
  105.  if ($chk_dls==1){$dat=gmdate($this->format,$stamp+(($this->strefa*3600)+3600));
  106.  }
  107.  else
  108.  {
  109.  $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  110.  }
  111. }
  112. elseif($this->czl_styl_klient==&#092;"US\" && $this->czl_styl_serwer==\"UE\")
  113. {
  114.  if ($chk_dls==&& $stamp>=$border)
  115.  {
  116.  $dat=gmdate($this->format,$stamp+(($this->strefa*3600)+3600));
  117.  }
  118.  else
  119.  {
  120.  $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  121.  }
  122. }
  123. elseif($this->czl_styl_klient==&#092;"UE\" && $this->czl_styl_serwer==\"US\")
  124. {
  125.  if ($chk_dls==|| ($stamp>=$border && $stamp<$border+(7*24*3600)))
  126.  {
  127.  $dat=gmdate($this->format,$stamp+(($this->strefa*3600)+3600));
  128.  }
  129.  else
  130.  {
  131.  $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  132.  }
  133. }
  134.  }
  135.  elseif($this->czl==0)
  136.  {
  137. $dat=gmdate($this->format,$stamp+($this->strefa*3600));
  138.  }
  139.  
  140. print $dat;
  141. }
  142.  
  143. }
  144.  
  145. ?>



jesli chcemy zwracac date do zmiennej to musimy zamienic w lini 140

:arrow: print $dat; na return $dat;

wtedy:
  1. <?php
  2. include &#092;"udate.php\";
  3. $udate=new udate();
  4. $a=$udate->pokaz_date(time()); 
  5. print &#092;"<span style='font: 20px Courier'>\".$a.\"</span>\";
  6. ?>

otrzymamy datę bieżącą.

aby powrocic do standardowych ustawien (przyjetych w kontruktorze), jeśli je zmienialismy, wystaczy wpisac:
  1. <?php
  2. $udate->udate();
  3. ?>

przyklad:
  1. <?php
  2. include &#092;"udate.php\";
  3. $udate=new udate();
  4. $udate->ustaw_czl_styl_klient(&#092;"US\");
  5. $udate->ustaw_format(&#092;"H:i\");
  6. $a=$udate->pokaz_date(&#092;"985482000\");
  7. $udate->udate();
  8. $b=$udate->pokaz_date(&#092;"985482000\");
  9. echo $a.&#092;"<br>\".$b;
  10. ?>

zwroci nam:
02:00
2001-03-25 03:00