Clase Calendar y GregorianCalendar Java

Clase Calendar y GregorianCalendar java. Conversión de Fechas. Ejemplos. Cambios desde Java 8 (CU00925C) Escrito por Man

Views 76 Downloads 7 File size 936KB

Report DMCA / Copyright

DOWNLOAD FILE

Recommend stories

Citation preview

Clase Calendar y GregorianCalendar java. Conversión de Fechas. Ejemplos. Cambios desde Java 8 (CU00925C) Escrito por Manuel Sierra

Resumen: Entrega nº25 del Curso Lenguaje de programación Java Nivel Avanzado I Codificación aprenderaprogramar.com: CU00925C

INTRODUCCIÓN A partir de la introducción de la versión Java 8, el manejo de las fechas y el tiempo ha cambiado en Java. Desde esta versión, se ha creado una nueva API para el manejo de fechas y tiempo en el paquete java.time, que resuelve distintos problemas que se presentaban con el manejo de fechas y tiempo en versiones anteriores. Sin embargo, nos podemos encontrar con la necesidad de tener que trabajar con código que usa versiones anteriores o que sigue usando las clases para el manejo de fechas y tiempo de java.util.

Tener en cuenta que si se está usando una versión de Java igual o superior a la 8 no deben usarse estas clases sino las proporcionadas dentro del paquete java.time. En apartados anteriores del curso vimos cómo usar la clase Date de Java para manejar fechas. Pero Date tiene distintas limitaciones (de hecho vimos que gran parte de sus métodos están “deprecated”), ni contiene métodos para realizarle consultas. Date simplemente representa una fecha exacta. Calendar también representa una fecha pero su principal objetivo es que sea mutable, es decir, permitir cambiar su valor sin generar un nuevo objeto (cosa que no permite Date).

CALENDAR La clase Calendar posee una gran cantidad de métodos para operar, consultar y modificar las propiedades de una fecha. Un aspecto principal es que es una clase abstracta y como tal posee algunos métodos que deben ser implementados por sus subclases. Calendar se suele instanciar con su método getInstance() el cual nos crea un objeto de la clase conteniendo

la

fecha

de

ese

momento.

Así

es

muy

típico

el

uso: Calendar ahoramismo

= Calendar.getInstance(); Calendar tiene 2 métodos de funcionamiento, lo que se llama “lenient” o “non-lenient” mode. Es decir modo permisivo o modo no permisivo. Por defecto se trabaja en modo permisivo y esto quiere decir que si configuramos un Calendar como el día 32 de Enero (lo cual sería un error), a la hora de formatear la fecha y por ejemplo imprimirla por pantalla se mostrará el 1 de Febrero. Es decir, con lenient mode Java trata de encontrar una fecha si le es posible aunque hayamos introducido un dato erróneo. Si configuramos el Calendar en modo no permisivo, antes de calcular la fecha más asemejable lanzaría una excepción si algún parámetro sale de su rango permitido. El 32 de enero daría error. El conjunto de métodos “set” permite establecer una fecha, mientras que los métodos “add” y “roll” permiten cambiar las fechas sumando o restando una cantidad. Estos dos últimos métodos fuerzan que los valores para los campos no sobrepasen el mínimo o el máximo del permitido según el calendario. También estos métodos suponen un recálculo inmediato de la fecha tras el cambio de sus valores, cosa que no ocurre con el uso de los métodos set. Por ejemplo imaginemos que tenemos una fecha con los datos siguientes: 31 de Agosto de 2000. Si ahora llamáramos sobre ese objeto Calendar el método add(Calendar.MONTH, 13) lo que hacemos es añadir 13 meses más a la fecha, con lo que tendríamos la fecha 30 de Septiembre del 2001. Observamos que al añadir 13 meses nos vamos al mes siguiente del año siguiente, pero sin saltar ninguna excepción hemos pasado del día 31 al 30, esto es porque add como hemos dicho fuerza los valores para que no sobrepasen del mínimo o máximo del campo correspondiente, en este caso del campo de días.

GREGORIANCALENDAR

Esta clase es una clase concreta de Calendar y que por otro lado es el sistema de calendario estándar en el mundo, al menos en el mundo occidental que comprende Europa, Norte, Centro y SurAmérica y muchos otros países. Por ello es la que vamos a utilizar en nuestro ejemplo a continuación, en donde vamos a ver cómo podemos trabajar con una fecha y realizar cambios sobre ella según nuestro calendario.

EJEMPLO DE USO DE CALENDAR Y GREGORIANCALENDAR En el ejemplo que vamos a dar a continuación veremos cómo se puede usar la clase Calendar y GregorianCalendar para representar una fecha determinada y poder modificarla según el calendario gregoriano:

/* Ejemplo Clase Calendar y GregorianCalendar aprenderaprogramar.com */ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.GregorianCalendar; public class Programa { public static void main (String []args)

{

Calendar c1 = GregorianCalendar.getInstance(); System.out.println("Fecha actual: "+c1.getTime().toLocaleString()); c1.set(2000, Calendar.AUGUST, 31); System.out.println("Fecha 31 Agosto 2000: "+c1.getTime().toLocaleString()); c1.set(Calendar.MONTH, 13); System.out.println("Fecha 13 meses más: "+c1.getTime().toLocaleString()); /* como podremos observar no nos imprimirá la fecha deseada, hemos escrito una incoherencia*/ c1.set(2000, Calendar.AUGUST, 31); /* volvemos a la fecha anterior usando set y empleamos el método add */ c1.add(Calendar.MONTH, 13); /* Añadir 13 meses */ System.out.println("Fecha 13 meses más: "+c1.getTime().toLocaleString()); /*ahora sí es correcto*/ c1.roll(Calendar.HOUR, 25); /* Añadir 25 horas */

System.out.println("Fecha 25 horas más: "+c1.getTime().toLocaleString()); de roll*/ SimpleDateFormat hh:mm:ss");

sdf

=

new

/*uso

SimpleDateFormat("dd/MMMMM/yyyy

System.out.println("Fecha Formateada: "+sdf.format(c1.getTime())); } }

En este caso no mostramos diagrama de clases, ya que tan solo hemos usado nuestra clase principal Programa. El método getTime() nos permite obtener un objeto Date a partir del objeto Calendar y al objeto Date le podemos pedir una representación tipo String con el método toLocaleString(). Al compilar nuestro Programa en BlueJ nos saldrá probablemente un mensaje alertando del uso de métodos deprecados. No le daremos importancia ahora a este hecho. El resultado de ejecución del programa nos devuelve la siguiente salida:

Como podemos observar en la salida, primero hemos impreso la fecha actual del sistema ya que al inicializar nuestro objeto GregorianCalendar con la instrucción: GregorianCalendar.getInstance(); ésta toma por defecto los valores locales y actuales del sistema.

Posteriormente observamos cómo alteramos la fecha con el método set indicándole que queremos establecer que el mes para esa fecha sea el mes 13. Observamos que si utilizamos set de esta manera (errónea, pues no existe ningún mes que sea el 13) lo que hace Java es tratar de buscar la fecha que considera que se ajusta a lo que hemos indicado, pero no siempre lo hará bien o como nosotros pudiéramos esperar. En este caso al indicar que el mes sea el 13 Java nos muestra la fecha 3 de marzo del 2001 lo cual es un resultado “imprevisible” ya que no corresponde a sumarle 13 meses ni a establecer el mes 3. Si escribiéramos 3 en lugar de 13, es decir c1.set(Calendar.MONTH, 3); el resultado obtenido sería 01may-2000 17:22:37, es decir, hemos establecido que el mes de la fecha es el mes 3 (siendo 0 enero, 1 febrero, 2 marzo, 3 abril y 4 mayo). ¿Por qué nos devuelve mayo si el mes 3 es abril? Porque Java busca el mes que le hemos indicado (abril) y comprueba que abril tiene 30 días, como nuestra fecha es día 31 interpreta que hemos cometido un error y busca la fecha más aproximada posible y nos devuelve el 31 de mayo de 2000. Realmente se trata de una incoherencia por nuestra parte tratar de representar un día 31 de abril porque ese día no existe. Fíjate que podemos tener problemas si tenemos activo el lenient mode. Para desactivarlo procedemos de esta manera: c1.setLenient(false); Una vez desactivado al tratar de ejecutar una instrucción como c1.set(Calendar.MONTH, 3); Java detecta que estamos tratando de representar un día 31 de abril y al no existir tal día en lugar de buscar algo asemejable nos devuelve un error (java.lang.IllegalArgumentException: MONTH). Observamos en la salida que utilizando el método add habiendo inicializado otra vez previamente nuestro calendar con la fecha del 31 de agosto del 2000, si sumamos 13 meses nos vamos al 30 de septiembre del 2001, lo cual es correcto. Además el método add nos ha corregido el desvío automáticamente ya que en un Calendario Gregoriano Septiembre tiene 30 días y no 31. Posteriormente vemos el uso del método roll que también añade valores a cierto parámetro, en este caso hemos tratado de añadir 25 horas. ¿Por qué no nos ha añadido 25 horas? Porque para roll el número máximo de horas que se pueden añadir es 23 (si añadiéramos 24 obtendríamos exactamente la misma fecha inicial sin cambios). Con roll, a diferencia de con el método add, no modificamos los parámetros más largos permisibles para un campo. Por tanto no podemos añadir más de 23 horas tratando de modificar una hora ni más de 11 meses tratando de modificar un mes. Es decir, nosotros al añadir 25 horas no aumentamos en un día y una hora con el método roll. Sin embargo con add sí podríamos sumar a nuestro calendario 25 horas porque add no establece una limitación en cuanto al valor máximo admisible. Si hubiéramos escrito c1.roll(Calendar.HOUR, 2); entonces sí se añadirían correctamente dos horas obteniendo como fecha 30-sep-2001 20:05:21.

Para finalizar, comentar el uso de DateFormat que como indicamos en apartados anteriores del curso es la clase utilizada para formatear fechas. Al igual que Calendar, DateFormat es una clase Abstracta y por eso hemos tenido que utilizar una subclase concreta de esta. En este caso hemos usado SimpleDateFormat, a la cual en el constructor le decimos como deseamos el patrón de fechas: new SimpleDateFormat("dd/MMMMM/yyyy hh:mm:ss"); En este caso le hemos introducido que nuestro formato de fecha es dd referente a los días en este caso “30”, MMMMM para que escriba el nombre de los meses en este caso “septiembre”, yyyy para los años en este caso 2001 y hh:mm:ss para las horas, minutos y segundos respectivamente, en nuestro caso 01:59:31. A la hora de la impresión o el formateo se utiliza el método format pasándole como argumento la fecha deseada como objeto Date, por ejemplo: sdf.format(c1.getTime());

CONCLUSIONES Hemos visto el uso de Calendar y GregorianCalendar así como también someramente el formateo de fechas con DateFormat y SimpleDateFormat. Hemos visto cómo podemos fácilmente cambiar un objeto que represente una fecha y las consecuencias que tiene dependiendo del método utilizado y de tener o no activo el lenient mode. El uso de estas clases sólo está indicado si trabajamos con versiones de Java anteriores a la 8. Si trabajamos con Java 8 o superior, se recomienda el uso de las clases incluidas dentro del paquete java.time para el manejo de tiempos y fechas (clases como Clock, Duration, Instant, LocalDate, LocalTime, MonthDay, OffsetDateTime, OffsetTime, Period, Year, YearMonth, ZonedDateTime, ZoneId y ZoneOffset)

Ejemplo de la utilización de la clase Calendar

Java

Publicado el 11 de Febrero del 2013 por Administrador 13.781 visualizaciones desde el 11 de Febrero del 2013. Una media de 154 por semana Código de ejemplo de la utilización de la clase calendar para obtener información sobre la fecha actual, diferencia entre fechas, operaciones con fechas para aumentar o disminuir los días a una fecha, ...

Versión 1

Publicado el 11 de Febrero del 2013

13.784 visualizaciones desde el 11 de Febrero del 2013. Una media de 154 por semana

Forma parte de Rose India import java.util.Date; import java.util.Calendar;

import java.text.SimpleDateFormat;

import java.util.*;

public class CalendarExample {

private static void CalendarTimemethod() {

Date date = Calendar.getInstance().getTime();

System.out.println("La Fecha actual es: " + date);

System.out.println();

}

private static void SimpleDateFormatmethod() {

Calendar date = Calendar.getInstance();

SimpleDateFormat dateformatter = new SimpleDateFormat("E dd/MM/yyyy 'a las' hh:mm:ss a zzz");

System.out.println("La fecha actual en un formato dado: " + dateformatter.format(date.getTime()));

System.out.println();

}

private static void Adddates() {

System.out.println("Realizando operaciones con las fechas del calendario");

// Get today's date

Calendar date = Calendar.getInstance();

Calendar cldr;

SimpleDateFormat dateformatter = new SimpleDateFormat("E dd/MM/yyyy 'a las' hh:mm:ss a zzz");

cldr = (Calendar) date.clone();

cldr.add(Calendar.DAY_OF_YEAR, - (365 * 2));

System.out.println("

Dos años atras era: " +

dateformatter.format(cldr.getTime()));

cldr = (Calendar) date.clone();

cldr.add(Calendar.DAY_OF_YEAR, + 5);

System.out.println("

Cinco días despues de hoy sera: " +

dateformatter.format(cldr.getTime()));

System.out.println();

}

private static void DateDifference() {

System.out.println("Diferencia entre dos fechas");

Date startDate1 = new GregorianCalendar(2005, 02, 25, 14, 00).getTime();

Date endDate1 = new Date();;

long diff = endDate1.getTime() - startDate1.getTime();

System.out.println("

Diferencia entre '" + endDate1 + "' y '" +

startDate1 + "'");

System.out.println("

es de " + (diff / (1000L*60L*60L*24L)) + "

días.");

System.out.println();

}

private static void Getcalendermethods() {

System.out.println("Varios metodos de la clase Calendar:");

Calendar calender = Calendar.getInstance();

System.out.println("Año : " + calender.get(Calendar.YEAR));

System.out.println("Mes (enero es el mes 0)

: " +

calender.get(Calendar.MONTH));

System.out.println("Día del mes

: " +

calender.get(Calendar.DAY_OF_MONTH));

System.out.println("Día de la semana (la semana empieza el domingo) calender.get(Calendar.DAY_OF_WEEK));

System.out.println("Día del año

: " +

calender.get(Calendar.DAY_OF_YEAR));

System.out.println("Semana del año calender.get(Calendar.WEEK_OF_YEAR));

: " +

: " +

System.out.println("Semana del mes

: " +

calender.get(Calendar.WEEK_OF_MONTH));

System.out.println("Día de la semana en el mes : " + calender.get(Calendar.DAY_OF_WEEK_IN_MONTH));

System.out.println("AM PM : " + calender.get(Calendar.AM_PM));

System.out.println("Hora : " + calender.get(Calendar.HOUR_OF_DAY));

System.out.println("Minutos : " + calender.get(Calendar.MINUTE));

System.out.println("Segundos : " + calender.get(Calendar.SECOND));

System.out.println();

}

public static void main(String[] args) {

System.out.println();

CalendarTimemethod();

SimpleDateFormatmethod();

Adddates();

DateDifference();

Getcalendermethods();

}

}

Fecha/Hora actual Calendar es una clase abstracta, por lo que no podemos hacer un new de ella. La forma de obtener una instancia es llamando al método getInstance(), que nos devolverá alguna clase hija de Calendar inicializada con la fecha/hora actual. ?

1

Calendar today = Calendar.getInstance();

2

System.out.println("Today is " + today.getTime());

La clase hija que realmente nos va a devolver este método es GregorianCalendar, correspondiente al calendario estándar para el mundo occidental. Para mostrar la fecha/hora por pantalla, podríamos intentar directamente ?

1

System.out.println("Today is " + today);

pero nos daría una salida que no es muy legible today is java.util.GregorianCalendar[time=1394883514531,areFieldsSet=true,areAl lFieldsSet=true, lenient=true,zone=sun.util.calendar.ZoneInfo[id="Europe/Paris", offset=3600000,dstSavings=3600000,useDaylight=true,transitions=184, lastRule=java.util.SimpleTimeZone[id=Europe/Paris,offset=3600000,dstSa vings=3600000, useDaylight=true,startYear=0,startMode=2, startMonth=2,startDay=1,startDayOfWeek=1,startTime=3600000,startTimeMode=2,endMode=2, endMonth=9,endDay=1,endDayOfWeek=1,endTime=3600000,endTimeMode=2]],firstDayOfWeek=2, minimalDaysInFirstWeek=4,ERA=1,YEAR=2014,MONTH=2,WEEK_OF_YEAR=11,WEEK_ OF_MONTH=2, DAY_OF_MONTH=15,DAY_OF_YEAR=74,DAY_OF_WEEK=7,DAY_OF_WEEK_IN_MONTH=3,AM _PM=1,HOUR=0, HOUR_OF_DAY=12,MINUTE=38,SECOND=34,MILLISECOND=531,ZONE_OFFSET=3600000 ,DST_OFFSET=0] El método getTime() devuelve el Calendar convertido a Date, que nos daría una salida legible por pantalla al pasarlo a System.out.println(), ese es el motivo por el que lo hemos usado today is Sat Mar 15 12:41:10 CET 2014

Fijar una fecha/hora Para obtener un Calendar en una fecha hora concreta tenemos dos opciones. Una de ellas, sabiendo que lo que realmente vamos a obtener es un GregorianCalendar, es hacer un new GregorianCalendar(...) pasando como parámetros el año, mes, día, hora, minuto, segundo. No es necesario pasar todo, ya que GregorianCalendar tiene varios constructores con menos parámetros ?

1

Calendar sameDate = new GregorianCalendar(2010, Calendar.FEBRUARY, 22, 23, 11, 44)

2

System.out.println("Some Date : " + sameDate.getTime());

Es importante tener en cuenta un detalle. Para Calendar los meses van de 0 a 11, es decir, 0 es Enero y 11 es Diciembre. Por ello, en el parámetro correspondiente al mes, si queremos meter Febrero, debemos meter un 1, en vez de un 2 que es los que nos dictaría la costumbre. Para evitar estas confusiones, siempre es bueno usar las constantes que nos define la clase Calendar, como Calendar.FEBRUARY en el ejemplo. La otra opción para obtener un Calendar en una fecha/hora concreta es llamar a su método set() para fijar los campos que queramos cambiar. El método set() admite dos parámetros, uno para identificar el campo concreto a cambiar (año, mes, día, hora, minuto, segundo, milésimas de segundo) y un segundo parámetro que sería el valor a poner. El siguiente código muestra bastantes de las posibilidades ?

1 Calendar sameDate = Calendar.getInstance();

2 3 sameDate.set(Calendar.YEAR, 2010);

4 5 6

// Month. 0 is January, 11 is November sameDate.set(Calendar.MONTH, Calendar.AUGUST); sameDate.set(Calendar.DAY_OF_MONTH, 23);

7 8

// Either 12-hour clock plus AM/PM

9

sameDate.set(Calendar.HOUR, 10);

10

sameDate.set(Calendar.AM_PM, Calendar.PM);

11

// or 24-hour clock

12

sameDate.set(Calendar.HOUR_OF_DAY, 22);

13 14

sameDate.set(Calendar.MINUTE, 36); sameDate.set(Calendar.SECOND, 22);

15 sameDate.set(Calendar.MILLISECOND, 123);

16 17 18

System.out.println("Some Date : " + sameDate.getTime());

Calendar define constantes para todos los nombres de los posibles campos y son estas constantes las que pasamos como primer parámetro. Adviértase que para el mes nuevamente hemos usado las constantes definidas comoCalendar.AUGUST, en vez de directamente un número de mes ( 7 para Agosto ), que puede llevar a confusión. Aparte de los campos evidentes, vemos por ejemplo que la hora se puede fijar de dos formas: 

Pasando una hora de 0 a 11 y pasando el valor AM/PM



Pasando una hora de 0 a 24.

No los mostramos en el ejemplo, pero hay más campos, como día de la semana, semana del año, semana del mes, etc. El día podría fijarse con cualquiera de estas combinaciones (ver API de Calendar). 

YEAR + MONTH + DAY_OF_MONTH



YEAR + MONTH + WEEK_OF_MONTH + DAY_OF_WEEK



YEAR + MONTH + DAY_OF_WEEK_IN_MONTH + DAY_OF_WEEK



YEAR + DAY_OF_YEAR



YEAR + DAY_OF_WEEK + WEEK_OF_YEAR

Fijando los valores de cualquiera de esas combinaciones quedaría perfectamente determinada la fecha. En el ejemplo no hemos metido tantas variantes, nos hemos ido a la más sencilla que es meter YEAR + MONTH + DAY_OF_MONTH

Leer los campos de la fecha/hora Calendar tiene un método get() al que se pasa como parámetro la constante que indica el campo que queremos obtener, es decir, las mismas constantes que se usan en set(). Aparte de los campos evidentes, tenemos campos que puede ser útiles, como el día de la semana (Lunes a Domingo), el número de semana del año, el número de semana del mes, etc. Un ejemplo más o menos completo puede ser el siguiente ?

1 2

Locale locale = Locale.getDefault(); // Locale locale = Locale.GERMAN; Calendar today = Calendar.getInstance();

3 4 System.out.println("Year : " + today.get(Calendar.YEAR));

5 6

System.out.println("Month (0 is January): " + today.get(Calendar.MONTH));

7 8 9

System.out.println("Month (String): " + today.getDisplayName(Calendar.MONTH, Calendar.SHORT, locale));

10 11

System.out.println("Day of Month : " + today.get(Calendar.DAY_OF_MONTH));

12 13 14

System.out.println("Day of Week (0 is Sunday): " + today.get(Calendar.DAY_OF_WEEK));

15 16

System.out .println("Day of Week (String): "

17 + today.getDisplayName(Calendar.DAY_OF_WEEK, Calendar.LONG,

18

locale));

19 20

System.out.println("Week of Year : " + today.get(Calendar.WEEK_OF_YEAR));

21 22 23

System.out .println("Week of Month : " + today.get(Calendar.WEEK_OF_MONTH));

24 25

System.out.println("Day of Year : " + today.get(Calendar.DAY_OF_YEAR));

26 27

System.out.println("24-hour clock : " + today.get(Calendar.HOUR_OF_DAY));

28 29

System.out.println("12-hour clock : " + today.get(Calendar.HOUR));

30 31

System.out.println("AM/PM : " + today.get(Calendar.AM_PM));

32 System.out.println("AM/PM : "

33 + today.getDisplayName(Calendar.AM_PM, Calendar.LONG, locale));

34 35 36

System.out.println("Minutes : " + today.get(Calendar.MINUTE));

37

System.out.println("Seconds : " + today.get(Calendar.SECOND));

38 39

System.out.println("MiliSeconds : " + today.get(Calendar.MILLISECOND));

40 41 42 Hay campos que no requieren explicación detallada, como año, día del mes, minuto, etc. Pero para otros conviene explicar un poco más. Por ejemplo, el día de la semana, el mes o si es am/pm nos devuelven un número entero que quizás no nos guste demasiado. El 0 corresponde a Domingo y el 6 a Sábado, el 0 corresponde a Enero y el 11 a Diciembre, el 0 corresponde a am y el 1 a pm. Para obtener un texto más legible y no decirle al usuario, por ejemplo, que está en el mes 0, Calendar tiene un método getDisplayName() que nos devuelve un texto legible para mes, día de la semana o AM/PM. Este método admite tres parámetros 

Campo del que queremos la cadena visible, Calendar.MONTH, Calendar.DAY_OF_WEEK, Calendar.AM_PM,...



Si queremos una representación larga o corta. Por ejemplo, para Enero podrían ser sólo tres letras Ene o bien Enero con todas sus letras. Para indicar esto debemos pasar como segundo parámetro una de las constantes Calendar.SHORTo Calendar.LONG



El Locale en el que queremos el texto. Este Locale de alguna forma es en qué idioma lo queremos. En mi caso, el Locale por defecto es español y el mes me devolvería Enero, pero si usamos un Locale en Alemán, nos devolvería Januar

El Locale por defecto del sistema operativo se puede obtener con ?

1

Locale locale = Locale.getDefault();

y para otros idiomas, pueden usarse las constantes definidas en Locale ?

1

Locale locale = Locale.GERMAN;

/* Descripcion: Contiene un metodo que Valida si una cadena es un numero entero. author: [email protected] fecha: 06/12/2009 archivo CadenaEnteros.java */ public class CadenaEnteros { //Devuelve true si en una cadena que llega todos son numeros, false en caso contrario

public boolean esEntero(String cad) { for(int i = 0; i