jueves, 24 de enero de 2013

Fechas en Java

Varios links utiles:

http://www.devrecipes.com/2010/02/14/datetimetimezone-manipulation-and-conversion-in-java-a-few-examples/

http://brian.pontarelli.com/2011/08/16/database-handling-for-timezones/

http://stackoverflow.com/questions/12008801/in-the-oracle-jdbc-driver-what-happens-to-the-time-zone-when-you-write-a-java-d


El siguiente link explica claramente y con ejemplo de BD como actúan los timezones y la conveniencia de insertar los registros en BD en UTC sin ningun timezone por defecto:

http://ooxs-be.goracer.nl/EN/java/Java%20and%20Date.html


".... A user John in New York enters a date/time for a planned teleconference with his colleague Mark in Brussels. He types 2009-07-06 09:30 , the application parses that to a Date - containing a long value of 1246887000000. This Date represents 14:30 UTC . It is inserted as such in the database.

On the other side of the Atlantic ocean, Mark checks the date of the planned meeting, the application reads the date from the database - it still represents 14:30 UTC and contains the same long value of 1246887000000. Mark's session contains a formatter that formats this date to 2009-07-06 15:30

The basic point is that each user's session contains a SimpleDateFormat , configured to the time zone of that particular user and parses or formats localized string representations of the actual (UTC) date in the database........."


"....Databases have some support for working with date/time values taking into account the existence of timezones. Most support is focused on interpreting and showing date/time in the timezone of the 'user' or connection. The fact that in a typical architecture, database connections are shared between application users, changing timezones per connection is not a feasible approach
There are no substantial differences. I still recommend to convert everything to UTC before updating or inserting values to the database..."


"... Oracle supports TIMESTAMP WITH TIME ZONE and TIMESTAMP WITH LOCAL TIME ZONE that enable input and output taking time zones into consideration...."

y por ultimo:

"... If the column is declared as a TIMESTAMP and not, say, a TIMESTAMP WITH TIME ZONE or TIMESTAMP WITH LOCAL TIME ZONE, the timestamp that is stored in the table will not have a time zone component. As a result, SYS_EXTRACT_UTC (http://psoug.org/definition/SYS_EXTRACT_UTC.htm) will convert the timestamp to UTC using the session time zone which is something that is controlled by the client and may be different on different client machines. I suspect that if you run

from your OCCI application and from your SQL*Plus session that you will end up with different results which is causing the strings returned to be different.

If you want the string that is returned to be independent of the client machine, I would tend to suggest storing the time zone in the database column. Is changing the schema definition to use a TIMESTAMP WITH TIME ZONE an option? Barring that, you could ensure that every client machine has the same time zone configured and/or run an explicit ALTER SESSION, i.e. ...."


Texto extraído de aqui: http://stackoverflow.com/questions/3629603/oracle-timestamp-utc-time-format-problem


Ejemplo basico:


Calendar c1 = Calendar.getInstance();
c1.set(Calendar.DAY_OF_MONTH, 1);
c1.set(Calendar.MONTH, 1);
c1.set(Calendar.YEAR, 2013);
c1.set(Calendar.HOUR_OF_DAY, 10);
c1.set(Calendar.MINUTE, 00);
c1.set(Calendar.SECOND, 00);
c1.setTimeZone(TimeZone.getTimeZone("GMT-0"));
System.out.println(c1.getTimeZone());
System.out.println(c1.getTime());
System.out.println("c1.getTimeInMillis() : " + c1.getTimeInMillis());

sun.util.calendar.ZoneInfo[id="GMT-00:00",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null] Fri Feb 01 07:00:00 ART 2013 c1.getTimeInMillis() : 1359712800572

Calendar c1 = Calendar.getInstance();
c1.set(Calendar.DAY_OF_MONTH, 1);
c1.set(Calendar.MONTH, 1);
c1.set(Calendar.YEAR, 2013);
c1.set(Calendar.HOUR_OF_DAY, 07);
c1.set(Calendar.MINUTE, 00);
c1.set(Calendar.SECOND, 00);
c1.setTimeZone(TimeZone.getTimeZone("GMT-3"));
System.out.println(c1.getTimeZone());
System.out.println(c1.getTime());
System.out.println("c1.getTimeInMillis() : " + c1.getTimeInMillis());
sun.util.calendar.ZoneInfo[id="GMT-03:00",offset=-10800000,dstSavings=0,useDaylight=false,transitions=0,lastRule=null] Fri Feb 01 07:00:00 ART 2013 c1.getTimeInMillis() : 1359712800590

Como vemos son iguales salvo los 3 últimos números. Estos 3 últimos números siempre varían en cada prueba que lancemos..

En cambio, si ambos calendars tienen la misma fecha, los milisegundos son distintos.

Aqui dejamos una pagina muy util para el calculo de las fechas:

http://www.ruddwire.com/handy-code/date-to-millisecond-calculators/


IMPORTANTE

Si yo creo dos objetos calendar y le seteo la MISMA fecha (ej 05/11/1980 a las 12hs) a ambos pero distintos timezones (12hs en Argentina y 12hs en Italia), cuando les pida los milisegundos a ambos, dichos milisegundos TIENEN que ser DISTINTOS porque no es el mismo tiempo transcurrido desde 1970.  

Es decir, a las 12hs Italia en la Argentina son las 8hs AM y viceversa, con lo cual, el tiempo que transcurrió desde el 1 de enero de 1970 hasta las 12hs de Argentina es el mismo que el tiempo que transcurrió hasta las 8hs Italia. Pero no es el mismo tiempo transcurrido hasta las 12hs de Argentina y 12hs de Italia.

Esto mismo ocurre cuando tenemos que leer una fecha de una BD.  Si con diferentes timezones (ejemplo, con timezone argentino y de venenzuela) leemos la misma fecha (es decir, que el método getTimestamp() del resultset de jdbc nos devuelve la misma fecha en ambos casos),  los milisegundos transcurridos serán distintos (idem ejemplo anterior entre argentina e italia).

Ahora bien, si en caso que la fecha que se esta leyendo (la misma) en diferentes paises (con diferentes timezones), varia según el timezone, obviamente los milisegundos transcurridos TIENEN QUE SER LOS MISMOS