F
legacy API problemsThe classes http://docs.oracle.com/javase/10/docs/api/java/util/Date.html and http://docs.oracle.com/javase/10/docs/api/java/util/Calendar.html , as well as the subclasses http://docs.oracle.com/javase/10/docs/api/java/util/GregorianCalendar.html , http://docs.oracle.com/javase/10/docs/api/java/sql/Date.html , http://docs.oracle.com/javase/10/docs/api/java/sql/Time.html and http://docs.oracle.com/javase/10/docs/api/java/sql/Timestamp.html , are notorious for being ill-equipped and because they are difficult classes to use due to the fact that their API has been mis-elaborated. They work properly if they are used with due care, but their code accumulates several bad programming practices and recurring problems that hinder the lives of developers in Java.In addition, these classes are all mutable, which makes them inappropriate to be used in some cases. For example: Date a = ...;
Date d = new Date();
pessoa.setAtualizacao(d); // Define a data de atualização.
// Em algum lugar bem longe do código acima:
d.setTime(1234); // A data de atualização muda magicamente de forma misteriosa.
Another problem in these classes is that they are not thread-safe. Since these classes are changeable, this is even expected. In cases where they do not suffer mutations while being used, this should not cause problems related to thread-safety for most of these classes. But with the class SimpleDateFormat, the situation is different. Share an instance of SimpleDateFormat between several threads will cause unpredictable results even if the instance of SimpleDateFormat do not suffer external changes/changes. This is because during the process of parse or formatting a date, class SimpleDateFormat changes the internal state of itself.That's why in Java 8, new classes were designed to replace them.The new APIFirst, in the new API all classes are immutable and thread-safe. Only that makes them much easier to use. In addition, their API was well-planned, discussed and exercised to stay consistent.The most used classes are as follows: https://docs.oracle.com/javase/10/docs/api/java/time/LocalDate.html - It represents a date with no time and no time zone information. https://docs.oracle.com/javase/10/docs/api/java/time/LocalTime.html - It represents an hour without date information or time zone. https://docs.oracle.com/javase/10/docs/api/java/time/OffsetTime.html - It represents an hour without date information, but with a fixed time zone (does not take into account summer time). https://docs.oracle.com/javase/10/docs/api/java/time/LocalDateTime.html - It represents a date and time, but no time zone. https://docs.oracle.com/javase/10/docs/api/java/time/ZonedDateTime.html - It represents a date and time with time zone that takes into account summer time. https://docs.oracle.com/javase/10/docs/api/java/time/OffsetDateTime.html - Represents a date and time with fixed time zone (does not take into account summer time). https://docs.oracle.com/javase/10/docs/api/java/time/YerMonth.html - It represents a date containing only one month and one year. https://docs.oracle.com/javase/10/docs/api/java/time/Year.html - It represents a date of only one year. https://docs.oracle.com/javase/10/docs/api/java/time/Instant.html - It represents a point in time, with precision of nanoseconds.All of them are interface implementations http://docs.oracle.com/javase/10/docs/api/java/time/temporal/Temporal.html , which specifies the behavior common to all of them. And note that their API is much easier to use than Date or Calendar, has a lot of methods to add dates, check who is before or after, extract certain field (day, month, time, second, etc), convert between one type and another, etc.There are also implementations Temporal more specific for different calendars. See: http://docs.oracle.com/javase/10/docs/api/java/time/chrono/JapaneseDate.html , http://docs.oracle.com/javase/10/docs/api/java/time/chrono/ThaiBuddhistDate.html , http://docs.oracle.com/javase/10/docs/api/java/time/chrono/HijrahDate.html and http://docs.oracle.com/javase/10/docs/api/java/time/chrono/MinguoDate.html . They are analogous to LocalDate, but in specific calendars, and therefore do not have time information or time zone.It is also noted that all of them have a static method now() that builds the object of the corresponding class according to the time of the system. For example:LocalDate hoje = LocalDate.now();
LocalDateTime horaRelogio = LocalDateTime.now();
Instant agora = Instant.now();
Time zones are represented by class https://docs.oracle.com/javase/10/docs/api/java/time/ZoneId.html . An instance that corresponds to ZoneId local machine can be obtained with method https://docs.oracle.com/javase/10/docs/api/java/time/ZoneId.html#systemDefault() . Another way to get instances of ZoneId is by means of the method https://docs.oracle.com/javase/10/docs/api/java/time/ZoneOffset.html#of(java.lang.String) . For example:ZoneId fusoHorarioDaqui = ZoneId.systemDefault();
ZoneId utc = ZoneId.of("Z");
ZoneId utcMais3 = ZoneId.of("+03:00");
ZoneId fusoDeSaoPaulo = ZoneId.of("America/Sao_Paulo");
Note that some time zones are fixed, i.e. not affected by summer time rules, while others, such as ZoneId.of("America/Sao_Paulo"), are affected by summer time.Conversion between Date and the new classesTo convert a Date for an instance of one of the classes of the package java.time, we can do this:Date d = ...;
Instant i = d.toInstant();
ZonedDateTime zdt = i.atZone(ZoneId.systemDefault());
OffsetDateTime odt = zdt.toOffsetDateTime();
LocalDateTime ldt = zdt.toLocalDateTime();
LocalTime lt = zdt.toLocalTime();
LocalDate ld = zdt.toLocalDate();
In the above code, the time zone used is important. Normally you will use the ZoneId.systemDefault() or ZoneId.of("Z")depending on what you're doing. In some cases, you may want to use some other different time zone. If you want to store the time zone in some variable (possibly static) and always (re)use after, there is no problem (including is recommended in many cases).Obviously, there are several other ways to obtain instances of the classes defined above.To convert back to Date:ZonedDateTime zdt = ...;
Instant i2 = zdt.toInstant();
Date.from(i2);
Parse and formatting with StringTo convert any of them to String, you use the class https://docs.oracle.com/javase/10/docs/api/java/time/format/DateTimeFormatter.html . She's the replacement of the SimpleDateFormat. For example:DateTimeFormatter fmt = DateTimeFormatter
.ofPattern("dd/MM/uuuu")
.withResolverStyle(ResolverStyle.STRICT);
LocalDate ld = ...;
String formatado = ld.format(fmt);
The reverse process is done with static methods parse(String, DateTimeFormatter) that each of these classes has. For example:DateTimeFormatter fmt = ...;
String texto = ...;
LocalDate ld = LocalDate.parse(texto, fmt);
A detail to look at is the use of uuuu rather than yyyy in the method ofPattern. The reason for this is that yyyy does not work in case of dates before Christ. Rarely that would matter, but where it doesn't matter, the two work the same, and where it matters, the uuuu should be used. Thus, it has not much sense to use yyyy to the detriment of uuuu. More details https://stackoverflow.com/a/41178418/540552 .Another detail is the http://docs.oracle.com/javase/10/docs/api/java/time/format/DateTimeFormatter.html#withResolverStyle(java.time.format.ResolverStyle) which says what to do with ill-formed dates. There are three possibilities: http://docs.oracle.com/javase/10/docs/api/java/time/format/ResolverStyle.html#STRICT , http://docs.oracle.com/javase/10/docs/api/java/time/format/ResolverStyle.html#SMART and http://docs.oracle.com/javase/10/docs/api/java/time/format/ResolverStyle.html#LENIENT . O STRICT does not allow anything that is not strictly standard. The mode LENIENT allows him to interpret 31/06/2017 as 01/07/2017For example. O SMART tries to guess what is the best way, interpreting 31/06/2017 as 30/06/2017. The default is SMART, but recommend using STRICT always, because it does not tolerate misformed dates and does not try to guess what a misformed date could be. See some tests on this https://ideone.com/sxE5s8 .Conversion CalendarThe legacy class GregorianCalendar is for all effects equivalent to new class ZonedDateTime. The methods https://docs.oracle.com/javase/10/docs/api/java/util/GregorianCalendar.html#from(java.time.ZonedDateTime) and https://docs.oracle.com/javase/10/docs/api/java/util/GregorianCalendar.html#toZonedDateTime() serve to make direct conversion:ZonedDateTime zdt1 = ...;
GregorianCalendar gc = GregorianCalendar.from(zdt1);
ZonedDateTime zdt2 = gc.toZonedDateTime();
Having then the conversion Calendar For ZonedDateTime and vice versa, use the métods described above if you want to get any of the new API objects such as LocalDate or LocalTime.If what you have is an instance of Calendar rather than GregorianCalendar, can almost always make a cast For GregorianCalendar to use the method toZonedDateTime(). If you don't want to use cast, it is possible to convert the Calendar For Instant:Calendar c2 = ...;
Date d2 = c2.getTime();
Instant i2 = d2.toInstant();
It is also possible to build a Calendar from one Instant using Date as intermediary:Instant i = ...;
Date d1 = Date.from(i);
Calendar c = new GregorianCalendar();
c.setTime(d1);
About Joda-TimeThe http://www.joda.org/joda-time/ , it is an API that has been developed for a few years exactly with the intention of replacing the Date and Calendar. And she did it! The package java.time and all classes there are strongly inspired by the Joda-Time, although there are some important differences that aim not to repeat some of the Joda-Time errors.