![](http://blog.vokiel.com/wp-content/plugins/qr-code-tag/data/qrct-04d23071416e1a43ba4ab48c57d575e4.png)
2009
PHP Date – Polskie nazwy dni i miesięcy. Funkcje date strftime
Programując w PHP czasami natykamy się na problemy operując na datach w języku polskim. Chcąc uzyskać nazwy miesięcy i/lub dni tygodnia nie zawsze możemy polegać na wbudowanych w PHP funkcjach. Tym bardziej jeśli w grę wchodzi ich odmiana. Bardzo łatwo możemy sobie z tym poradzić. Wystarczy dopisać swoją funkcję.
Konfiguracja wbudowanych funkcji
Do dyspozycji mamy funkcje date()
oraz strftime()
. Pierwsza z nich niestety nie zwraca daty z lokalnymi nazwami. Za to strftime()
jest możliwe do ustawienia.
Co należy ustawić, aby domyślnie PHP korzystał z lokalizacji polskiej?
$arrLocales = array('pl_PL', 'pl','Polish_Poland.28592'); setlocale( LC_ALL, $arrLocales ); |
Funkcja setlocale()
ustawia opcje regionalne. Za pierwszy parametr może przyjmować:
- LC_ALL dla wszystkich poniżej
- LC_COLLATE ciąg dla porównania, patrz strcoll ()
- LC_CTYPE na charakter i klasyfikację konwersji, na przykład strtoupper ()
- LC_MONETARY dla localeconv ()
- LC_NUMERIC dla separator (Patrz także localeconv ())
- LC_TIME do formatowania daty i czasu z strftime ()
- LC_MESSAGES dla systemu odpowiedzi (dostępna jeśli PHP zostało skompilowane z libintl)
Dzięki temu zabiegowi ustawiliśmy język polski jako domyślny. Jednak problemy zaczynają się w przypadku, gdy zechcemy użyć kodowania innego niż ISO-8859-2
(które jest ustawiane poprzez Polish_Poland.28592'
). Musimy niestety przekonwertować zwracane dane z ISO-8859-2
na UTF-8
. Zrobimy to za pomocą prostej funkcji:
function strftimeV($format,$timestamp){ return iconv("ISO-8859-2","UTF-8",ucfirst(strftime($format,$timestamp))); } |
Użycie:
<?php echo strftimeV('%A %d %B %Y',strtotime('2009-09-02')); ?> |
Daje w wyniku Środa 02 wrzesień 2009
, co jest troszeczkę nie po polsku.
Utworzenie własnej funkcji obsługi formatu daty
Pozostaje nam stworzenie własnej funkcji, która odpowiednio zamieni format.
Na początku skryptu ustawiamy domyślną strefę czasową używaną przez funkcje date/time:
date_default_timezone_set('Europe/Warsaw'); |
Następnie tworzymy naszą funkcję, która odpowiednio przekonwertuje standardowy format daty dla funkcji date()
. Najlepiej aby była zgodna, tak aby w przypadku zamiany jej na zwykłą date()
nie trzeba było przepisywać formatów. Niestety w języku polskim mamy odmianę, co skutecznie uniemożliwia nam pełną zgodność. Problem pojawia się właściwie tylko w przypadku miesięcy, dni tygodnia zwykle używa się w formie podstawowej, natomiast miesiące już różnie. Raz jest styczeń, innym razem stycznia. Aby móc skorzystać z kilku form będziemy musieli rozszerzyć format daty o własne znaczniki.
Interesujące nas znaczniki formatu daty to l (małe L)
oraz F
. Dodamy własne oznaczenie f
, Które nie występuje na liście parametrów formatu date. Utwórzmy zatem własną funkcję dateV()
– czyli funkcję dateVokiel()
😉
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | function dateV($format,$timestamp=null){ $to_convert = array( 'l'=>array('dat'=>'N','str'=>array('Poniedziałek','Wtorek','Środa','Czwartek','Piątek','Sobota','Niedziela')), 'F'=>array('dat'=>'n','str'=>array('styczeń','luty','marzec','kwiecień','maj','czerwiec','lipiec','sierpień','wrzesień','październik','listopad','grudzień')), 'f'=>array('dat'=>'n','str'=>array('stycznia','lutego','marca','kwietnia','maja','czerwca','lipca','sierpnia','września','października','listopada','grudnia')) ); if ($pieces = preg_split('#[:/.\-, ]#', $format)){ if ($timestamp === null) { $timestamp = time(); } foreach ($pieces as $datepart){ if (array_key_exists($datepart,$to_convert)){ $replace[] = $to_convert[$datepart]['str'][(date($to_convert[$datepart]['dat'],$timestamp)-1)]; }else{ $replace[] = date($datepart,$timestamp); } } $result = strtr($format,array_combine($pieces,$replace)); return $result; } } |
Edit: Listing został zaktualizowany ze względu na wykryte błędy, szczegóły w komentarzach
Krótkie omówienie funkcji dla wywołania:
<?php echo dateV('l j f Y',strtotime('2009-09-02')); // Środa 2 września 2009 ?> |
W linii 2 definiujemy tablicę, która zawiera polskie odpowiedniki dni tygodnia oraz nazw miesięcy w odpowiedniej formie. Tablica zawiera indeksy odpowiadające standardowym znacznikom funkcji date, które zamienimy na nasze. Wewnątrz tablicy pola dat
mają za zadanie wskazanie znacznika dla funkcji date, który zostanie użyty jako index dla tablicy str
. Taki zabieg jest konieczny, gdyż musimy utworzyć znaczniki liczbowe danego dnia tygodnia bądź miesiąca, aby móc wyciągnąć ich polskie nazwy.
Linia 7 rozbija nam podany format na pojedyncze znaczniki.
W linii 8 tworzymy aktualny znacznik czasu, jeśli nie został podany.
Linie 10-16 są kluczowe dla zrozumienia sposobu zamiany podanego formatu aby zwracał poprawne dane.
W linii 10 sprawdzamy, czy aktualnie wybrany znacznik formatu występuje w naszej tablicy kwalifikującej go do zmiany.
Jeśli tak, to w linii 11 do tablicy $replace
dodajemy kolejny wiersz zawierający już utworzony element daty. Sposób jego utworzenia może wydawać się skomplikowany, jednak nie jest 😉
Rozbijmy wpis na części składowe. W pierwszej iteracji $datepart=='l'
1 2 3 4 5 6 7 | $replace[] = // dopisanie wiersza tablicy $to_convert[$datepart]['str'][( // odwołanie $to_convert['l']['str'][] czyli tablica dni tygodnia o indeksie: date( // data w formacie: $to_convert[$datepart]['dat'], //tablica dni tygodnia - format N (czyli numery dni od 1 (dla Poniedziałku) aż do 7 (dla Niedzieli)) $timestamp // znacznik czasu )-1) // pomniejszony o 1 (indexy w tablicy zaczynają się od 0 ) ]; |
Natomiast jeśli $datepart
nie zawiera się w tablicy $to_convert
wykona się linia 13.
W linii 13 do tablicy $replace
dodawane jest standardowe wywołanie funkcji date()
Na koniec po przejściu przez wszystkie elementy formatu, w linii 16, dokonuje się zamiana każdego z elementów formatu na odpowiadający mu, utworzony w pętli wcześniej, wynik działania funkcji date.
No i to wszystko 😉 Wystarczy teraz dodać własne znaczniki i odpowiadające im dane, aby móc cieszyć się poprawnymi, polskimi nazwami 😉
Bardzo mi się przydała 2 opcja kiedy, właśnie piszę jedno-plikowy panelik admina z bazą w pliku tekstowym, dla kolegi 🙂
Hmm, fajne ale. No właśnie ale. Mam coś takiego:
Wynik:
Mon01ay, 01 lutego 2010 (01-02-2010) 19:30
Co się dzieje?
Na liście znaków oddzielających poszczególne elementy daty nie było uwzględnionego przecinka. Wystarczy linię 7 zamienić z:
Na poniższy kod i powinno być ok:
Albo zrezygnować z przestarzałej funkcji split i użyć preg_split (jak słusznie zauważył jedre)
Linia 7 po poprawkach (już zaktualizowana w kodzie w treści posta)
dzięki za wstawkę, już się przydała! 🙂
Bardzo dziekuje, swietna funkcja, dziala az milo.
Jak zauważył użytkownik czarodziej na forum cba.pl w tym wątku , moja funkcja w pewnych przypadkach nie zachowywała się poprawnie.
Wynikało to z zastosowania funkcji str_replace, która potrafi ponownie zmienić już zmieniony ciąg. W związku z powyższym należy zamienić linię 16 z głównego listingu.
Zastosowanie poprawionej funkcji:
W treść wpisu została (ponownie) poprawiona.
Dzięki za świetny artykuł i świetną funkcję!!!
W moim przypadku, żeby skrypt działał musiałem poprzedzić backslashem spacje i inne znaki. Tak wygląda mój kawałek kodu, wyświetlający ostatnią datę modyfikacji dokumentu:
Hej! Świetna robota, ale ja zmieniłem funkcję rozbijającą na
str_split
więc rozdzielanie nie jest potrzebne (choć przecież celowe 😉 )
Dodałem jeszcze sobie rzymskie miesiące do converta:
Jako timestamp przyjmuję datę i ją tłumaczę strtotime-em, kiedy nie jest integerem, a jeszcze zaraz przywalę „+1d”, „-2m” – jako timestamp względem dziś :)))
Szaleć to szaleć!! 🙂
Proponuję w linii 7:
if( $pieces = preg_split( '#[:/.\-,\s+]#', $format, NULL, PREG_SPLIT_NO_EMPTY ) )
dzięki czemu będzie np. działać notacja:
dateEx( 'l, j f Y, G:i' )
czyli spacje po przecinkach. Wygląda to o wiele czytelniej, niż string pokropiony przecinkami.
A ogólnie bardzo przydatny snippet, dziękuję serdecznie.
[…] odmieniona. Mamy 21 lipiec 2014 r. A przecież użycie prostego kodu, na przykład z tej strony rozwiązuje problem. Na tej stronie też użyłem szablonu angielskojęzycznego i […]
Bardzo mi się przydało!
Dzięki wielkie!
Mnie zastanawia następująca rzecz. Lokalna maszyna wyświetla prawidłowe nazwy miesięcy przy ustawieniu:
Jednak ten sam kod na serwerze produkcyjnym działa inaczej. Czy istnieje jakiś sposób do zmuszenia PHP i funkcji strftime() to właściwego działania?
Spróbuj użyć:
setlocale(LC_ALL, 'pl_PL.UTF8');
[…] nie odmieniona. Mamy 21 lipiec 2014 r. A przecież użycie prostego kodu, na przykład z tej strony rozwiązuje problem. Na tej stronie też użyłem szablonu angielskojęzycznego […]
Super robota dzięki !!!