Czy istnieje standardowy sposób, aby serwer WWW mógł określić strefę czasową użytkownika na stronie internetowej?
Być może z nagłówka HTTP lub części user-agent
ciągu?
Czy istnieje standardowy sposób, aby serwer WWW mógł określić strefę czasową użytkownika na stronie internetowej?
Być może z nagłówka HTTP lub części user-agent
ciągu?
Odpowiedzi:
-new Date().getTimezoneOffset()/60;
Metoda getTimezoneOffset()
odejmie Twój czas od GMT i zwróci liczbę minut. Więc jeśli mieszkasz w GMT-8, zwróci 480.
Aby przeliczyć to na godziny, podziel przez 60. Zwróć też uwagę, że znak jest przeciwieństwem tego, czego potrzebujesz - oblicza przesunięcie GMT od Twojej strefy czasowej, a nie przesunięcie strefy czasowej od GMT. Aby to naprawić, wystarczy pomnożyć przez -1.
Zauważ też, że w3school mówi:
Zwrócona wartość nie jest stała ze względu na praktykę korzystania z czasu letniego.
>>> date.toTimeString() "15:46:04 GMT+1200 (New Zealand Standard Time)"
Najbardziej popularnym (== standardowym) sposobem określania strefy czasowej, którą widziałem, jest po prostu zapytanie użytkowników. Jeśli witryna wymaga subskrypcji, można ją zapisać w danych profilu użytkownika. W przypadku użytkowników anon daty mogą być wyświetlane jako UTC lub GMT lub niektóre podobne.
Nie staram się być mądrym idiotą. Po prostu czasami niektóre problemy mają lepsze rozwiązania poza jakimkolwiek kontekstem programowania.
Do tej pory nie ma nagłówków HTTP, które zgłosiłyby strefę czasową klientów, chociaż sugerowano włączenie jej do specyfikacji HTTP.
Gdybym to był ja, prawdopodobnie spróbowałbym pobrać strefę czasową za pomocą JavaScript po stronie klienta, a następnie przesłać ją na serwer za pomocą Ajax lub coś takiego.
JavaScript to najprostszy sposób na uzyskanie czasu lokalnego klienta. Sugerowałbym użycie XMLHttpRequest do odesłania czasu lokalnego, a jeśli to się nie powiedzie, wróć do strefy czasowej wykrytej na podstawie ich adresu IP.
Jeśli chodzi o geolokalizację, użyłem MaxMind GeoIP w kilku projektach i działa dobrze, chociaż nie jestem pewien, czy dostarczają one dane o strefie czasowej. Jest to usługa, za którą płacisz i zapewniają comiesięczne aktualizacje Twojej bazy danych. Zapewniają opakowania w kilku językach internetowych.
Po pierwsze, zrozum, że wykrywanie stref czasowych w JavaScript jest niedoskonałe. Można uzyskać przesunięcie lokalnej strefy czasowej dla określonej daty i godziny przy użyciu getTimezoneOffset
instancji Date
obiektu, ale nie jest to dokładnie to samo, co pełna strefa czasowa IANA, taka jakAmerica/Los_Angeles
.
Istnieje jednak kilka opcji, które mogą działać:
const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(tzid);
Wynikiem jest ciąg zawierający ustawienie strefy czasowej IANA komputera, na którym działa kod.
Obsługiwane środowiska są wymienione w tabeli zgodności Intl . Rozwiń DateTimeFormat
sekcję i spójrz na nazwaną funkcję resolvedOptions().timeZone defaults to the host environment
.
Niektóre biblioteki, takie jak Luxon, używają tego interfejsu API do określania strefy czasowej za pomocą funkcji takich jak luxon.Settings.defaultZoneName
.
Intl
interfejs API, jeśli jest on dostępny, a gdy nie jest dostępny, sprawdzają getTimezoneOffset
funkcję Date
obiektu dla kilku różnych punktów w czasie, wykorzystując wyniki do wybrania odpowiedniej strefy czasowej z wewnętrznego zestawu danych.Zarówno jsTimezoneDetect, jak i moment-timezone mają tę funkcję.
// using jsTimeZoneDetect
var tzid = jstz.determine().name();
// using moment-timezone
var tzid = moment.tz.guess();
W obu przypadkach wynik można traktować jedynie jako przypuszczenie. Zgadywanie może być poprawne w wielu przypadkach, ale nie we wszystkich.
Ponadto biblioteki te muszą być okresowo aktualizowane, aby przeciwdziałać faktowi, że wiele starszych implementacji JavaScript zna tylko bieżącą regułę czasu letniego dla swojej lokalnej strefy czasowej. Więcej informacji na ten temat tutaj.
Ostatecznie lepszym rozwiązaniem jest zapytanie użytkownika o strefę czasową. Podaj ustawienie, które mogą zmienić. Możesz użyć jednej z powyższych opcji, aby wybrać ustawienie domyślne , ale nie uniemożliwiaj odejścia od tego w aplikacji.
Istnieje również zupełnie inne podejście polegające na tym, że w ogóle nie zależy od ustawienia strefy czasowej komputera użytkownika. Zamiast tego, jeśli możesz zebrać współrzędne szerokości i długości geograficznej, możesz przekształcić je w strefę czasową przy użyciu jednej z tych metod . Działa to dobrze na urządzeniach mobilnych.
Oto niezawodne rozwiązanie JavaScript do określania strefy czasowej przeglądarki.
>>> var timezone = jstz.determine();
>>> timezone.name();
"Europe/London"
https://bitbucket.org/pellepim/jstimezonedetect
Załącznik 1: Teraz ten projekt znajduje się na GitHub: https://github.com/pellepim/jstimezonedetect
Oto bardziej kompletny sposób.
Fragment znajduje się poniżej:
function TimezoneDetect(){
var dtDate = new Date('1/1/' + (new Date()).getUTCFullYear());
var intOffset = 10000; //set initial offset high so it is adjusted on the first attempt
var intMonth;
var intHoursUtc;
var intHours;
var intDaysMultiplyBy;
// Go through each month to find the lowest offset to account for DST
for (intMonth=0;intMonth < 12;intMonth++){
//go to the next month
dtDate.setUTCMonth(dtDate.getUTCMonth() + 1);
// To ignore daylight saving time look for the lowest offset.
// Since, during DST, the clock moves forward, it'll be a bigger number.
if (intOffset > (dtDate.getTimezoneOffset() * (-1))){
intOffset = (dtDate.getTimezoneOffset() * (-1));
}
}
return intOffset;
}
Pobieranie TZ i DST z JS (przez Way Back Machine)
Africa/Johannesburg
lub Europe/Istanbul
. Zobacz wiki tagu strefy czasowej .
Stosując podejście Unkwntech, napisałem funkcję używając jQuery i PHP. To jest przetestowane i działa!
Na stronie PHP, w której chcesz ustawić strefę czasową jako zmienną, umieść ten fragment kodu gdzieś u góry strony:
<?php
session_start();
$timezone = $_SESSION['time'];
?>
Spowoduje to odczytanie zmiennej sesji „time”, którą właśnie stworzymy.
Na tej samej stronie, w <head> musisz przede wszystkim dołączyć jQuery:
<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>
Również w <head>, poniżej jQuery, wklej to:
<script type="text/javascript">
$(document).ready(function() {
if("<?php echo $timezone; ?>".length==0){
var visitortime = new Date();
var visitortimezone = "GMT " + -visitortime.getTimezoneOffset()/60;
$.ajax({
type: "GET",
url: "http://example.org/timezone.php",
data: 'time='+ visitortimezone,
success: function(){
location.reload();
}
});
}
});
</script>
Być może zauważyłeś, ale musisz zmienić adres URL na rzeczywistą domenę.
Ostatnia rzecz. Prawdopodobnie zastanawiasz się, co to do cholery jest strefa czasowa.php. Po prostu: (utwórz nowy plik o nazwie timezone.php i wskaż go za pomocą powyższego adresu URL)
<?php
session_start();
$_SESSION['time'] = $_GET['time'];
?>
Jeśli to działa poprawnie, najpierw załaduje stronę, uruchom JavaScript i załaduje stronę ponownie. Będziesz wtedy mógł odczytać zmienną $ timezone i wykorzystać ją dla własnej przyjemności! Zwraca bieżące przesunięcie strefy czasowej UTC / GMT (GMT -7) lub dowolną strefę czasową, w której się znajdujesz.
Aby przesłać przesunięcie strefy czasowej jako nagłówek HTTP dla żądań AJAX za pomocą jQuery
$.ajaxSetup({
beforeSend: function(xhr, settings) {
xhr.setRequestHeader("X-TZ-Offset", -new Date().getTimezoneOffset()/60);
}
});
Możesz również zrobić coś podobnego, aby uzyskać rzeczywistą nazwę strefy czasowej, korzystając moment.tz.guess();
ze strony http://momentjs.com/timezone/docs/#/using-timezones/guessing-user-timezone/
Nadal nie widziałem tutaj szczegółowej odpowiedzi, która określa strefę czasową. Nie powinieneś potrzebować geokodować według adresu IP ani używać PHP (lol) lub niepoprawnie zgadywać z przesunięcia.
Po pierwsze, strefa czasowa to nie tylko przesunięcie w stosunku do GMT. Jest to obszar ziemi, w którym zasady czasowe są określone przez lokalne standardy. Niektóre kraje mają czas letni i włączają czas letni w różnym czasie. Zazwyczaj ważne jest uzyskanie rzeczywistej strefy, a nie tylko bieżącego przesunięcia.
Jeśli zamierzasz przechowywać tę strefę czasową, na przykład w preferencjach użytkownika, chcesz strefę, a nie tylko przesunięcie. W przypadku konwersji w czasie rzeczywistym nie będzie to miało większego znaczenia.
Teraz, aby uzyskać strefę czasową z javascript, możesz użyć tego:
>> new Date().toTimeString();
"15:46:04 GMT+1200 (New Zealand Standard Time)"
//Use some regular expression to extract the time.
Jednak łatwiej mi było użyć tej solidnej wtyczki, która zwraca strefę czasową sformatowaną przez Olsena:
Z PHP date
funkcji otrzymasz datę i godzinę serwera, na którym znajduje się strona. Jedynym sposobem na uzyskanie czasu użytkownika jest użycie JavaScript.
Ale sugeruję, abyś, jeśli twoja strona wymaga rejestracji, najlepszym sposobem jest zapytanie użytkownika o rejestrację jako pole obowiązkowe. Możesz wymienić różne strefy czasowe na stronie rejestru i zapisać je w bazie danych. Następnie, jeśli użytkownik zaloguje się na stronie, możesz ustawić domyślną strefę czasową dla tej sesji zgodnie z wybraną strefą czasową użytkownika.
Możesz ustawić dowolną konkretną strefę czasową za pomocą funkcji PHP date_default_timezone_set
. Ustawia określoną strefę czasową dla użytkowników.
Zasadniczo strefa czasowa użytkowników przechodzi po stronie klienta, więc musimy do tego użyć JavaScript.
Poniżej znajduje się skrypt do uzyskiwania strefy czasowej użytkowników za pomocą PHP i JavaScript.
<?php
#http://www.php.net/manual/en/timezones.php List of Time Zones
function showclienttime()
{
if(!isset($_COOKIE['GMT_bias']))
{
?>
<script type="text/javascript">
var Cookies = {};
Cookies.create = function (name, value, days) {
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
var expires = "; expires=" + date.toGMTString();
}
else {
var expires = "";
}
document.cookie = name + "=" + value + expires + "; path=/";
this[name] = value;
}
var now = new Date();
Cookies.create("GMT_bias",now.getTimezoneOffset(),1);
window.location = "<?php echo $_SERVER['PHP_SELF'];?>";
</script>
<?php
}
else {
$fct_clientbias = $_COOKIE['GMT_bias'];
}
$fct_servertimedata = gettimeofday();
$fct_servertime = $fct_servertimedata['sec'];
$fct_serverbias = $fct_servertimedata['minuteswest'];
$fct_totalbias = $fct_serverbias – $fct_clientbias;
$fct_totalbias = $fct_totalbias * 60;
$fct_clienttimestamp = $fct_servertime + $fct_totalbias;
$fct_time = time();
$fct_year = strftime("%Y", $fct_clienttimestamp);
$fct_month = strftime("%B", $fct_clienttimestamp);
$fct_day = strftime("%d", $fct_clienttimestamp);
$fct_hour = strftime("%I", $fct_clienttimestamp);
$fct_minute = strftime("%M", $fct_clienttimestamp);
$fct_second = strftime("%S", $fct_clienttimestamp);
$fct_am_pm = strftime("%p", $fct_clienttimestamp);
echo $fct_day.", ".$fct_month." ".$fct_year." ( ".$fct_hour.":".$fct_minute.":".$fct_second." ".$fct_am_pm." )";
}
showclienttime();
?>
Ale z mojego punktu widzenia lepiej zapytać użytkowników, czy rejestracja jest obowiązkowa w twoim projekcie.
Nie używaj adresu IP do ostatecznego określania lokalizacji (a tym samym strefy czasowej) - to dlatego, że w przypadku NAT, serwerów proxy (coraz bardziej popularne) i VPN, adresy IP niekoniecznie realistycznie odzwierciedlają rzeczywistą lokalizację użytkownika, ale lokalizację, w której znajdują się serwery implementujące te protokoły.
Podobne do tego, w jaki sposób numery kierunkowe w USA nie są już przydatne do lokalizowania użytkownika telefonu, biorąc pod uwagę popularność przenoszenia numerów.
Adres IP i inne techniki pokazane powyżej są przydatne do sugerowania wartości domyślnej, którą użytkownik może dostosować / poprawić.
JavaScript:
function maketimus(timestampz)
{
var linktime = new Date(timestampz * 1000);
var linkday = linktime.getDate();
var freakingmonths = new Array();
freakingmonths[0] = "jan";
freakingmonths[1] = "feb";
freakingmonths[2] = "mar";
freakingmonths[3] = "apr";
freakingmonths[4] = "may";
freakingmonths[5] = "jun";
freakingmonths[6] = "jul";
freakingmonths[7] = "aug";
freakingmonths[8] = "sep";
freakingmonths[9] = "oct";
freakingmonths[10] = "nov";
freakingmonths[11] = "dec";
var linkmonthnum = linktime.getMonth();
var linkmonth = freakingmonths[linkmonthnum];
var linkyear = linktime.getFullYear();
var linkhour = linktime.getHours();
var linkminute = linktime.getMinutes();
if (linkminute < 10)
{
linkminute = "0" + linkminute;
}
var fomratedtime = linkday + linkmonth + linkyear + " " +
linkhour + ":" + linkminute + "h";
return fomratedtime;
}
Po prostu podaj swoje czasy w formacie uniksowego znacznika czasu dla tej funkcji; JavaScript zna już strefę czasową użytkownika.
Lubię to:
PHP:
echo '<script type="text/javascript">
var eltimio = maketimus('.$unix_timestamp_ofshiz.');
document.write(eltimio);
</script><noscript>pls enable javascript</noscript>';
To zawsze pokaże czasy poprawnie w oparciu o strefę czasową, którą dana osoba ustawiła na swoim komputerze. Dzięki Bogu, nie trzeba nikogo o nic prosić i zapisywać go w miejscach.
Łatwo, wystarczy użyć getTimezoneOffset
funkcji JavaScript tak:
-new Date().getTimezoneOffset()/60;
Wydaje się, że cała magia jest w środku
visitortime.getTimezoneOffset()
Fajnie, nie wiedziałem o tym. Czy to działa w przeglądarce Internet Explorer itp.? Stamtąd powinieneś być w stanie używać JavaScript do Ajax, ustawiać pliki cookie, cokolwiek. Prawdopodobnie sam bym poszedł na ciastko.
Musisz jednak pozwolić użytkownikowi to zmienić. Próbowaliśmy użyć geolokalizacji (przez maxmind), aby to zrobić jakiś czas temu, i było to dość często niewłaściwe - na tyle, że nie warto tego robić, więc po prostu pozwalamy użytkownikowi ustawić to w swoim profilu i wyświetlać powiadomienie użytkownikom, którzy jeszcze ich nie ustawił.
Oto artykuł (z kodem źródłowym), który wyjaśnia, jak określić i wykorzystać zlokalizowany czas w aplikacji ASP.NET (VB.NET, C #):
Krótko mówiąc, opisane podejście opiera się na getTimezoneOffset
funkcji JavaScript , która zwraca wartość zapisaną w cookie sesyjnym i wykorzystywaną przez kod w celu dostosowania wartości czasu między GMT a czasem lokalnym. Zaletą jest to, że użytkownik nie musi określać strefy czasowej (kod robi to automatycznie). Jest więcej zaangażowanych (dlatego link do artykułu), ale podany kod sprawia, że jest naprawdę łatwy w użyciu. Podejrzewam, że możesz przekonwertować logikę na PHP i inne języki (o ile rozumiesz ASP.NET).
Jeśli używasz OpenID do uwierzytelniania, Simple Registration Extension rozwiąże problem dla uwierzytelnionych użytkowników (musisz przekonwertować z tz na numeryczny).
Inną opcją byłoby wywnioskowanie strefy czasowej na podstawie preferencji kraju agenta użytkownika. Jest to dość prymitywna metoda (nie działa dla en-US), ale stanowi dobre przybliżenie.
W JavaScript i PHP jest to proste:
Mimo że użytkownik może zepsuć swój wewnętrzny zegar i / lub strefę czasową, najlepszym sposobem, jaki do tej pory znalazłem, aby uzyskać przesunięcie, pozostaje new Date().getTimezoneOffset();
. Jest nieinwazyjny, nie boli głowy i eliminuje potrzebę polegania na osobach trzecich.
Powiedzmy, że mam tabelę users
zawierającą pole date_created int(13)
do przechowywania znaczników czasu Unix;
Zakładając creates a new account
, że dane są odbierane przez klienta , post
a ja potrzebuję do insert/update
niego date_created column
uniksowego znacznika czasu klienta, a nie serwera.
Ponieważ timezoneOffset jest potrzebny w momencie wstawiania / aktualizacji, jest przekazywany jako dodatkowy element $ _POST, gdy klient przesyła formularz, eliminując w ten sposób potrzebę przechowywania go w sesjach i / lub plikach cookie, a także żadnych dodatkowych trafień na serwer.
var off = (-new Date().getTimezoneOffset()/60).toString();//note the '-' in front which makes it return positive for negative offsets and negative for positive offsets
var tzo = off == '0' ? 'GMT' : off.indexOf('-') > -1 ? 'GMT'+off : 'GMT+'+off;
Powiedz, że serwer otrzymuje tzo
jako $_POST['tzo']
;
$ts = new DateTime('now', new DateTimeZone($_POST['tzo']);
$user_time = $ts->format("F j, Y, g:i a");//will return the users current time in readable format, regardless of whether date_default_timezone() is set or not.
$user_timestamp = strtotime($user_time);
Wstaw / aktualizuj date_created=$user_timestamp
.
Podczas pobierania utworzonej daty możesz przekształcić znacznik czasu w następujący sposób:
$date_created = // Get from the database
$created = date("F j, Y, g:i a",$date_created); // Return it to the user or whatever
Teraz ten przykład może pasować first
do twoich potrzeb, jeśli chodzi o wstawianie znacznika czasu ... Jeśli chodzi o dodatkowy znacznik czasu lub tabelę, możesz rozważyć wstawienie wartości tzo do tabeli użytkowników do wykorzystania w przyszłości lub ustawienie jej jako sesja lub plik cookie.
PS ALE co jeśli użytkownik podróżuje i zmienia strefy czasowe. Loguje się na GMT + 4, szybko jedzie do GMT-1 i loguje się ponownie. Ostatnie logowanie będzie w przyszłości.
Myślę, że ... myślimy za dużo.
Możesz to zrobić na kliencie w strefie czasowej i wysłać wartość na serwer; przykładowe użycie:
> moment.tz.guess()
"America/Asuncion"
Uzyskanie prawidłowej nazwy strefy czasowej bazy danych TZ w PHP to proces dwuetapowy:
Dzięki JavaScript możesz uzyskać przesunięcie strefy czasowej w kilka minut getTimezoneOffset
. To przesunięcie będzie dodatnie, jeśli lokalna strefa czasowa jest opóźniona w stosunku do UTC, i ujemne, jeśli nastąpi w przód. Musisz więc dodać przeciwny znak do odsunięcia.
var timezone_offset_minutes = new Date().getTimezoneOffset();
timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;
Przekaż to przesunięcie do PHP.
W PHP przekonwertuj to przesunięcie na prawidłową nazwę strefy czasowej za pomocą funkcji timezone_name_from_abbr .
// Just an example.
$timezone_offset_minutes = -360; // $_GET['timezone_offset_minutes']
// Convert minutes to seconds
$timezone_name = timezone_name_from_abbr("", $timezone_offset_minutes*60, false);
// America/Chicago
echo $timezone_name;</code></pre>
Napisałem na nim post na blogu: Jak wykryć strefę czasową użytkownika w PHP . Zawiera także wersję demo.
Intl.DateTimeFormat().resolvedOptions().timeZone
i wysłanie go do serwera WWW. Ref: stackoverflow.com/questions/9772955/…
Prostym sposobem na to jest użycie:
new Date().getTimezoneOffset();
Jedną z możliwych opcji jest użycie Date
pola nagłówka, które jest zdefiniowane w RFC 7231 i powinno obejmować strefę czasową. Oczywiście nie ma gwarancji, że wartość jest tak naprawdę strefą czasową klienta, ale może być dogodnym punktem wyjścia.
Oto jak to robię. Spowoduje to ustawienie domyślnej strefy czasowej PHP na lokalną strefę czasową użytkownika. Wystarczy wkleić następujące na górze wszystkich stron:
<?php
session_start();
if(!isset($_SESSION['timezone']))
{
if(!isset($_REQUEST['offset']))
{
?>
<script>
var d = new Date()
var offset= -d.getTimezoneOffset()/60;
location.href = "<?php echo $_SERVER['PHP_SELF']; ?>?offset="+offset;
</script>
<?php
}
else
{
$zonelist = array('Kwajalein' => -12.00, 'Pacific/Midway' => -11.00, 'Pacific/Honolulu' => -10.00, 'America/Anchorage' => -9.00, 'America/Los_Angeles' => -8.00, 'America/Denver' => -7.00, 'America/Tegucigalpa' => -6.00, 'America/New_York' => -5.00, 'America/Caracas' => -4.30, 'America/Halifax' => -4.00, 'America/St_Johns' => -3.30, 'America/Argentina/Buenos_Aires' => -3.00, 'America/Sao_Paulo' => -3.00, 'Atlantic/South_Georgia' => -2.00, 'Atlantic/Azores' => -1.00, 'Europe/Dublin' => 0, 'Europe/Belgrade' => 1.00, 'Europe/Minsk' => 2.00, 'Asia/Kuwait' => 3.00, 'Asia/Tehran' => 3.30, 'Asia/Muscat' => 4.00, 'Asia/Yekaterinburg' => 5.00, 'Asia/Kolkata' => 5.30, 'Asia/Katmandu' => 5.45, 'Asia/Dhaka' => 6.00, 'Asia/Rangoon' => 6.30, 'Asia/Krasnoyarsk' => 7.00, 'Asia/Brunei' => 8.00, 'Asia/Seoul' => 9.00, 'Australia/Darwin' => 9.30, 'Australia/Canberra' => 10.00, 'Asia/Magadan' => 11.00, 'Pacific/Fiji' => 12.00, 'Pacific/Tongatapu' => 13.00);
$index = array_keys($zonelist, $_REQUEST['offset']);
$_SESSION['timezone'] = $index[0];
}
}
date_default_timezone_set($_SESSION['timezone']);
//rest of your code goes here
?>