Eu tenho um valor de carimbo de data / hora que vem do meu aplicativo. O usuário pode estar em qualquer fuso horário local.
Como essa data é usada para um WebService que assume que a hora fornecida está sempre em GMT, preciso converter o parâmetro do usuário de, digamos, (EST) para (GMT). Aqui está o kicker: o usuário está alheio ao seu TZ. Ele insere a data de criação que deseja enviar ao WS, então o que eu preciso é:
O usuário insere: 01/05/2008 18:12 (EST)
O parâmetro para o WS deve ser : 01/05/2008 18:12 (GMT)
Eu sei que TimeStamps sempre devem estar em GMT por padrão, mas ao enviar o parâmetro, embora eu tenha criado meu calendário a partir do TS (que deveria estar em GMT), as horas estão sempre desligadas, a menos que o usuário esteja em GMT. o que estou perdendo?
Timestamp issuedDate = (Timestamp) getACPValue(inputs_, "issuedDate");
Calendar issueDate = convertTimestampToJavaCalendar(issuedDate);
...
private static java.util.Calendar convertTimestampToJavaCalendar(Timestamp ts_) {
java.util.Calendar cal = java.util.Calendar.getInstance(
GMT_TIMEZONE, EN_US_LOCALE);
cal.setTimeInMillis(ts_.getTime());
return cal;
}
Com o código anterior, é o que obtenho como resultado (formato curto para facilitar a leitura):
[1º de maio de 2008 23h12]
Respostas:
Esta é a saída se eu passar a hora atual ("12:09:05 EDT" de
Calendar.getInstance()
) em:12:09:05 GMT é 8:09:05 EDT.
A parte confusa aqui é que
Calendar.getTime()
retorna umDate
em seu fuso horário atual, e também que não há nenhum método para modificar o fuso horário de um calendário e ter a data subjacente rolada também. Dependendo do tipo de parâmetro que seu serviço da web usa, você pode querer apenas ter o acordo WS em termos de milissegundos a partir da época.fonte
offsetFromUTC
vez de adicioná-lo? Usando o seu exemplo, se 12:09 GMT for 8:09 EDT (o que é verdade), e o usuário inserir "12:09 EDT", o algoritmo deverá gerar "16:09 GMT", em minha opinião.Obrigado a todos por responder. Após uma investigação mais aprofundada, cheguei à resposta certa. Conforme mencionado por Skip Head, o TimeStamped que eu estava recebendo do meu aplicativo estava sendo ajustado para o TimeZone do usuário. Portanto, se o usuário inserisse 18h12 (EST), eu receberia 14h12 (GMT). O que eu precisava era de uma forma de desfazer a conversão para que a hora inserida pelo usuário fosse a hora que enviei para a solicitação do WebServer. Veja como eu fiz isso:
A saída do código é: (Usuário inserido 01/05/2008 18:12 (EST)
Fuso
horário do usuário atual: EST Compensação atual de GMT (em horas): - 4 (Normalmente -5, exceto se o horário de verão é ajustado)
TS de ACP: 2008-05-01 14: 12: 00.0
Data do calendário convertida de TS usando GMT e US_EN Local : 01/05/08 18:12 (GMT)
fonte
Você diz que a data é usada em conexão com serviços da web, então presumo que seja serializada em uma string em algum ponto.
Se for esse o caso, você deve dar uma olhada no método setTimeZone da classe DateFormat. Isso determina qual fuso horário será usado ao imprimir o carimbo de hora.
Um exemplo simples:
fonte
Você pode resolver isso com Joda Time :
Java 8:
fonte
Parece que seu TimeStamp está sendo definido para o fuso horário do sistema de origem.
Está obsoleto, mas deve funcionar:
A maneira não obsoleta é usar
mas isso precisaria ser feito no lado do cliente, já que esse sistema sabe em que fuso horário está.
fonte
Método para converter de um timeZone para outro (provavelmente funciona :)).
fonte
Os objetos Date e Timestamp ignoram o fuso horário: eles representam um certo número de segundos desde a época, sem se comprometer com uma interpretação particular daquele instante como horas e dias. Os fusos horários entram na imagem apenas em GregorianCalendar (não diretamente necessário para esta tarefa) e SimpleDateFormat , que precisam de um deslocamento de fuso horário para converter entre campos separados e valores de data (ou longos ).
O problema do OP está logo no início de seu processamento: o usuário insere horas, que são ambíguas, e são interpretadas no fuso horário local, não GMT; neste ponto, o valor é "6:12 EST" , que pode ser facilmente impresso como "11,12 GMT" ou qualquer outro fuso horário, mas nunca mudará para "6,12 GMT" .
Não há como fazer com que o SimpleDateFormat que analisa "06:12" como "HH: MM" (padronizando para o fuso horário local) seja UTC como padrão; SimpleDateFormat é um pouco inteligente demais para seu próprio bem.
No entanto, você pode convencer qualquer instância de SimpleDateFormat a usar o fuso horário correto se colocá-lo explicitamente na entrada: basta anexar uma string fixa ao recebido (e adequadamente validado) "06:12" para analisar "06:12 GMT" como "HH: MM z" .
Não há necessidade de configuração explícita de campos GregorianCalendar ou de recuperar e usar fuso horário e ajustes de horário de verão.
O verdadeiro problema é segregar entradas que são padronizadas para o fuso horário local, entradas que são padronizadas para UTC e entradas que realmente requerem uma indicação explícita de fuso horário.
fonte
Algo que funcionou para mim no passado foi determinar o deslocamento (em milissegundos) entre o fuso horário do usuário e o GMT. Depois de obter o deslocamento, você pode simplesmente adicionar / subtrair (dependendo de como a conversão está indo) para obter o tempo apropriado em qualquer fuso horário. Eu normalmente faria isso definindo o campo de milissegundos de um objeto Calendar, mas tenho certeza de que você poderia aplicá-lo facilmente a um objeto timestamp. Aqui está o código que uso para obter o deslocamento
timezoneId é o id do fuso horário do usuário (como EST).
fonte
java.time
A abordagem moderna usa as classes java.time que suplantaram as classes legadas e problemáticas de data e hora agrupadas com as primeiras versões do Java.
A
java.sql.Timestamp
classe é uma daquelas classes legadas. Não é mais necessário. Em vez disso, useInstant
ou outras classes java.time diretamente com seu banco de dados usando JDBC 4.2 e posterior.A
Instant
classe representa um momento na linha do tempo em UTC com uma resolução de nanossegundos (até nove (9) dígitos de uma fração decimal).Se você precisar interoperar com um existente
Timestamp
, converta imediatamente em java.time por meio dos novos métodos de conversão adicionados às classes antigas.Para ajustar em outro fuso horário, especifique o fuso horário como um
ZoneId
objeto. Especifique um nome próprio fuso horário no formatocontinent/region
, comoAmerica/Montreal
,Africa/Casablanca
, ouPacific/Auckland
. Nunca use os pseudo-fusos de 3-4 letras, comoEST
ouIST
porque eles não são fusos horários verdadeiros, não padronizados e nem mesmo únicos (!).Aplicar ao
Instant
para produzir umZonedDateTime
objeto.Para gerar uma string para exibir ao usuário, pesquise Stack Overflow para
DateTimeFormatter
encontrar muitas discussões e exemplos.Sua pergunta é realmente sobre ir na outra direção, da entrada de dados do usuário aos objetos de data e hora. Geralmente é melhor dividir a entrada de dados em duas partes, uma data e uma hora do dia.
Sua pergunta não está clara. Você quer interpretar a data e a hora inseridas pelo usuário como sendo UTC? Ou em outro fuso horário?
Se você quis dizer UTC, crie um
OffsetDateTime
com um deslocamento usando a constante para UTCZoneOffset.UTC
,.Se você quis dizer outro fuso horário, combine junto com um objeto de fuso horário, a
ZoneId
. Mas qual fuso horário? Você pode detectar um fuso horário padrão. Ou, se for crítico, você deve confirmar com o usuário para ter certeza de sua intenção.Para obter um objeto mais simples que está sempre em UTC por definição, extraia um
Instant
.…ou…
Envie para seu banco de dados.
Sobre java.time
A estrutura java.time é integrada ao Java 8 e posterior. Essas classes suplantar os velhos problemáticos legados aulas de data e hora, como
java.util.Date
,Calendar
, eSimpleDateFormat
.O projeto Joda-Time , agora em modo de manutenção , aconselha a migração para as classes java.time .
Para saber mais, consulte o tutorial Oracle . E pesquise no Stack Overflow para muitos exemplos e explicações. A especificação é JSR 310 .
Onde obter as classes java.time?
O projeto ThreeTen-Extra estende java.time com classes adicionais. Este projeto é um campo de provas para possíveis adições futuras ao java.time. Você pode encontrar algumas classes úteis aqui, como
Interval
,YearWeek
,YearQuarter
, e mais .fonte