Pytanie PHP 5.4 nie może samodzielnie określić stref czasowych


Po prostu szukam trochę wyjaśnienia na ten temat. PHP 5.4 wyeliminowało zmienną środowiskową TZ i "zgadywanie" tego date_default_timezone_get używane do zrobienia. Teraz wydaje mi się, że nie ma sposobu, aby w ogóle uzyskać strefę czasową serwera.

Moje pytanie brzmi: czy można uzyskać strefę czasową serwera w PHP 5.4? Wiem, że mogę ręcznie ustawić go w php.ini, ale wydaje się to trochę głupie, gdy jest komputer, który doskonale wie, która jest godzina. Oczekuję, że odpowiedź brzmi "nie", więc być może ktoś może rzucić trochę światła na to, dlaczego język programowania nie byłby w stanie określić swojej strefy czasowej, jeśli tak jest.


12
2017-07-31 19:37


pochodzenie


[Jak automatycznie wykryć strefę czasową użytkownika?] [1] [1]: stackoverflow.com/questions/5203382/... - Siamak A.Motlagh
Dlaczego głupio jest poprawnie skonfigurować PHP? To nie jest tak, że strefa czasowa serwera jest dynamiczna ... - nickb
@nickb: Co jeśli masz wiele serwerów w różnych strefach czasowych, trudno będzie im udostępnić domyślne php.ini. - Mike Purcell
@MikePurcell - Zachowaj wszystkie standardowe konfiguracje w PHP.ini i nadpisaj to, co jest niezbędne w konfiguracji serwera. - nickb
Wydaje mi się, że użytkownik wybrał strefę czasową, kiedy dostał swój serwer, więc dlaczego miałbym prosić o powtórzenie? Ale także, powiedzmy, że preinstalowałem mój kod, teraz użytkownik musi zmienić strefę czasową w dwóch miejscach. Rozumiem, że to tylko niedogodność, ale jest to niedogodność WPROWADZONA w 5.4. Wcześniej wszystko działało dobrze. - Andrew


Odpowiedzi:


Nie ma niezawodnego sposobu na odgadnięcie strefy czasowej w każdym systemie. Różne systemy używają różnych konwencji, a czasem nawet różnych definicji stref czasowych (takich jak Unix i Windows), czasami mają sprzeczne specyfikatory stref czasowych (ten sam trzy-literowy skrót strefy może oznaczać różne rzeczy w różnych miejscach). Więc jeśli chcesz mieć kod, który jest przenośny między systemami, jedynym sposobem na niezawodne wykonanie tego jest poproszenie użytkownika. Zobacz na przykład ten wątek: http://marc.info/?t=132356551500002&r=1&w=2 w niektórych kwestiach z nim związanych (poszukaj wiadomości od Derick Rethans - jest on opiekunem rozszerzenia datetime PHP).

Jeśli masz sposób na znalezienie strefy czasowej, której ufasz - takiej jak zmienna TZ - to zawsze możesz to zrobić date_default_timezone_set($_SERVER['TZ']);. Generalnie nie jest to jednak niezawodna metoda, więc musisz podjąć decyzję, aby zaufać temu, PHP nie może tego zrobić dla ciebie.


4
2017-07-31 21:09



Słowo kluczowe tutaj jest przenośne. - Mike Purcell
Ale musisz ustawić zmienną TZ, prawda? - Andrew
Wątek. Właśnie przejrzałem wszystkie te e-maile. Przynajmniej Oleg jest po mojej stronie. Tak więc odpowiedź jest zasadniczo taka, że ​​się go pozbyli, ponieważ nie była przenośna. Myślę, że głupio jest wyeliminować funkcjonalność z tego powodu. Co się stanie, jeśli nie dbam o przenośność? Jeśli nie możemy zrobić czegoś w każdym systemie, nie możemy tego zrobić w żadnym systemie? No cóż. - Andrew
@Andrew dobrze, musiałbyś coś ustawić. Serwer nie może w magiczny sposób odgadnąć, w której strefie czasowej się znajduje. W systemie Unix, ty (lub ktokolwiek konfiguruje serwer) zwykle konfiguruje strefę czasową na serwerze, a następnie jest w zmiennej TZ. Ale w niektórych systemach jest inaczej - na przykład Mac OS X tego nie robi. A także Windows. A może inni ... - StasM
No cóż, używam systemu Windows, a zmienna TZ nie jest ustawiona, ale komputer zdecydowanie wie, w jakiej strefie czasowej jest ustawiony, ponieważ ustawienia czasu pokazują ją poprawnie. Problem polega na tym, że PHP usunął możliwość zadawania pytań systemowi, ponieważ nie jest wystarczająco "przenośny". Dla moich celów wszystko działało doskonale. - Andrew


Jeśli spojrzysz tutaj możesz zobaczyć kod z PHP 5.3, który próbowałby odgadnąć strefę czasową systemu. Nie ma aż tak wiele, ale wydaje się, że przyczyny usunięcia zgadywania są najczęściej związane z DST, ponieważ wydaje się, że problemy wydają się ujawniać.

Podział całego procesu zgadywania wygląda następująco:

  • Sprawdza, czy jest już zdefiniowana globalnie (php.ini lub wcześniejsze domysły) (linia 851-853)
  • Czek TZ zmienna środowiskowa (rzadko definiowana z mojego doświadczenia) (linia 855-858)
  • Czek date.default_timezone od php.ini (specjalny przypadek, jak powinien już być zdefiniowany) (wiersz 860-872)
  • Spróbuj odgadnąć strefę czasową z systemu, porównując time() niezgodne z localtime(). Wydaje się, że specyfikacja ustawienia strefy czasowej jest opcjonalna, ponieważ mogą występować problemy z wersjami gwintowanymi tego połączenia (wiersz 873-890)
  • Win32: Call funkcja WinAPI GetTimeZoneInformation() i spróbuj określić systemową strefę czasową (linia 893-928)
  • Netware: Sprawdź _timezone wartość, jeśli jest zdefiniowana (wiersz 929-937)
  • Obniżenie do UTC, jeśli żadna z powyższych kontroli nie powiodła się

Mogę tylko spekulować, ale może usunęli go tylko dlatego, że na początku był to domysł i nie zawsze jest niezawodny.

Również ze względu na popularność PHP, jest on instalowany na prawie każdym opartym na Linuksie wspólnym planie hostingu, w którym klienci często nie są w tej samej strefie czasowej co serwer, więc powrót do strefy czasowej serwera dla tych osób nie jest lepszy niż domyślne używanie UTC. To powoduje tylko zamieszanie, ponieważ ci klienci muszą przyjść do SO, aby zapytać, dlaczego czas jest błędny w PHP.

Nie jestem wystarczająco zaznajomiony z C i standardem, ale wygląda na to, że zgaduję strefę czasową localtime ma problemy z kodem wielowątkowym lub w niektórych przypadkach nie jest dostępny. Ponieważ na platformach innych niż Windows jest to najlepszy sposób na określenie strefy czasowej, nie ma sensu robić tego, jeśli mówi się, że przez połowę czasu nic nie zwraca lub powoduje problemy z wielowątkowym PHP.

Oczywiście w niektórych miejscach pojawia się kwestia czasu letniego, w której strefa czasowa i przesunięcie są różne w zależności od pory roku.

Nadzieja, która pomaga.


2
2017-07-31 21:26



Hmmm ... cóż, zdarza mi się używać Windowsa, więc interesuje mnie funkcja GetTimeZoneInformation (). Gdybym mógł wymyślić, jak to nazwać, prawdopodobnie rozwiązałby mój problem. Oczywiście robienie tego w inny sposób byłoby prawdopodobnie bardziej właściwe i prostsze w tym momencie. - Andrew
Większość pakietów do wywoływania funkcji Windows API nie jest już konserwowanych lub jest bardzo starych, więc jest mało prawdopodobne, że znajdziesz sposób na wywołanie tej funkcji z PHP, a nie napisanie jakiegoś programu, który zrobi to za ciebie, a potem exec()ten program. - drew010
Myślę, że twoja odpowiedź odpowiada na pierwszą część pytania. Odpowiedź brzmi: nie ma na to przenośnego sposobu, ale jeśli nie zależy Ci na przenośności, to z pewnością jest to możliwe, jeśli masz trochę wolnego czasu. Ale będzie to znacznie trudniejsze niż w PHP 5.3 i prawdopodobnie lepiej jest po prostu ustawić go w pliku config (ini). - Andrew
Problem z localtime () nie jest wątkiem. Problem polega na tym, że po aktualnym przesunięciu nic nie mówi na aktualnej strefie czasowej - wiele stref czasowych z różnymi regułami może w tym samym momencie mieć takie samo przesunięcie, a strefa czasowa jest o wiele więcej niż jednym przesunięciem w pewnym momencie. Może to prowadzić do sytuacji, w której kod użytkownika działa dzisiaj, ale przestanie działać w ciągu miesiąca, gdy rozbieżne będą różne reguły stref czasowych. Więc ludzie wracają i narzekają "PHP złamał mój kod, działało 2 dni temu, nic nie zmieniłem, a teraz to nie działa! PHP jest do bani!". Jawna wiadomość mówi ludziom, gdzie jest problem. - StasM
@StasM Dzięki za wyjaśnienie tego, ma sens i mówi głośno, dlaczego PHP usunął zgadywanie TZ. - drew010


Nie, nie ma możliwości odzyskania strefy czasowej na komputerze PC w tym momencie.


0
2017-07-31 19:40



"Spodziewam się, że odpowiedź brzmi" nie ", więc być może ktoś może rzucić trochę światła na to, dlaczego język programowania nie byłby w stanie określić swojej strefy czasowej, jeśli tak jest." - Zar


Niedawno zbudowałem kilka serwerów dla projektu od podstaw. Ze względu na wcześniejsze doświadczenia w innych projektach, w których serwery korzystały z lokalnych stref czasowych, zdecydowałem się zmusić każdy serwer do korzystania z strefy czasowej "UTC". Chociaż spowodowało to wyłączenie plików dziennika o 7 godzin (UTC - PST), usunęło to niespójność, która powodowała powstanie lokalnych stref czasowych (z poprzedniego projektu).

Wymuszona konsystencja okazała się pomocna na poziomie OS i aplikacji. W przypadku warstwy systemu operacyjnego wszystkie wpisy w plikach dziennika można przeglądać ze scentralizowanej lokalizacji (przez syslog over udp) niezależnie od ich fizycznej lokalizacji. W warstwie aplikacji znacznie łatwiej było przechowywać każdy znacznik czasu jako UTC, a następnie przekonwertować go na użytkowników, którzy określili strefę czasową. Ta jednokierunkowa konwersja jest znacznie prostsza niż konwersja dwukierunkowa, w której po zapisaniu trzeba będzie przekonwertować sygnaturę czasową na UTC z lokalnej strefy czasowej, a następnie przekonwertować ją do strefy czasowej wybranej przez użytkownika po renderowaniu.

Tak więc, o ile nie ma bardzo przekonującego powodu, dla którego twoje serwery znają strefę czasową, wolałbym pozostać przy UTC, który był domyślny przed 5.4: "Jeśli żadna z powyższych opcji się nie powiedzie, date_default_timezone_get () zwróci domyślną strefę czasową UTC. "


0
2017-07-31 20:49



Ale przed 5,4 działało to również poprzez "sprawdzanie systemu operacyjnego hosta". Mam więc kod, który wcześniej działał niezawodnie, który teraz nie tylko nie działa, ale nie może być w ogóle replikowany przez jakikolwiek kod. - Andrew
Czy możesz opublikować fragment kodu? - Mike Purcell
No cóż, "nie działa", mam na myśli to, że umieszcza czas w UTC, kiedy wcześniej był to America / New_York. I nie mogę powtórzyć poprzedniego zachowania w kodzie, ponieważ PHP jest teraz ślepy na strefę czasową OS. - Andrew
@Andrew działało w niektórych przypadkach, nie działało w innych. Tak więc nie działało to "niezawodnie" - mogło działać dla ciebie, ale nie dla innych. Jeśli potrzebujesz strefy czasowej OS na Uniksie i masz TZ var, wykonaj date_default_timezone_set ($ _ ENV ['TZ']) lub coś w tym stylu. - StasM
Chodzi mi o to, jakie szkody powstają teraz, gdy strefa czasowa to UTC? Może to tak proste, jak dodanie skryptu konwersji strefy czasowej podczas renderowania. Czy aplikacja umożliwia użytkownikom określenie stref czasowych? - Mike Purcell


To tylko dzikie domysły. Czy możesz uzyskać strefę czasową dzięki:

date('H', 0); czy coś takiego? Mam na myśli, ponieważ pieczęć unixtime jest taka sama we wszystkich regionach, ale Hour różni się, czy nie powinieneś bazować na godzinie, która strefa czasowa jest używana?


0
2017-07-31 21:17





Na serwerze Windows można uzyskać lokalną strefę czasową z odrobiną matematyki:

<?php
  date_default_timezone_set('UTC');

  $nowUTC = new DateTime();
  $nowSys = new DateTime(exec('echo %time%'));
  $offset = $nowUTC->diff($nowSys);

  echo $nowUTC->format('H:i:s') . '<br />';
  echo $nowSys->format('H:i:s') . '<br />';
  echo $offset->format('%H');
?>

Z mojego locale (UTC-05) w chwili pisania tego kodu wyjściowego tego kodu jest:

22:16:41
17:16:41
05

Jest jedno zastrzeżenie: czasem znaczniki czasu mogą być wyłączone o 1 sekundę, powodując $offset zmienna na 4:59:59. Uzyskanie właściwej strefy czasowej powinno trwale zaokrąglić, aby była bezpieczna.


0
2018-01-14 22:17