Forzar la zona horaria de Java como GMT / UTC

95

Necesito forzar cualquier operación relacionada con la hora a GMT / UTC, independientemente de la zona horaria establecida en la máquina. ¿Alguna forma conveniente de hacerlo en el código?

Para aclarar, estoy usando la hora del servidor de base de datos para todas las operaciones, pero sale formateado de acuerdo con la zona horaria local.

¡Gracias!

SyBer
fuente
En realidad, su problema es un subconjunto del mío, pero encontré una solución.
SyBer
Mire la pregunta duplicada y busque "Joda" y "DateTimeZone".
Basil Bourque

Respuestas:

124

El OP respondió a esta pregunta para cambiar la zona horaria predeterminada para una sola instancia de una JVM en ejecución, establezca la user.timezonepropiedad del sistema:

java -Duser.timezone=GMT ... <main-class>

Si necesita establecer zonas horarias específicas al recuperar objetos de fecha / hora / marca de tiempo de una base de datos ResultSet, use la segunda forma de los getXXXmétodos que toman un Calendarobjeto:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
ResultSet rs = ...;
while (rs.next()) {
    Date dateValue = rs.getDate("DateColumn", tzCal);
    // Other fields and calculations
}

O, estableciendo la fecha en un PreparedStatement:

Calendar tzCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
PreparedStatement ps = conn.createPreparedStatement("update ...");
ps.setDate("DateColumn", dateValue, tzCal);
// Other assignments
ps.executeUpdate();

Esto garantizará que el valor almacenado en la base de datos sea coherente cuando la columna de la base de datos no mantenga la información de la zona horaria.

Las clases java.util.Datey java.sql.Datealmacenan el tiempo real (milisegundos) en UTC. Para formatearlos en la salida a otra zona horaria, use SimpleDateFormat. También puede asociar una zona horaria con el valor mediante un objeto Calendario:

TimeZone tz = TimeZone.getTimeZone("<local-time-zone>");
//...
Date dateValue = rs.getDate("DateColumn");
Calendar calValue = Calendar.getInstance(tz);
calValue.setTime(dateValue);

Referencia útil

https://docs.oracle.com/javase/9/troubleshoot/time-zone-settings-jre.htm#JSTGD377

https://confluence.atlassian.com/kb/setting-the-timezone-for-the-java-environment-841187402.html

Kevin Brock
fuente
Una cosa a tener en cuenta sobre la configuración de la zona horaria para toda la JVM es que afecta a todo, incluidas cosas como el registro. Solo algo a tener en cuenta si ese es el efecto deseado.
Hermann Hans
Sí, está bien. Solo un punto para mencionar, que en realidad configuré user.timezone directamente en el código, en lugar de hacerlo mediante el parámetro -D.
SyBer
6
@SyBer: Eso funciona, pero debe asegurarse de configurarlo antes de que cualquier método llame al método TimeZone.getDefault (). De lo contrario, tendrá cierta confusión ya que el valor predeterminado se almacena en caché después de la primera ejecución. Esto también significa que podría ser un problema si lo hace dentro de una API / biblioteca (oculta a la vista simple); asegúrese de documentar en gran medida lo que está haciendo.
Kevin Brock
23

Además, si puede configurar la zona horaria de JVM de esta manera

System.setProperty("user.timezone", "EST");

o -Duser.timezone=GMTen los argumentos de JVM.

Desarrollador MG
fuente
System.setProperty("user.timezone" ...)no funciona.
wilmol
9

Puede cambiar la zona horaria usando TimeZone.setDefault () :

TimeZone.setDefault(TimeZone.getTimeZone("GMT"))
snorbi
fuente
No se ofenda, pero modificar temporalmente un estado estático global suena como una muy mala idea ...
G. Demecki
Podrías, pero no deberías. Este es un consejo extraordinariamente malo. Toda la JVM ha cambiado su zona horaria.
scot
1
A veces es exactamente lo que quieres lograr. P.ej. He visto microservicios basados ​​en Java que se ejecutan siempre con UTC para evitar problemas de zona horaria. En estos sistemas, el backend de la base de datos también se ejecuta con UTC, por lo que es natural "forzar" la JVM a UTC también. Lo importante: tienes que saber lo que estás haciendo y cuáles son las consecuencias ...
snorbi
absolutamente no. Si desea que todo su sistema esté en UTC (una muy buena idea), configure la zona horaria del sistema en UTC y deje la zona horaria de Java en paz.
scot
3
Excepto si tiene varias JVM con diferentes requisitos. Podemos discutir para siempre, pero cada caso es único: a veces es necesario establecer la zona horaria de todo el sistema, a veces solo establece una JVM. Seamos felices de que los sistemas actuales sean tan flexibles que podamos hacer ambas cosas 😉
snorbi
8

para mí, simplemente SimpleDateFormat rápido,

  private static final SimpleDateFormat GMT = new SimpleDateFormat("yyyy-MM-dd");
  private static final SimpleDateFormat SYD = new SimpleDateFormat("yyyy-MM-dd");
  static {
      GMT.setTimeZone(TimeZone.getTimeZone("GMT"));
    SYD.setTimeZone(TimeZone.getTimeZone("Australia/Sydney"));
  }

luego formatee la fecha con una zona horaria diferente.

lwpro2
fuente
6

Recuperaría la hora de la base de datos en forma sin procesar (marca de tiempo larga o fecha de Java), y luego usaría SimpleDateFormat para formatearla, o Calendar para manipularla. En ambos casos, debe establecer la zona horaria de los objetos antes de usarlos.

Ver SimpleDateFormat.setTimeZone(..)y Calendar.setTimeZone(..)para más detalles

Eyal Schneider
fuente
6

tl; dr

String sql = "SELECT CURRENT_TIMESTAMP ;

OffsetDateTime odt = myResultSet.getObject( 1 , OffsetDateTime.class ) ;

Evite depender del sistema operativo del host o JVM para la zona horaria predeterminada

Le recomiendo que escriba todo su código para indicar explícitamente la zona horaria deseada / esperada. No es necesario que dependa de la zona horaria predeterminada actual de la JVM. Y tenga en cuenta que la zona horaria predeterminada actual de la JVM puede cambiar en cualquier momento durante el tiempo de ejecución, con cualquier código en cualquier hilo de cualquier llamada de aplicación TimeZone.setDefault. Tal llamada afecta a todas las aplicaciones dentro de esa JVM inmediatamente.

java.time

Algunas de las otras respuestas eran correctas, pero ahora están pasadas de moda. Las terribles clases de fecha y hora incluidas con las primeras versiones de Java tenían fallas, escritas por personas que no entendían las complejidades y sutilezas del manejo de la fecha y hora.

Las clases de fecha y hora heredadas han sido suplantadas por las clases java.time definidas en JSR 310.

Para representar una zona horaria, utilice ZoneId. Para representar un desplazamiento de UTC, utilice ZoneOffset. Un desplazamiento es simplemente un número de horas-minutos-segundos por delante o por detrás del primer meridiano. Una zona horaria es mucho más. Una zona horaria es un historial de los cambios pasados, presentes y futuros del desplazamiento utilizado por la gente de una región en particular.

Necesito forzar cualquier operación relacionada con el tiempo a GMT / UTC

Para una compensación de cero horas-minutos-segundos, use la constante ZoneOffset.UTC.

Instant

Para capturar el momento actual en UTC, use un Instant. Esta clase representa un momento en UTC, siempre en UTC por definición.

Instant instant = Instant.now() ;  // Capture current moment in UTC.

ZonedDateTime

Para ver ese mismo momento a través del tiempo de reloj de pared utilizado por la gente de una región en particular, ajústese a una zona horaria. Mismo momento, mismo punto en la línea de tiempo, diferente hora de reloj de pared.

ZoneId z = ZoneId.of( "Asia/Tokyo" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;

Base de datos

Mencionas una base de datos.

Para recuperar un momento de la base de datos, su columna debe ser de un tipo de datos similar al estándar SQL TIMESTAMP WITH TIME ZONE. Recupere un objeto en lugar de una cadena. En JDBC 4.2 y posteriores, podemos intercambiar objetos java.time con la base de datos. El OffsetDateTimees requerido por JDBC, mientras que Instanty ZonedDateTimeson opcionales.

OffsetDateTime odt = myResultSet.getObject(  , OffsetDateTime.class ) ;

En la mayoría de las bases de datos y controladores, supongo que obtendrá el momento como se ve en UTC. Pero si no es así, puede ajustarlo de dos formas:

  • Extrae un Instant: odt.toInstant()
  • Ajuste del desplazamiento dado a un desplazamiento de cero: OffsetDateTime odtUtc = odt.withOffsetSameInstant (ZoneOffset.UTC); `.

Tabla de tipos de fecha y hora en Java (tanto heredado como moderno) y en SQL estándar


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, y SimpleDateFormat.

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 .

El proyecto Joda-Time , ahora en modo de mantenimiento , aconseja la migración a las clases java.time .

Puede intercambiar objetos java.time directamente con su base de datos. Utilice un controlador JDBC compatible con JDBC 4.2 o posterior. No se necesitan cuerdas, no se necesitan java.sql.*clases.

¿Dónde obtener las clases java.time?

Albahaca Bourque
fuente
1

Cree un par de cliente / servidor, de modo que después de la ejecución, el servidor cliente envíe la fecha y hora correctas. Luego, el cliente pregunta al servidor pm GMT y el servidor devuelve la respuesta correcta.

bertán
fuente
1

Utilice la propiedad del sistema:

-Duser.timezone=UTC
Dawid Stępień
fuente
5
¿Por qué debería uno usar eso? Agregue alguna explicación a su respuesta para que otros puedan aprender de ella
Nico Haase
1

Ejecute esta línea en MySQL para restablecer su zona horaria:

SET @@global.time_zone = '+00:00';
Saeed
fuente
0

Guau. Sé que este es un hilo antiguo, pero todo lo que puedo decir es que no llame a TimeZone.setDefault () en ningún código de nivel de usuario. Esto siempre establece la zona horaria para toda la JVM y casi siempre es una muy mala idea. Aprenda a usar la biblioteca joda.time o la nueva clase DateTime en Java 8, que es muy similar a la biblioteca joda.time.

escocés
fuente
-6

Si desea obtener la hora GMT solo con intiger: var currentTime = new Date (); var currentYear = '2010' var currentMonth = 10; var currentDay = '30 'var currentHours = '20' var currentMinutes = '20 'var currentSeconds = '00' var currentMilliseconds = '00 '

currentTime.setFullYear(currentYear);
currentTime.setMonth((currentMonth-1)); //0is January
currentTime.setDate(currentDay);  
currentTime.setHours(currentHours);
currentTime.setMinutes(currentMinutes);
currentTime.setSeconds(currentSeconds);
currentTime.setMilliseconds(currentMilliseconds);

var currentTimezone = currentTime.getTimezoneOffset();
currentTimezone = (currentTimezone/60) * -1;
var gmt ="";
if (currentTimezone !== 0) {
  gmt += currentTimezone > 0 ? ' +' : ' ';
  gmt += currentTimezone;
}
alert(gmt)
Incmos
fuente
5
eso me parece JavaScript (! = Java).
Phil