Add months to a Calendar without modifying the original instance

Asked

Viewed 290 times

1

I am implementing a system in which I set a specific date in a type variable Calendar and then I need to manipulate her.

I would like to take the value of a few months added:

Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.MONTH,4);

What I would like is to take this date added in another variable, which does not affect the Calendar since it is a Singleton class.

1 answer

3


The fact of getInstance() static does not mean that Calendar is a Singleton.

A Singleton means there will be only one instance of the class in the JVM. But getInstance() always returns a new instance:

Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
System.out.println(c1 == c2); // false

The code above prints false, since c1 and c2 are not the same instance. Note that although getInstance() be static, a new instance is always returned.

In this case, the method getInstance() is working with a Static Factory method. Just because there is a static method that returns an instance does not necessarily mean that this instance will be a Singleton.


How to copy an instance

The detail is that getInstance() returns a Calendar which corresponds to the current date and time. That is, c1 and c2 will not have exactly the same values.

If you want to get a new instance with the same values as the original, just copy it using the method clone(). Then you can change the clone at will, without modifying the original:

Calendar calendar = Calendar.getInstance();

// criar outro Calendar, com o mesmo valor do original
Calendar clone = (Calendar) calendar.clone();
clone.add(Calendar.MONTH, 4); // somar 4 meses

With this, the clone can be changed as needed, and the calendar original will not have its value changed.


GregorianCalendar

There was an answer in which the questioner said that he had found a solution, using directly GregorianCalendar. The reply was deleted, but I left this additional explanation as a complement anyway.

GregorianCalendar is a subclass of Calendar, and it’s okay to use it directly if you want to. The detail is that you were probably already using this class without knowing.

This is because Calendar is an abstract class, which means that it is not possible to create instances directly with new Calendar(). So getInstance() actually returns some subclass of Calendar, based on the Locale JVM standard. And in the vast majority of cases* (for almost all locales), the return is a GregorianCalendar:

Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getClass()); // class java.util.GregorianCalendar

Of course you can use GregorianCalendar directly if you want. But you can also continue using getInstance() without problems, and if you want a Calendar is not modified, create copies of it using clone().

* From what I saw in android documentation, GregorianCalendar seems to be the only native subclass. However, in JDK there are other implementations, so some locales may return different subclasses.


java.time

Depending on the version of Anroid, you can also use the bundle java.time (see here requirements to be able to use it). This new date API is much higher than Date and Calendar, and in my opinion, it is very worth migrating your code to use it.

An interesting detail that would help in your case is that all classes are immutable, so any operations (like adding months to a date) always return a new instance. An example with java.time.LocalDate:

LocalDate hoje = LocalDate.now(); // data atual
// somar 4 meses (retorna uma nova instância)
LocalDate maisQuatroMeses = hoje.plusMonths(4);

plusMonths() (and all other methods for summing/subtracting days/months/years) returns a new instance, then the variable hoje will remain the same (there is no need to clone the instance, as we did with Calendar).

Another detail is that in this API there are several different classes to represent dates and times, unlike the previous API, which only has Date and Calendar.

For example, LocalDate represents only the date (day, month and year). There is also LocalTime, to represent hours (only hour, minute, second and fractions of a second), LocalDateTime for date and time, ZonedDateTime to deal with time zones, etc. I suggest you see the oracle tutorial and this question for more details on this API.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.