2010-05-05 25 views
80

En una aplicación JS, recibo la marca de tiempo (por ejemplo, 1270544790922) del servidor (Ajax).Cómo ignorar la zona horaria del usuario y forzar la fecha() utiliza la zona horaria específica

Basándose en la marca de tiempo que se crea Date objeto usando:

var _date = new Date(); 
_date.setTime(1270544790922); 

Ahora, _date marca de tiempo decodificado en la zona horaria actual configuración regional del usuario. No quiero eso.

Deseo _date convertir esta marca de tiempo a la hora actual en la ciudad de Helsinki en Europa (sin tener en cuenta la zona horaria actual del usuario).

¿Cómo puedo hacer eso?

+0

Sé que el desplazamiento de zona horaria en Helsinki es +2 en invierno y +3 en horario de verano. ¿Pero quién sabe cuándo es DST? Solo algunos mecanismos de configuración regional que no están disponibles en JS – warpech

+0

Es posible, pero no se usan métodos nativos de Javascript, porque javascript no tiene un método para determinar el historial de transición de otra zona horaria que la zona horaria actual del sistema del usuario (y es por cierto navegador dependiente al menos cuando vamos a las fechas de los 80). Pero de esta manera es posible: http://stackoverflow.com/a/12814213/1691517 y creo que mi respuesta le da el resultado correcto. –

+0

http://www.w3schools.com/jsref/jsref_setutcmilliseconds.asp – radpin

Respuesta

56

A El valor subyacente del objeto de fecha está realmente en UTC. Para probar esto, observe que si escribe new Date(0), verá algo como: Wed Dec 31 1969 16:00:00 GMT-0800 (PST). 0 se trata como 0 en GMT, pero el método .toString() muestra la hora local.

Nota importante, UTC significa Universal código de tiempo. La hora actual en este momento en 2 lugares diferentes es la misma UTC, pero la salida se puede formatear de manera diferente.

Lo que necesitamos es un poco de formato

var _date = new Date(1270544790922); 
// outputs > "Tue Apr 06 2010 02:06:30 GMT-0700 (PDT)", for me 
_date.toLocaleString('fi-FI', { timeZone: 'Europe/Helsinki' }); 
// outputs > "6.4.2010 klo 12.06.30" 
_date.toLocaleString('en-US', { timeZone: 'Europe/Helsinki' }); 
// outputs > "4/6/2010, 12:06:30 PM" 

Esto funciona, pero .... realmente no se puede utilizar cualquiera de los otros métodos de fecha para sus propósitos ya que describen la zona horaria del usuario. Lo que quiere es un objeto de fecha que esté relacionado con la zona horaria de Helsinki. Sus opciones en este momento son usar una biblioteca de terceros (lo recomiendo), o modificar el objeto de fecha para que pueda usar la mayoría de sus métodos.

Opción 1 - una tercera parte como zona horaria momento-

moment(1270544790922).tz('Europe/Helsinki').format('YYYY-MM-DD HH:mm:ss') 
// outputs > 2010-04-06 12:06:30 
moment(1270544790922).tz('Europe/Helsinki').hour() 
// outputs > 12 

Esto se ve mucho más elegante que lo que vamos a hacer a continuación.

Opción 2 - Hack el objeto de fecha

var currentHelsinkiHoursOffset = 2; // sometimes it is 3 
var date = new Date(1270544790922); 
var helsenkiOffset = currentHelsinkiHoursOffset*60*60000; 
var userOffset = _date.getTimezoneOffset()*60000; // [min*60000 = ms] 
var helsenkiTime = new Date(date.getTime()+ helsenkiOffset + userOffset); 
// Outputs > Tue Apr 06 2010 12:06:30 GMT-0700 (PDT) 

Todavía piensa que es GMT-0700 (PDT), pero si no miras demasiado duro que puede ser capaz de confundir eso con una el objeto de fecha que es útil para sus propósitos.

Omití convenientemente una parte. Necesita poder definir currentHelsinkiOffset. Si puede usar date.getTimezoneOffset() en el lado del servidor, o simplemente usar algunas sentencias if para describir cuándo ocurrirán los cambios en la zona horaria, eso debería resolver su problema.

Conclusión - Creo que especialmente para este fin debe utilizar una biblioteca de fechas como moment-timezone.

+0

también ... se puede hacer una tarea similar, simplemente usando el desplazamiento gmt desde una ubicación. No necesita javascript en absoluto en ese caso. – Parris

+0

lo siento, pero no, me refiero exactamente a lo contrario :) He editado la pregunta, tal vez está más claro ahora – warpech

+0

Ok, he cambiado mi solución. Creo que esto es lo que estás buscando. – Parris

15

Para dar cuenta de milisegundos y la zona horaria del usuario, utilice el siguiente:

var _userOffset = _date.getTimezoneOffset()*60*1000; // user's offset time 
var _centralOffset = 6*60*60*1000; // 6 for central time - use whatever you need 
_date = new Date(_date.getTime() - _userOffset + _centralOffset); // redefine variable 
+0

Para reemplazar el uso de un desplazamiento fijo para central, utilicé el concepto de crear una fecha usando CST con un tiempo fijo de 00:00, luego obtuve las horas de viaje de esa fecha. – grantwparks

+0

+1 Esto funcionó para mí. No estoy seguro de cómo 'la' respuesta puede funcionar sin tratar en milisegundos. –

+2

@Ehren no debería agregar el timezoneOffset para obtener gmt y luego restar el desplazamiento central? – coder

13

Tengo la sospecha de que el Answer no da el resultado correcto.En la pregunta, el asker quiere convertir la marca de tiempo del servidor a la hora actual en Hellsinki sin tener en cuenta la zona horaria actual del usuario.

Es el hecho de que la zona horaria del usuario puede ser lo que alguna vez lo que no podemos confiar a ella.

Si, por ejemplo. marca de tiempo es 1270544790922 y tenemos una función:

var _date = new Date(); 
_date.setTime(1270544790922); 
var _helsenkiOffset = 2*60*60;//maybe 3 
var _userOffset = _date.getTimezoneOffset()*60*60; 
var _helsenkiTime = new Date(_date.getTime()+_helsenkiOffset+_userOffset); 

Cuando un neoyorquino visita la página, alerta (_helsenkiTime) impresiones:

Tue Apr 06 2010 05:21:02 GMT-0400 (EDT) 

Y cuando un Finlander visita la página, alerta prints (_helsenkiTime) :

Tue Apr 06 2010 11:55:50 GMT+0300 (EEST) 

Así que la función es correcta sólo si el visitante página tiene el objetivo de zona horaria (Europa/Helsinki) en su computadora, pero falla en casi cualquier otra parte del mundo. Y debido a que la fecha y hora del servidor suele ser marca de tiempo UNIX, que es, por definición, en UTC, el número de segundos desde el Epoch Unix (1 enero 1970 00:00:00 GMT), no podemos determinar el horario de verano o no el horario de verano de marca de tiempo.

Así que la solución es hacer caso omiso de la zona horaria actual del usuario y poner en práctica alguna forma de calcular UTC compensado si la fecha está en el horario de verano o no. Javascript no tiene un método nativo para determinar el historial de transición de DST de otra zona horaria que la zona horaria actual del usuario. Podemos lograr esto de la manera más simple usando el script del lado del servidor, porque tenemos acceso fácil a la base de datos de la zona horaria del servidor con todo el historial de transición de todas las zonas horarias.

Pero si no tiene acceso a la base de datos de zona horaria del servidor (o de cualquier otro servidor) Y la marca de tiempo está en UTC, puede obtener la funcionalidad similar codificando las reglas de DST en Javascript.

Para cubrir las fechas en los años 1998 - 2099 en Europa/Helsinki se puede utilizar la siguiente función (jsfiddled):

function timestampToHellsinki(server_timestamp) { 
    function pad(num) { 
     num = num.toString(); 
     if (num.length == 1) return "0" + num; 
     return num; 
    } 

    var _date = new Date(); 
    _date.setTime(server_timestamp); 

    var _year = _date.getUTCFullYear(); 

    // Return false, if DST rules have been different than nowadays: 
    if (_year<=1998 && _year>2099) return false; 

    // Calculate DST start day, it is the last sunday of March 
    var start_day = (31 - ((((5 * _year)/4) + 4) % 7)); 
    var SUMMER_start = new Date(Date.UTC(_year, 2, start_day, 1, 0, 0)); 

    // Calculate DST end day, it is the last sunday of October 
    var end_day = (31 - ((((5 * _year)/4) + 1) % 7)) 
    var SUMMER_end = new Date(Date.UTC(_year, 9, end_day, 1, 0, 0)); 

    // Check if the time is between SUMMER_start and SUMMER_end 
    // If the time is in summer, the offset is 2 hours 
    // else offset is 3 hours 
    var hellsinkiOffset = 2 * 60 * 60 * 1000; 
    if (_date > SUMMER_start && _date < SUMMER_end) hellsinkiOffset = 
    3 * 60 * 60 * 1000; 

    // Add server timestamp to midnight January 1, 1970 
    // Add Hellsinki offset to that 
    _date.setTime(server_timestamp + hellsinkiOffset); 
    var hellsinkiTime = pad(_date.getUTCDate()) + "." + 
    pad(_date.getUTCMonth()) + "." + _date.getUTCFullYear() + 
    " " + pad(_date.getUTCHours()) + ":" + 
    pad(_date.getUTCMinutes()) + ":" + pad(_date.getUTCSeconds()); 

    return hellsinkiTime; 
} 

Ejemplos de uso:

var server_timestamp = 1270544790922; 
document.getElementById("time").innerHTML = "The timestamp " + 
server_timestamp + " is in Hellsinki " + 
timestampToHellsinki(server_timestamp); 

server_timestamp = 1349841923 * 1000; 
document.getElementById("time").innerHTML += "<br><br>The timestamp " + 
server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp); 

var now = new Date(); 
server_timestamp = now.getTime(); 
document.getElementById("time").innerHTML += "<br><br>The timestamp is now " + 
server_timestamp + " and the current local time in Hellsinki is " + 
timestampToHellsinki(server_timestamp);​ 

Y esta impresión la siguiente independientemente del usuario zona horaria:

The timestamp 1270544790922 is in Hellsinki 06.03.2010 12:06:30 

The timestamp 1349841923000 is in Hellsinki 10.09.2012 07:05:23 

The timestamp is now 1349853751034 and the current local time in Hellsinki is 10.09.2012 10:22:31 

Por supuesto, si puede devolver ti mestamp en una forma en que el desplazamiento (DST o no DST) ya está agregado a la marca de tiempo en el servidor, no tiene que calcularlo en el lado del cliente y puede simplificar mucho la función. PERO recuerda NO usar timezoneOffset(), porque entonces tienes que tratar con la zona horaria del usuario y este no es el comportamiento deseado.

+2

nb. Helsinki solo tiene una 'l'. Este error realmente desvirtúa esta respuesta. –

+0

@BenMcIntyre Es una pequeña broma. O se supone que es tal. :) –

0

Usted podría utilizar setUTCMilliseconds()

var _date = new Date(); 
_date.setUTCMilliseconds(1270544790922); 
+0

Esta respuesta es incorrecta. setUTCMilliseconds agrega la cantidad de milisegundos especificados a la fecha. – Tibor

+0

@Tibor: desde MozDev: el método 'setUTCMilliseconds()' establece los milisegundos para una fecha especificada de acuerdo con la hora universal. [...] Si un parámetro que usted especifica está fuera del rango esperado, 'setUTCMilliseconds()' intenta actualizar la información de fecha en el objeto Date en consecuencia. En otras palabras, crea un objeto 'Fecha' que tiene la marca de tiempo de Unix dada, en UTC. – jimasun

+0

Desde w3schools: el método setUTCMilliseconds() establece los milisegundos (de 0 a 999), según la hora universal. Pruebe la respuesta anterior y compruébelo usted mismo. – Tibor

10

Sólo otro enfoque

function parseTimestamp(timestampStr) { 
 
    return new Date(new Date(timestampStr).getTime() + (new Date().getTimezoneOffset() * 60 * 1000)); 
 
}; 
 

 
//Sun Jan 01 2017 12:00:00 
 
var timestamp = 1483272000000; 
 
date = parseTimestamp(timestamp); 
 
document.write(date);

Salud!

1

Suponiendo que usted consigue la marca de tiempo en tiempo Helsinki, me gustaría crear un objeto Date establecido en la medianoche del 1 de enero de 1970 UTC (para tener en cuenta los ajustes de zona horaria local del navegador). A continuación, solo añada la cantidad necesaria de milisegundos.

var _date \t = new Date(Date.UTC(1970, 0, 1, 0, 0, 0, 0)); 
 
_date.setUTCMilliseconds(1270544790922); 
 

 
alert(_date); //date shown shifted corresponding to local time settings 
 
alert(_date.getUTCFullYear()); //the UTC year value 
 
alert(_date.getUTCMonth());  //the UTC month value 
 
alert(_date.getUTCDate());  //the UTC day of month value 
 
alert(_date.getUTCHours());  //the UTC hour value 
 
alert(_date.getUTCMinutes());  //the UTC minutes value

Cuidado después, preguntar siempre los valores UTC del objeto de fecha. De esta forma, los usuarios verán los mismos valores de fecha independientemente de la configuración local. De lo contrario, los valores de fecha se desplazarán según la configuración de hora local.

Cuestiones relacionadas