2012-08-27 32 views
5

Estoy tratando de establecer el campo HOUR_OF_DAY y cambiar la zona horaria del objeto de fecha GregorianCalendar.Java GregorianCalendar change TimeZone

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10")); 
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY)); 
date.set(Calendar.HOUR_OF_DAY, 23); 
//date.get(Calendar.HOUR_OF_DAY); 
date.setTimeZone(TimeZone.getTimeZone("GMT")); 
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY)); 

Salida:

HOUR: 16 
HOUR: 23 

Por alguna razón el valor de HOUR_OF_DAY no cambia después de establecer diferentes zona horaria. Pero si Descomentar date.get para HOUR_OF_DAY, todo funciona exactamente como debería

GregorianCalendar date = new GregorianCalendar(TimeZone.getTimeZone("GMT+10")); 
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY)); 
date.set(Calendar.HOUR_OF_DAY, 23); 
date.get(Calendar.HOUR_OF_DAY); // uncommenting this line will is changing the output 
date.setTimeZone(TimeZone.getTimeZone("GMT")); 
System.out.println("HOUR: " + date.get(Calendar.HOUR_OF_DAY)); 

Salida:

HOUR: 16 
HOUR: 13 

¿Cómo es esto posible? ¿Por qué el método .get está cambiando el comportamiento de los objetos?

Respuesta

8

La clase GregorianCalendar hereda su método get de Calendar, que tiene el siguiente efecto secundario:

En el modo indulgente, todos los campos de calendario se normalizan.

Esto significa que el valor time y todos los campos se vuelven a calcular cuando get se llama en un objeto Calendar. Esto puede conducir a un comportamiento impredecible, especialmente cuando se combina con setTimeZone, que tiene algunos documented buggy behavior propios.

0

tl; dr

OffsetDateTime.now(ZoneOffset.ofHours(10) ).withHour(23) 

Evitar el legado clases de fecha y hora

El legado clases de fecha y hora, incluyendo GregorianCalendar son una confusa. torpe, mal diseño desastre. Evítales. Ahora suplantado por las clases java.time. Específicamente, GregorianCalendar se reemplaza por ZonedDateTime.

Offset-de-UTC

Evidentemente, usted quiere un momento con una offset-from-UTC de cada diez horas antes de UTC. Defina su desplazamiento deseado.

ZoneOffset offset = ZoneOffset.ofHours(10) ; 

offset.toString(): 10: 00

Obtener el momento actual como una OffsetDateTime con ese desplazamiento.

OffsetDateTime odt = OffsetDateTime.now(offset) ; 

odt.toString(): 2018-02-15T16: 44: 44.216642 + 10: 00

desea anular la hora de ser 23.

OffsetDateTime odt23 = odt.withHour(23) ; 

odt23.toString(): 2018-02-15T23: 44: 44.216642 + 10: 00

Zona horaria

Estoy tratando de establecer campo HOUR_OF_DAY y cambiar la zona horaria de la fecha objeto GregorianCalendar.

No, usted está cambiando el offset-from-UTC, no el time zone.

Siempre es mejor utilizar una zona horaria en lugar de una simple compensación, si conoce con certeza la zona prevista. Una zona horaria es un historial de cambios pasados, presentes y futuros en la compensación utilizada por las personas de una determinada región. Con una zona horaria, siempre puede determinar el desplazamiento, pero no viceversa.

Especifique un proper time zone name en el formato de continent/region, como America/Montreal, Africa/Casablanca, o Pacific/Auckland. Nunca utilice la abreviatura de 3-4 letras como EST o IST ya que son no zonas horarias verdaderas, no estandarizadas, y ni siquiera únicas (!).

ZoneId z = ZoneId.of("Australia/Brisbane") ; 

Capture el momento actual en un reloj de pared visto por las personas de esa zona.

ZonedDateTime zdt = ZonedDateTime.now(z) ; 

Anular la hora del día.

ZonedDateTime zdt23 = zdt.withHour(23) ; 

Sobre java.time

El marco java.time está incorporado en Java 8 y versiones posteriores. Estas clases suplantan a las viejas y problemáticas clases de fecha y hora de legacy, como java.util.Date, Calendar, & SimpleDateFormat.

El proyecto Joda-Time, ahora en maintenance mode, recomienda la migración a las clases java.time.

Para obtener más información, consulte el Oracle Tutorial. Y busque Stack Overflow para obtener muchos ejemplos y explicaciones. La especificación es JSR 310.

El uso de un JDBC driver compatible con JDBC 4.2 o temprano, es posible intercambiar java.time objetos directamente con su base de datos. No necesita cadenas ni clases java.sql. *.

¿Dónde obtener las clases java.time?

  • Java SE 8, Java SE 9, y más tarde
    • incorporado.
    • Parte de la API estándar de Java con una implementación integrada.
    • Java 9 agrega algunas características menores y correcciones.
  • Java SE 6 y Java SE 7
    • Gran parte de la funcionalidad de back-java.time está portado a Java 6 & 7 en ThreeTen-Backport.
  • Android
    • Las versiones posteriores de las implementaciones de haces de Android de las clases java.time.
    • Para Android anterior, el proyecto ThreeTenABP se adapta a ThreeTen-Backport (mencionado anteriormente). Ver How to use ThreeTenABP….

El proyecto se extiende ThreeTen-Extra java.time con clases adicionales. Este proyecto es un terreno de prueba para posibles adiciones futuras a java.time. Puede encontrar algunas clases útiles aquí, como Interval, YearWeek, YearQuarter y more.