Determinar la zona horaria de un usuario

610

¿Existe una forma estándar para que un servidor web pueda determinar la zona horaria de un usuario dentro de una página web?

¿Quizás desde un encabezado HTTP o parte de la user-agentcadena?

Kevin Dente
fuente
66
Pregúntale al usuario. Si obtiene la zona horaria de la computadora del usuario y está configurada incorrectamente, ¿entonces qué?
Rob Williams
40
¿Entonces al usuario probablemente no le importa?
agnoster
2
¿Te refieres a stackoverflow.com/q/1091372/218196 ?
Felix Kling
2
Desafortunadamente, las respuestas a esta pregunta también permiten la creación de perfiles y geofencing de usuarios.
William Entriken
1
¿Por qué necesita saber la zona horaria del usuario?
Braiam

Respuestas:

325
-new Date().getTimezoneOffset()/60;

El método getTimezoneOffset()restará su tiempo de GMT y devolverá la cantidad de minutos. Entonces, si vives en GMT-8, te devolverá 480.

Para poner esto en horas, divida por 60. Además, observe que el letrero es lo opuesto a lo que necesita: está calculando el desplazamiento de GMT desde su zona horaria, no el desplazamiento de su zona horaria desde GMT. Para solucionar esto, simplemente multiplique por -1.

También tenga en cuenta que w3school dice:

El valor devuelto no es una constante, debido a la práctica de usar el horario de verano.

JD Isaacks
fuente
55
¿Qué pasa con los usuarios que usan teléfonos celulares que tienen navegadores sin soporte de JavaScript? Me gusta la pregunta, el usuario pregunta sobre encabezados HTTP, agente de usuario ... ¿hay alguna manera de hacer que este lado del servidor de trabajo sea lo más preciso posible?
Nischal
19
Esto no siempre funciona para el horario de verano. Obtener compensación de zona horaria hace exactamente lo que dice. Es el desplazamiento. Una ZONA de tiempo es en realidad un área geográfica. Esto no funcionará para el horario de verano, ya que no sabe en qué hemisferio vive el usuario, o si su país incluso tiene horario de verano. Por qué no usar esto en su lugar:>>> date.toTimeString() "15:46:04 GMT+1200 (New Zealand Standard Time)"
Keyo
20
Ruego diferir con Keyo. La definición de getTimezoneOffset () (de acuerdo con el estándar ECMA ecma-international.org/ecma-262/5.1/#sec-15.9.5.26 ) es "Devuelve la diferencia entre la hora local y la hora UTC en minutos". - en otras palabras, debe tener en cuenta el horario de verano. La documentación de Mozilla dice que "el horario de verano evita que este valor sea una constante incluso para un lugar determinado".
xgretsch
12
@xgretsch: Obtiene el desplazamiento actual del usuario de GMT. Eso está bien si presenta otro momento que ocurre el mismo día (a menos que la fecha actual sea una fecha de cambio, donde podría estar equivocado). Sin embargo, hay muchas zonas horarias que tienen el mismo desplazamiento de GMT, y pueden tener diferentes fechas de cambio o no usar el horario de verano.
Mike Dimmick
13
Una cosa a tener en cuenta aquí; Algunos lugares (como Terranova en Canadá) tienen zonas horarias que están apagadas por media hora, por lo que después de dividir entre 60 su respuesta puede no ser un número entero.
Jason Walton
193

La forma más popular (== ¿estándar?) De determinar la zona horaria que he visto es simplemente preguntar a los propios usuarios. Si su sitio web requiere suscripción, esto podría guardarse en los datos del perfil de los usuarios. Para los usuarios anon, las fechas se pueden mostrar como UTC o GMT o algo así.

No estoy tratando de ser un sabelotodo. Es solo que a veces algunos problemas tienen soluciones más finas fuera de cualquier contexto de programación.

Ismaeel
fuente
55
¿Qué sucede cuando un usuario está descargando un archivo .ics que debe tener una hora de inicio específica para su ubicación (por ejemplo, 9-11 a.m. en todo el país)? No deberían tener que decir cuál es su zona horaria imo.
Marcy Sutton
33
@Ishmaeel: pero los usuarios viajan internacionalmente y no deberían necesitar decir su zona horaria cada vez que inician sesión desde alguna zona horaria no nativa
Rajat Gupta
10
Esto no responde a la pregunta, lo que claramente implica que está buscando una solución tecnológica.
G-Wiz
55
@gWiz OP está pidiendo una solución estándar. Esto es bastante estándar.
Simon Bergot el
44
La mejor solución probablemente sería una combinación de preguntarle al usuario (por ejemplo, proporcionar un menú desplegable de zona horaria en la parte superior de un informe), mientras que la selección desplegable se predetermina a una zona horaria determinada por GPS cuando el usuario está en un teléfono móvil dispositivo que proporciona información de ubicación y, de lo contrario, predeterminado a UTC
Triynko
133

No hay encabezados HTTP que informarán la zona horaria de los clientes hasta ahora, aunque se ha sugerido incluirla en la especificación HTTP.

Si fuera yo, probablemente intentaría buscar la zona horaria usando JavaScript del lado del cliente y luego enviarla al servidor usando Ajax o algo así.

Mads Kristiansen
fuente
16
Curiosamente, esta es la única respuesta correcta a la pregunta, que pregunta cómo hacerlo del lado del servidor. Sospecho que la razón por la que hay otras respuestas con más votos es porque una vez que te das cuenta de que debes hacerlo del lado del cliente, terminas usando las otras respuestas. Pero, en mi humilde opinión, cualquiera que esté votando otra respuesta también debería estar votando esta.
TTT
Creo que el mejor método es usar la ubicación de geo-ip para ordenar las zonas horarias posibles y, de forma predeterminada, elegir la primera que coincida (cerca) con el desplazamiento de tiempo del agente de usuario (se requiere JavaScript). Incluso después de eso, debe proporcionar una forma de arreglar la zona horaria después de que incluso este método seleccione la incorrecta.
Mikko Rantalainen
@MikkoRantalainen tiene cuidado al usar proxies, ya que no siempre se anuncian en los encabezados.
Matthieu
@Matthieu existe una mejor respuesta hoy en día: stackoverflow.com/a/11836123/334451
Mikko Rantalainen
2
Esta es literalmente la única respuesta que realmente abordó la pregunta planteada.
lscoughlin
54

JavaScript es la forma más fácil de obtener la hora local del cliente. Sugeriría usar XMLHttpRequest para enviar la hora local, y si eso falla, recurrir a la zona horaria detectada en función de su dirección IP.

En cuanto a la geolocalización, he usado MaxMind GeoIP en varios proyectos y funciona bien, aunque no estoy seguro de si proporcionan datos de zona horaria. Es un servicio por el que paga y proporcionan actualizaciones mensuales a su base de datos. Proporcionan envoltorios en varios idiomas web.

pix0r
fuente
He votado esta respuesta porque la latitud y longitud obtenidas de bases de datos como GeoIP (que tiene una versión gratuita disponible a partir de ahora) se pueden combinar con bases de datos que convierten dicha coordenada en una zona horaria. Creo que GeoNames tiene una última base de datos de este tipo.
Peter O.
Las versiones actuales (tanto gratuitas como de pago) de las bases de datos / API MaxMind GeoIP, de hecho, proporcionan información de zona horaria (devuelve "Europa / Londres" para mi zona horaria). No recuerdo si la versión anterior de su sistema GeoIP hizo lo mismo, ¡pero funciona muy bien ahora! Los campos de MaxMind se denominan "time_zone", "time_zone_name".
Matthew Slyman
51

Primero, comprenda que la detección de zona horaria en JavaScript es imperfecta. Usted puede obtener el local de desplazamiento de zona horaria para una fecha y hora determinada utilizando getTimezoneOffseten una instancia del Dateobjeto, pero eso no es exactamente lo mismo que una completa zona horaria IANA como America/Los_Angeles.

Sin embargo, hay algunas opciones que pueden funcionar:

const tzid = Intl.DateTimeFormat().resolvedOptions().timeZone;
console.log(tzid);

El resultado es una cadena que contiene la configuración de zona horaria IANA de la computadora donde se ejecuta el código.

Los entornos compatibles se enumeran en la tabla de compatibilidad internacional . Expande la DateTimeFormatsección y mira la característica nombrada resolvedOptions().timeZone defaults to the host environment.

  • Algunas bibliotecas, como Luxon, usan esta API para determinar la zona horaria a través de funciones como luxon.Settings.defaultZoneName.

    • Si necesita admitir un conjunto más amplio de entornos, como navegadores web más antiguos, puede usar una biblioteca para hacer una suposición informada sobre la zona horaria. Funcionan probando primero la IntlAPI si está disponible, y cuando no está disponible, interrogan la getTimezoneOffsetfunción del Dateobjeto, durante varios puntos diferentes en el tiempo, utilizando los resultados para elegir una zona horaria adecuada de un conjunto de datos interno.

    Tanto jsTimezoneDetect como moment-timezone tienen esta funcionalidad.

    // using jsTimeZoneDetect
    var tzid = jstz.determine().name();
    
    // using moment-timezone
    var tzid = moment.tz.guess();

    En ambos casos, el resultado solo puede considerarse una suposición. La suposición puede ser correcta en muchos casos, pero no en todos.

    Además, estas bibliotecas deben actualizarse periódicamente para contrarrestar el hecho de que muchas implementaciones de JavaScript antiguas solo conocen la regla de horario de verano actual para su zona horaria local. Más detalles sobre eso aquí.

En última instancia, un mejor enfoque es pedirle a su usuario su zona horaria. Proporcione una configuración que puedan cambiar. Puedes usar una de las opciones anteriores para elegir una configuración predeterminada , pero no hagas imposible desviarte de eso en tu aplicación.

También existe el enfoque completamente diferente de no depender en absoluto de la configuración de zona horaria de la computadora del usuario. En cambio, si puede reunir las coordenadas de latitud y longitud, puede resolverlas en una zona horaria utilizando uno de estos métodos . Esto funciona bien en dispositivos móviles.

Matt Johnson-Pint
fuente
El uso de la ubicación geográfica del usuario (es decir, su ubicación) para deducir la zona horaria también es defectuoso. Es posible que los usuarios deseen usar una zona horaria específica en su dispositivo que no sea la zona horaria local, incluso aunque pueda mostrar la misma hora (o no). Por ejemplo, los viajeros con frecuencia dejan sus dispositivos con la zona horaria establecida en su localidad habitual y no esperan ver que las fechas y horas usen un desplazamiento diferente sin que se les avise. Podría estar hablando por experiencia personal aquí ... ;-)
RobG
No puedo decir si me estás trolleando, Rob. ;) Pero ninguno de estos enfoques utiliza su configuración regional, sino la configuración del dispositivo, por lo que se alinea con su punto. (Solo el enfoque alternativo mencionado en el último párrafo usaría la ubicación actual.)
Matt Johnson-Pint
Repican en una nota con la terminología: "locale" es enfáticamente no la ubicación geográfica del usuario. "Configuración regional" es un grupo de configuraciones como idioma, formato de número, calendario, etc. Por ejemplo, la configuración regional de_DE especifica alemán como idioma predeterminado, el euro como moneda predeterminada, comas como separador decimal, puntos como separador de miles y gregoriano como el calendario Ver developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
azernik
49

Aquí hay una solución robusta de JavaScript para determinar la zona horaria en la que se encuentra el navegador.

>>> var timezone = jstz.determine();
>>> timezone.name(); 
"Europe/London"

https://bitbucket.org/pellepim/jstimezonedetect

Apéndice 1: ahora este proyecto se encuentra en GitHub: https://github.com/pellepim/jstimezonedetect

Adán
fuente
14
Se desaconsejan las respuestas de solo enlace, porque si el enlace desaparece, la respuesta deja de ser útil; y porque sin seguir el enlace, los lectores no saben si da una buena respuesta. En este caso, podría aclarar que se trata de una biblioteca de terceros que adopta un enfoque de identificación basado en una base de datos, y tal vez explicar algunos de los principios de su funcionamiento.
IMSoP
1
¡Esta! Este es el camino a seguir. Biblioteca simple, maneja DST correctamente. Otras respuestas están llenas de WTF y muchas no hacen DST.
Dirbaio
1
Esta biblioteca es muy inteligente. Funciona consultando el desplazamiento actual a UTC, luego ajustando el tiempo del objeto Fecha de JavaScript agregando o restando segundos hasta que cambie el desplazamiento a UTC. Usando este método, esta biblioteca descubre muchos cambios DST suficientes para identificar de forma exclusiva la zona horaria. Creo que la biblioteca podría tener un rendimiento aún mejor si hiciera una búsqueda binaria en lugar de una búsqueda lineal. El valor de retorno es una clave de información de zona IANA (también conocida como la base de datos de zonas horarias de Olson).
Mikko Rantalainen
3
Esta biblioteca ya no es necesaria. Los navegadores modernos admiten la API Intl, que devuelve la cadena de zona horaria de IANA. Mira esta respuesta .
Dan Dascalescu
42

Aquí hay una manera más completa.

  1. Obtenga el desplazamiento de la zona horaria para el usuario
  2. Pruebe algunos días en los límites de horario de verano para determinar si están en una zona que utiliza el horario de verano.

Un extracto está a continuación:

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;
}

Obtener TZ y DST de JS (a través de Way Back Machine)

Joseph Lust
fuente
¡Esto funcionó para mí! Lea los comentarios debajo de la publicación del blog para ver un par de actualizaciones del código.
arlomedia
Esto solo devolverá el desplazamiento estándar para la zona horaria, como +02: 00. No le dará suficiente información para determinar la zona horaria del usuario, como Africa/Johannesburgo Europe/Istanbul. Vea el wiki de etiqueta de zona horaria .
Matt Johnson-Pint
32

Usando el enfoque de Unkwntech, escribí una función usando jQuery y PHP. ¡Esto está probado y funciona!

En la página PHP donde desea tener la zona horaria como variable, tenga este fragmento de código en algún lugar cerca de la parte superior de la página:

<?php
    session_start();
    $timezone = $_SESSION['time'];
?>

Esto leerá la variable de sesión "tiempo", que ahora estamos a punto de crear.

En la misma página, en <head>, primero debe incluir jQuery:

<script type="text/javascript" src="http://code.jquery.com/jquery-latest.min.js"></script>

También en <head>, debajo de jQuery, pegue esto:

<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>

Puede que hayas notado o no, pero debes cambiar la URL a tu dominio real.

Una última cosa. Probablemente se esté preguntando cuál es el heck timezone.php. Bueno, es simplemente esto: (cree un nuevo archivo llamado timezone.php y apúntelo con la URL anterior)

<?php
    session_start();
    $_SESSION['time'] = $_GET['time'];
?>

Si esto funciona correctamente, primero cargará la página, ejecutará JavaScript y volverá a cargar la página. ¡Entonces podrá leer la variable $ timezone y usarla a su gusto! Devuelve el desplazamiento de zona horaria UTC / GMT actual (GMT -7) o cualquier zona horaria en la que se encuentre.

Westy92
fuente
Me gusta esto, pero podría tener algo que verifique el $ _SESSION ['time'] actual y solo obtenga el javascript para recargar si es diferente
Christopher Chase,
1
Probablemente sea más fácil usar una Cookie que una Sesión para transportar esto, ya que bloquear y deserializar la sesión PHP puede causar ralentizaciones en su aplicación. Para obtener la máxima eficacia, puede copiar el valor en la sesión y eliminar la cookie para que no se envíe en solicitudes posteriores.
IMSoP
25

Para enviar el desplazamiento de zona horaria como un encabezado HTTP en solicitudes AJAX con jQuery

$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        xhr.setRequestHeader("X-TZ-Offset", -new Date().getTimezoneOffset()/60);
    }
});

También puede hacer algo similar para obtener el nombre real de zona horaria mediante el uso moment.tz.guess();de http://momentjs.com/timezone/docs/#/using-timezones/guessing-user-timezone/

philfreo
fuente
1
Esto solo devuelve el desplazamiento de la zona horaria actual , no la zona horaria . Vea el wiki de etiqueta de zona horaria .
Matt Johnson-Pint
Editado para incluir información sobre cómo hacer lo mismo para el nombre de la zona horaria.
philfreo
24

Todavía no he visto una respuesta detallada aquí que obtenga la zona horaria. No debería necesitar geocodificar por dirección IP o usar PHP (lol) o adivinar incorrectamente desde un desplazamiento.

En primer lugar, una zona horaria no es solo un desplazamiento de GMT. Es un área de tierra en la que las normas de tiempo se establecen según los estándares locales. Algunos países tienen horario de verano y activarán el horario de verano en diferentes momentos. Por lo general, es importante obtener la zona real, no solo el desplazamiento actual.

Si tiene la intención de almacenar esta zona horaria, por ejemplo, en las preferencias del usuario, desea la zona y no solo el desplazamiento. Para las conversiones en tiempo real no importará mucho.

Ahora, para obtener la zona horaria con JavaScript, puede usar esto:

>> new Date().toTimeString();
"15:46:04 GMT+1200 (New Zealand Standard Time)"
//Use some regular expression to extract the time.

Sin embargo, me resultó más fácil usar este complemento robusto que devuelve la zona horaria formateada de Olsen:

https://github.com/scottwater/jquery.detect_timezone

Keyo
fuente
22

Con la datefunción PHP obtendrá la fecha y hora del servidor en el que se encuentra el sitio. La única forma de obtener tiempo para el usuario es usar JavaScript.

Pero le sugiero que, si su sitio requiere registro, la mejor manera es pedirle al usuario que se registre como un campo obligatorio. Puede enumerar varias zonas horarias en la página de registro y guardarlas en la base de datos. Después de esto, si el usuario inicia sesión en el sitio, puede establecer la zona horaria predeterminada para esa sesión según la zona horaria seleccionada por los usuarios.

Puede establecer cualquier zona horaria específica utilizando la función PHP date_default_timezone_set. Esto establece la zona horaria especificada para los usuarios.

Básicamente, la zona horaria de los usuarios va al lado del cliente, por lo que debemos usar JavaScript para esto.

A continuación se muestra el script para obtener la zona horaria de los usuarios utilizando PHP y 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();
?>

Pero según mi punto de vista, es mejor preguntar a los usuarios si el registro es obligatorio en su proyecto.

Sanjay Khatri
fuente
22

No use la dirección IP para determinar definitivamente la ubicación (y, por lo tanto, la zona horaria), ya que con NAT, proxies (cada vez más populares) y VPN, las direcciones IP no necesariamente reflejan de manera realista la ubicación real del usuario, sino la ubicación en la que los servidores que implementan esos protocolos residen.

Similar a cómo los códigos de área de EE. UU. Ya no son útiles para localizar a un usuario de teléfono, dada la popularidad de la portabilidad numérica.

La dirección IP y otras técnicas que se muestran arriba son útiles para sugerir un valor predeterminado que el usuario puede ajustar / corregir.

Jaime G
fuente
21

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;
}

Simplemente proporcione sus tiempos en formato de marca de tiempo Unix a esta función; JavaScript ya conoce la zona horaria del usuario.

Me gusta esto:

PHP:

echo '<script type="text/javascript">
var eltimio = maketimus('.$unix_timestamp_ofshiz.');
document.write(eltimio);
</script><noscript>pls enable javascript</noscript>';

Esto siempre mostrará las horas correctamente en función de la zona horaria que la persona ha configurado en el reloj de su computadora. No hay necesidad de pedirle nada a nadie y guardarlo en lugares, ¡gracias a Dios!

Envis
fuente
$ unix_timestamp_ofshiz? Aquí falta algo y no funciona del todo, aunque parezca que podría ser una buena respuesta.
20

Fácil, solo use la getTimezoneOffsetfunción JavaScript de esta manera:

-new Date().getTimezoneOffset()/60;
JoeyFur62
fuente
1
Esta es una función Javascript, no una función PHP.
cincodenada
Además, solo devuelve el desplazamiento de la zona horaria actual , no la zona horaria . Vea el wiki de etiqueta de zona horaria .
Matt Johnson-Pint
3
Esta es solo una copia de la respuesta aceptada, por qué incluso vota por ella.
Rambatino
19

La magia todo parece estar en

visitortime.getTimezoneOffset()

Eso es genial, no sabía sobre eso. ¿Funciona en Internet Explorer, etc.? Desde allí, debería poder usar JavaScript para Ajax, configurar cookies, lo que sea. Probablemente iría yo mismo por la ruta de las galletas.

Sin embargo, deberá permitir que el usuario lo cambie. Intentamos usar la geolocalización (a través de maxmind) para hacer esto hace un tiempo, y fue un error razonablemente frecuente, lo suficiente como para que no valga la pena hacerlo, así que solo dejamos que el usuario lo configure en su perfil y muestre un aviso a los usuarios que No he configurado el suyo todavía.

Orion Edwards
fuente
15

Aquí hay un artículo (con código fuente) que explica cómo determinar y usar el tiempo localizado en una aplicación ASP.NET (VB.NET, C #):

Ya es hora

En resumen, el enfoque descrito se basa en la getTimezoneOffsetfunción de JavaScript , que devuelve el valor guardado en la cookie de sesión y utilizado por el código subyacente para ajustar los valores de hora entre GMT y la hora local. Lo bueno es que el usuario no necesita especificar la zona horaria (el código lo hace automáticamente). Hay más involucrados (es por eso que hago un enlace al artículo), pero el código proporcionado hace que sea realmente fácil de usar. Sospecho que puede convertir la lógica a PHP y otros lenguajes (siempre que comprenda ASP.NET).

Alek Davis
fuente
1
El enlace está muerto. Creo que este es el enlace alternativo: devproconnections.com/article/aspnet2/it-s-about-time-122778
Gan
1
El artículo también está disponible en formato PDF aquí: app.box.com/shared/bfvvmidtyg
Ivaylo Slavov
El método de convertir la hora del servidor UTC a la hora del cliente local que se describe en este artículo es incorrecto. El uso de la compensación actual del cliente para ajustar las horas UTC en el servidor dará como resultado tiempos "locales" incorrectos durante la mitad del año para las configuraciones regionales del cliente que observen el horario de verano. Considere este escenario: un cliente en el Reino Unido el 14 de enero de 2013 (GMT + 0000 Hora estándar) establece una fecha y hora del 21 de agosto de 2015 a las 14:00 (GMT + 0100 Hora de verano). Esto se normaliza en el servidor al 21 de agosto de 2015 a las 13:00 UTC. El día que esto ocurre, el desplazamiento del cliente es 0, por lo que el tiempo enviado de vuelta al cliente será el 21 de agosto de 2015 a las 13:00.
Stephen Blair el
Punto válido, pero no dije que fuera una solución a prueba de balas. Si necesita implementar una solución realmente urgente, digamos una aplicación de reserva de boletos de tren, entonces necesita encontrar una solución más completa (y compleja). Sin embargo, para muchas aplicaciones esto no sería un problema. Porque en muchos casos queremos localizar los valores GMT para la sesión actual. Ahora, si tiene una aplicación que necesita guardar una marca de tiempo para algunos, incluso en el futuro, y no puede tolerar DTS, entonces una forma adecuada sería presentar una opción para ahorrar tiempo directamente en GMT. Si conoce una mejor opción, por favor comparta.
Alek Davis
14

Si utiliza OpenID para la autenticación, la Extensión de registro simple resolvería el problema para los usuarios autenticados (deberá convertir de tz a numérico).

Otra opción sería inferir la zona horaria de la preferencia de país del agente de usuario. Este es un método algo burdo (no funcionará para Estados Unidos), pero es una buena aproximación.

Dmitry Shechtman
fuente
13

Es simple con JavaScript y PHP:

A pesar de que el usuario puede meterse con su reloj interno y / o zona horaria, la mejor manera que encontré hasta ahora, para obtener el desplazamiento, sigue siendo new Date().getTimezoneOffset();. No es invasivo, no produce dolor de cabeza y elimina la necesidad de depender de terceros.

Digamos que tengo una tabla, usersque contiene un campo date_created int(13), para almacenar marcas de tiempo de Unix;

Asumiendo un cliente creates a new account, los datos son recibidos por post, y necesito insert/updatela date_created columnmarca de tiempo Unix del cliente, no la del servidor.

Dado que el timezoneOffset es necesario en el momento de la inserción / actualización, se pasa como un elemento adicional $ _POST cuando el cliente envía el formulario, eliminando así la necesidad de almacenarlo en sesiones y / o cookies, y tampoco afecta al servidor adicional.

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;

Digamos que el servidor recibe tzocomo $_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);

Insertar / actualizar date_created=$user_timestamp.

Al recuperar date_created, puede convertir la marca de tiempo de esta manera:

$date_created = // Get from the database
$created = date("F j, Y, g:i a",$date_created); // Return it to the user or whatever

Ahora, este ejemplo puede ajustarse a las necesidades de uno, cuando se trata de insertar una firstmarca de tiempo ... Cuando se trata de una marca de tiempo o tabla adicional, puede considerar insertar el valor tzo en la tabla de usuarios para referencia futura, o configurarlo como sesión o como cookie.

PD PERO qué pasa si el usuario viaja y cambia de zona horaria. Inicia sesión en GMT + 4, viaja rápido a GMT-1 y vuelve a iniciar sesión. El último inicio de sesión sería en el futuro.

Creo ... pensamos demasiado.

hombre
fuente
13

Puede hacerlo en el cliente con zona horaria y enviar el valor al servidor; uso de muestra:

> moment.tz.guess()
"America/Asuncion"
Tomás Tomecek
fuente
55
El nombre de la función dice todo sobre su precisión ;-)
Legends
Hoy en día, moment.js ya no lo recomiendo. Hay alternativas mucho más pequeñas actualmente ( dayjs , date-fns ). El momento es enorme .
Dan Dascalescu
11

Obtener un nombre válido de zona horaria de la base de datos TZ en PHP es un proceso de dos pasos:

  1. Con JavaScript, obtenga el desplazamiento de la zona horaria en minutos getTimezoneOffset. Este desplazamiento será positivo si la zona horaria local está detrás de UTC y negativo si está adelante. Por lo tanto, debe agregar un signo opuesto al desplazamiento.

    var timezone_offset_minutes = new Date().getTimezoneOffset();
    timezone_offset_minutes = timezone_offset_minutes == 0 ? 0 : -timezone_offset_minutes;

    Pase este desplazamiento a PHP.

  2. En PHP, convierta este desplazamiento en un nombre de zona horaria válido con la función 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>

He escrito una publicación de blog sobre él: Cómo detectar la zona horaria del usuario en PHP . También contiene una demostración.

Ángulo útil
fuente
1
Creo que un proceso más simple es llamar Intl.DateTimeFormat().resolvedOptions().timeZoney enviarlo al servidor web. Ref: stackoverflow.com/questions/9772955/…
Michael Tsang
9

Una forma sencilla de hacerlo es mediante el uso de:

new Date().getTimezoneOffset();
Naeem Ul Wahhab
fuente
8
¿Por qué volvió a publicar una respuesta idéntica (por John Isaacks) de hace 2 años: stackoverflow.com/a/1809974/836407 ?
Chown
2
Además, solo devuelve el desplazamiento de la zona horaria actual , no la zona horaria . Vea el wiki de etiqueta de zona horaria .
Matt Johnson-Pint
8

Una opción posible es usar el Datecampo de encabezado, que se define en RFC 7231 y se supone que incluye la zona horaria. Por supuesto, no se garantiza que el valor sea realmente la zona horaria del cliente, pero puede ser un punto de partida conveniente.

Berislav Lopac
fuente
1
Desafortunadamente, ese encabezado parece estar diseñado principalmente para respuestas, no para solicitudes: "Un agente de usuario PUEDE enviar un campo de encabezado de fecha en una solicitud, aunque generalmente no lo hará a menos que se cree que transmite información útil al servidor". Acabo de comprobar y Firefox no lo envía.
IMSoP
8

Así es como lo hago. Esto establecerá la zona horaria predeterminada de PHP en la zona horaria local del usuario. Simplemente pegue lo siguiente en la parte superior de todas sus páginas:

<?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
?>
Dane Iracleous
fuente
1
Esto no tiene en cuenta los ajustes de "horario de verano": un usuario en Dublín coincidiría con su 'Europa / Dublín' en invierno, pero 'Europa / Belgrado' en verano. Si va a utilizar el desplazamiento actual, todo lo que razonablemente puede suponer es ese desplazamiento, no un identificador geográfico.
IMSoP
8

Prueba este código PHP:

<?php
    $ip = $_SERVER['REMOTE_ADDR'];
    $json = file_get_contents("http://api.easyjquery.com/ips/?ip=" . $ip . "&full=true");
    $json = json_decode($json,true);
    $timezone = $json['LocalTimeZone'];
?>
pckabeer
fuente