Tengo un valor de marca de tiempo que proviene de mi aplicación. El usuario puede estar en cualquier zona horaria local determinada.
Dado que esta fecha se usa para un WebService que asume que la hora dada siempre está en GMT, tengo la necesidad de convertir el parámetro del usuario de digamos (EST) a (GMT). Aquí está el truco: el usuario es ajeno a su TZ. Ingresa la fecha de creación que quiere enviar a WS, entonces lo que necesito es:
El usuario ingresa: 5/1/2008 6:12 PM (EST)
El parámetro de WS debe ser : 5/1/2008 6:12 PM (GMT)
Sé que las marcas de tiempo siempre deben estar en GMT de forma predeterminada, pero al enviar el parámetro, aunque creé mi calendario desde el TS (que se supone que está en GMT), las horas siempre están apagadas a menos que el usuario esté en GMT. ¿Qué me estoy perdiendo?
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;
}
Con el Código anterior, esto es lo que obtengo como resultado (formato corto para una lectura fácil):
[1 de mayo de 2008 11:12 p. M.]
Respuestas:
Aquí está la salida si paso la hora actual ("12:09:05 EDT" de
Calendar.getInstance()
) en:12:09:05 GMT son las 8:09:05 EDT.
La parte confusa aquí es que le
Calendar.getTime()
devuelve unDate
en su zona horaria actual, y también que no hay un método para modificar la zona horaria de un calendario y hacer que la fecha subyacente también aparezca. Dependiendo del tipo de parámetro que tome su servicio web, es posible que solo desee tener el trato de WS en términos de milisegundos desde la época.fuente
offsetFromUTC
lugar de sumarlo? Usando su ejemplo, si las 12:09 GMT son las 8:09 EDT (que es cierto), y el usuario ingresa "12:09 EDT", el algoritmo debería generar "16:09 GMT", en mi opinión.Gracias a todos por responder. Después de una investigación más profunda, obtuve la respuesta correcta. Como mencionó Skip Head, el TimeStamped que obtenía de mi aplicación se estaba ajustando al TimeZone del usuario. Entonces, si el usuario ingresó a las 6:12 p.m. (EST), obtendría 2:12 p.m. (GMT). Lo que necesitaba era una forma de deshacer la conversión para que la hora ingresada por el usuario sea la hora que envié a la solicitud del WebServer. Así es como logré esto:
La salida del código es: (El usuario ingresó el 5/1/2008 6:12 PM (EST)
Zona horaria del usuario actual: EST
Desplazamiento actual de GMT (en horas): - 4 (Normalmente -5, excepto que se ajusta el DST)
TS de ACP: 2008-05-01 14: 12: 00.0
Fecha de calendario convertida de TS usando GMT y US_EN Locale : 1/5/08 6:12 p.m. (GMT)
fuente
Dice que la fecha se usa en relación con los servicios web, por lo que supongo que se serializa en una cadena en algún momento.
Si este es el caso, debería echar un vistazo al método setTimeZone de la clase DateFormat. Esto dicta qué zona horaria se utilizará al imprimir la marca de tiempo.
Un simple ejemplo:
fuente
Puedes resolverlo con Joda Time :
Java 8:
fuente
Parece que su TimeStamp se está configurando en la zona horaria del sistema de origen.
Esto está desaprobado, pero debería funcionar:
La forma no obsoleta es usar
pero eso tendría que hacerse del lado del cliente, ya que ese sistema sabe en qué zona horaria se encuentra.
fuente
Método para convertir de una zona horaria a otra (probablemente funcione :)).
fuente
Los objetos Date y Timestamp son ajenos a la zona horaria: representan un cierto número de segundos desde la época, sin comprometerse con una interpretación particular de ese instante como horas y días. Las zonas horarias ingresan a la imagen solo en GregorianCalendar (no se necesita directamente para esta tarea) y SimpleDateFormat , que necesitan un desplazamiento de zona horaria para convertir entre campos separados y valores de fecha (o largos ).
El problema del OP está justo al comienzo de su procesamiento: el usuario ingresa horas, que son ambiguas, y se interpretan en la zona horaria local, no GMT; en este punto, el valor es "6:12 EST" , que se puede imprimir fácilmente como "11.12 GMT" o cualquier otra zona horaria, pero nunca cambiará a "6.12 GMT" .
No hay forma de hacer que SimpleDateFormat que analiza "06:12" como "HH: MM" (por defecto a la zona horaria local) por defecto a UTC en su lugar; SimpleDateFormat es demasiado inteligente para su propio bien.
Sin embargo, puede convencer a cualquier instancia de SimpleDateFormat para que use la zona horaria correcta si la coloca explícitamente en la entrada: simplemente agregue una cadena fija a las "06:12" recibidas (y adecuadamente validadas) para analizar "06:12 GMT" como "HH: MM z" .
No hay necesidad de establecer explícitamente los campos GregorianCalendar o de recuperar y usar la zona horaria y las compensaciones del horario de verano.
El problema real es segregar las entradas que están predeterminadas en la zona horaria local, las entradas que están predeterminadas en UTC y las entradas que realmente requieren una indicación explícita de la zona horaria.
fuente
Algo que me ha funcionado en el pasado fue determinar el desplazamiento (en milisegundos) entre la zona horaria del usuario y GMT. Una vez que tenga el desplazamiento, puede simplemente sumar / restar (dependiendo de en qué dirección vaya la conversión) para obtener el tiempo apropiado en cualquier zona horaria. Por lo general, lograría esto configurando el campo de milisegundos de un objeto Calendario, pero estoy seguro de que podría aplicarlo fácilmente a un objeto de marca de tiempo. Aquí está el código que utilizo para obtener la compensación
timezoneId es el ID de la zona horaria del usuario (como EST).
fuente
java.time
El enfoque moderno utiliza las clases java.time que suplantaron las problemáticas clases de fecha y hora heredadas incluidas con las primeras versiones de Java.
La
java.sql.Timestamp
clase es una de esas clases heredadas. Ya no es necesario. En su lugar, useInstant
u otras clases java.time directamente con su base de datos usando JDBC 4.2 y posterior.La
Instant
clase representa un momento en la línea de tiempo en UTC con una resolución de nanosegundos (hasta nueve (9) dígitos de una fracción decimal).Si debe interoperar con uno existente
Timestamp
, conviértalo inmediatamente a java.time mediante los nuevos métodos de conversión agregados a las clases antiguas.Para ajustar a otra zona horaria, especifique la zona horaria como un
ZoneId
objeto. Especificar un nombre de zona horaria correcta en el formato decontinent/region
, por ejemploAmerica/Montreal
,Africa/Casablanca
oPacific/Auckland
. Nunca use las pseudozonas de 3-4 letras comoEST
oIST
ya que no son zonas horarias verdaderas, no están estandarizadas y ni siquiera son únicas (!).Aplicar al
Instant
para producir unZonedDateTime
objeto.Para generar una cadena para mostrar al usuario, busque Stack Overflow para
DateTimeFormatter
encontrar muchas discusiones y ejemplos.Su pregunta se trata realmente de ir en la otra dirección, desde la entrada de datos del usuario hasta los objetos de fecha y hora. Generalmente es mejor dividir la entrada de datos en dos partes, una fecha y una hora del día.
Tu pregunta no está clara. ¿Quiere interpretar que la fecha y la hora introducidas por el usuario están en UTC? ¿O en otra zona horaria?
Si nos referimos UTC, crear una
OffsetDateTime
con un desplazamiento utilizando la constante de UTC,ZoneOffset.UTC
.Si se refería a otra zona horaria, combine junto con un objeto de zona horaria, a
ZoneId
. ¿Pero en qué zona horaria? Es posible que detecte una zona horaria predeterminada. O, si es crítico, debe confirmar con el usuario para estar seguro de su intención.Para obtener un objeto más simple que siempre esté en UTC por definición, extraiga un archivo
Instant
.…o…
Envíe a su base de datos.
Acerca de java.time
El marco java.time está integrado en Java 8 y versiones posteriores. Estas clases suplantar la vieja problemáticos heredados clases de fecha y hora como
java.util.Date
,Calendar
, ySimpleDateFormat
.El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .
Para obtener más información, consulte el tutorial de Oracle . Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310 .
¿Dónde obtener las clases java.time?
El proyecto ThreeTen-Extra extiende java.time con clases adicionales. Este proyecto es un campo de pruebas para posibles adiciones futuras a java.time. Usted puede encontrar algunas clases útiles aquí, como
Interval
,YearWeek
,YearQuarter
, y más .fuente