Como ignorar o fuso horário do usuário e forçar Date () usar fuso horário específico

Em um aplicativo JS, recebo timestamp (eq. 1270544790922 ) do servidor (Ajax).

Baseando nesse timestamp eu crio o object Date usando:

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

Agora, _date decodificador de data e hora no fuso horário local do usuário atual. Eu não quero isso.

Gostaria que a date convertesse esse timestamp para a hora atual na cidade de Helsinque na Europa (desconsiderando o fuso horário atual do usuário).

Como eu posso fazer isso?

O valor subjacente de um object Date está realmente em UTC. Para provar isso, observe que, se você digitar new Date(0) verá algo como: Wed Dec 31 1969 16:00:00 GMT-0800 (PST) . 0 é tratado como 0 em GMT, mas o método .toString() mostra a hora local.

Nota grande, UTC significa o código de tempo Universal . A hora atual em dois locais diferentes é a mesma UTC, mas a saída pode ser formatada de forma diferente.

O que precisamos aqui é alguma formatação

 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" 

Isso funciona, mas … você não pode usar nenhum dos outros methods de data para seus propósitos, pois eles descrevem o fuso horário do usuário. O que você quer é um object de data relacionado ao fuso horário de Helsinque. Suas opções neste momento são usar alguma biblioteca de terceiros (eu recomendo isso), ou hack-up o object de data para que você possa usar a maioria dos seus methods.

Opção 1 – uma terceira parte como momento-fuso horário

 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 

Isso parece muito mais elegante do que o que vamos fazer em seguida.

Opção 2 – hackear o object de data

 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) 

Ainda acha que é GMT-0700 (PDT), mas se você não olhar muito, pode ser capaz de confundir isso com um object de data útil para seus propósitos.

Eu convenientemente pulei uma parte. Você precisa ser capaz de definir currentHelsinkiOffset . Se você puder usar date.getTimezoneOffset() no lado do servidor, ou apenas usar algumas instruções if para descrever quando as mudanças de fuso horário ocorrerão, isso deve resolver seu problema.

Conclusão – Eu acho que, especialmente para este propósito, você deve usar uma biblioteca de datas como o fuso horário do momento .

Para contabilizar milissegundos e o fuso horário do usuário, use o seguinte:

 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 

Eu tenho uma suspeita de que a resposta não dá o resultado correto. Na questão, o consulente deseja converter o timestamp do servidor para a hora atual no Hellsinki, desconsiderando o fuso horário atual do usuário.

É o fato de que o fuso horário do usuário pode ser o que nunca, então não podemos confiar nele.

Se ex. timestamp é 1270544790922 e nós temos uma function:

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

Quando um nova-iorquino visita a página, o alerta (_helsenkiTime) imprime:

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

E quando um Finlander visita a página, o alerta (_helsenkiTime) imprime:

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

Portanto, a function está correta somente se o visitante da página tiver o fuso horário alvo (Europa / Helsinki) em seu computador, mas falhar em quase todas as outras partes do mundo. E como o registro de data e hora do servidor geralmente é carimbo de data / hora do UNIX, que é por definição em UTC, não podemos determinar o horário de verão ou não o horário de verão.

Portanto, a solução é DESCARTAR o fuso horário atual do usuário e implementar alguma maneira de calcular o deslocamento UTC, quer a data esteja em DST ou não. O Javascript não possui um método nativo para determinar o histórico de transição de horário de verão de outro fuso horário do que o fuso horário atual do usuário. Podemos conseguir isso simplesmente usando script do lado do servidor, porque temos access fácil ao database de fuso horário do servidor com todo o histórico de transição de todos os fusos horários.

Mas se você não tiver access ao database de fuso horário do servidor (ou de qualquer outro servidor) E o registro de data e hora estiver em UTC, você poderá obter a funcionalidade semelhante codificando as regras de DST em Javascript.

Para cobrir datas nos anos de 1998 a 2099 na Europa / Helsinque, você pode usar a seguinte function ( 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; } 

Exemplos 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 += "

The timestamp " + server_timestamp + " is in Hellsinki " + timestampToHellsinki(server_timestamp); var now = new Date(); server_timestamp = now.getTime(); document.getElementById("time").innerHTML += "

The timestamp is now " + server_timestamp + " and the current local time in Hellsinki is " + timestampToHellsinki(server_timestamp);​

E isso imprime o seguinte, independentemente do fuso horário do usuário:

 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 

É claro que se você puder retornar o registro de data e hora em um formulário em que o deslocamento (DST ou não DST) já foi adicionado ao registro de data e hora no servidor, não é necessário calculá-lo no cliente e simplificar muito a function. Mas lembre-se de não usar timezoneOffset (), porque então você tem que lidar com o fuso horário do usuário e este não é o comportamento desejado.

Apenas outra abordagem

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

Supondo que você receba o timestamp no horário de Helsinque, criaria um object de data definido como meia-noite de 1 de janeiro de 1970 UTC (para desconsiderar as configurações de fuso horário local do navegador). Em seguida, basta adicionar o número necessário de milissegundos a ele.

 var _date = 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 

Você poderia usar setUTCMilliseconds()

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