Como posso determinar um fuso horário pela UTC compensado?
-
16-09-2019 - |
Pergunta
Eu tenho um cenário onde eu tenho um offset (em minutos) fuso horário e necessidade de determinar o fuso horário para ele. Eu sei que todos os dados não está disponível (por exemplo, pode haver vários fusos horários com um deslocamento de -240 minutos), mas uma "melhor estimativa" é aceitável.
A minha primeira passagem ficou assim:
foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
if (info.BaseUtcOffset.TotalMinutes == timezoneOffset)
{
// do something here if this is a valid timezone
}
}
Este sorta funciona, mas eu preciso para conta para horário de verão que está me jogando fora um pouco. Eu adicionei este terrível corte:
foreach (var info in TimeZoneInfo.GetSystemTimeZones())
{
var extra = info.IsDaylightSavingTime(DateTime.Now) ? 60 : 0;
if (info.BaseUtcOffset.TotalMinutes + extra == timezoneOffset)
{
// do something here if this is a valid timezone
}
}
Isso funciona "bem o suficiente" em que eu possa mostrar ao usuário o tempo correto para eles quando o horário de verão não está em vigor e estou cerca de 70% correta durante DST. Ainda assim ... isso é algum código terrível aos meus globos oculares.
Existe uma maneira melhor de fazer isso? Mais elegância seria bom, e mais precisão seria melhor ainda.
Atualização
Tecnicamente eu tenho acesso a qualquer informação Javascript pode obter sobre a data. Eu tenho uma página na qual eu tenho colocado um campo oculto chamado "compensar". Eu tenho uma função JQuery que preenche o campo compensado com o DateTime (). GetTimezoneOffset (). Enquanto eu não vejo nada no objeto DateTime que vai ajudar, talvez isso vai abrir outros caminhos para idéias.
Solução
Resposta curta:. Você não pode
O horário de verão tornam impossível. Por exemplo, não há nenhuma maneira de determinar, exclusivamente a partir de UTC offset, a diferença entre o Arizona e Califórnia no verão, ou Arizona e Novo México no inverno (desde Arizona não observa DST).
Há também a questão do que de tempo diferentes países observam DST. Por exemplo, na DST US começa mais cedo e termina mais tarde do que na Europa.
A suposição perto é possível (ou seja +/- uma hora), mas se você estiver usando-o para exibir tempo para os usuários você vai inevitavelmente exibir a hora errada para alguns deles.
Atualizar : A partir dos comentários, parece que o seu principal objetivo é exibir um timestamp no fuso horário local do usuário. Se é isso que você quer fazer, você deve enviar o tempo como um timestamp UTC, e em seguida, basta reescrevê-lo no navegador do usuário com Javascript. No caso em que eles não têm Javascript habilitado, eles ainda iria ver um UTC timestamp utilizável. Aqui é uma função que eu vim com a esta pergunta ??a >, que eu usei no este script Greasemonkey . Você pode querer ajustá-lo para atender às suas necessidades.
//@param timestamp An ISO-8601 timestamp in the form YYYY-MM-DDTHH:MM:SS±HH:MM
//Note: Some other valid ISO-8601 timestamps are not accepted by this function
function parseISO8601(timestamp)
{
var regex = new RegExp("^([\\d]{4})-([\\d]{2})-([\\d]{2})T([\\d]{2}):([\\d]{2}):([\\d]{2})([\\+\\-])([\\d]{2}):([\\d]{2})$");
var matches = regex.exec(timestamp);
if(matches != null)
{
var offset = parseInt(matches[8], 10) * 60 + parseInt(matches[9], 10);
if(matches[7] == "-")
offset = -offset;
return new Date(
Date.UTC(
parseInt(matches[1], 10),
parseInt(matches[2], 10) - 1,
parseInt(matches[3], 10),
parseInt(matches[4], 10),
parseInt(matches[5], 10),
parseInt(matches[6], 10)
) - offset*60*1000
);
}
return null;
}
Aqui está uma função que eu uso no meu blog para exibir um timestamp analisado no fuso horário local do usuário. Novamente, você pode ajustá-lo para o formato que você quiser.
var weekDays = new Array("Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday");
var months = new Array("January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December");
function toLocalTime(date)
{
var hour = date.getHours();
var ampm = (hour < 12 ? "am" : "pm");
hour = (hour + 11)%12 + 1;
var minutes = date.getMinutes();
if(minutes < 10)
minutes = "0" + minutes;
return weekDays[date.getDay()] + ", "
+ months[date.getMonth()] + " "
+ date.getDate() + ", "
+ date.getFullYear() + " at "
+ hour + ":"
+ minutes + " "
+ ampm;
}
Outras dicas
Sabendo apenas o deslocamento do UTC, você não pode dizer o fuso horário em que está, por causa da DST. Você poderia considerar a olhar para a parte da hora do tempo para tentar adivinhar se DST estava em vigor, em seguida, ou não, mas considerações políticas que isso quase impossível, como diferentes jurisdições alterar a definição de DST.