{"id":51,"date":"2020-09-15T10:00:41","date_gmt":"2020-09-15T00:00:41","guid":{"rendered":"http:\/\/localhost:8000\/?p=51"},"modified":"2020-09-15T10:00:41","modified_gmt":"2020-09-15T00:00:41","slug":"java8-date-time-intro","status":"publish","type":"post","link":"http:\/\/www.cheerfulprogramming.com\/?p=51","title":{"rendered":"Java8 Date Time Intro"},"content":{"rendered":"<p>Why do you need to know about Java 8 date and time classes? In a lot of<br \/>\nJava applications it is necessary to calculate business days, or<br \/>\nmanipulate dates for display or export: eg. calendar events. There is<br \/>\nalso a lot of old Java code which uses the old date and calendar<br \/>\nclasses, that needs to be upgraded for when those classes are no longer<br \/>\nsupported. Furthermore, Java 8 makes working with date and time easier.<\/p>\n<h2>Definitions<\/h2>\n<p>Here are some commonly used terms:<\/p>\n<ul>\n<li><strong>Greenwich Mean Time<\/strong>: abbreviated GMT. This was the zero offset<br \/>\ntimezone. It has now been superseded by Universal Coordinated Time<br \/>\n(see next term) although the two terms are often used<br \/>\ninterchangeably. See<br \/>\n<a href=\"https:\/\/en.wikipedia.org\/wiki\/Greenwich_Mean_Time\">Wikipedia<\/a>.<\/li>\n<li><strong>Coordinated Universal Time<\/strong>: abbreviated UTC. This is zero offset<br \/>\ntimezone but should be used instead of GMT, because it is more<br \/>\nprecise than GMT, and not just to keep the French happy. See<br \/>\n<a href=\"https:\/\/en.wikipedia.org\/wiki\/Coordinated_Universal_Time\">Wikipedia<\/a>.<\/li>\n<\/ul>\n<h2>Storing date and time values<\/h2>\n<h3>ZonedDateTime<\/h3>\n<p>First is <code class=\"\" data-line=\"\">java.time.ZonedDateTime<\/code>. This class lets you represent date and<br \/>\ntime for anywhere in the world, and it knows the daylight savings<br \/>\ntransitions for a great many regions. You can create one by reading the<br \/>\nsystem clock as shown:<\/p>\n<pre><code class=\"\" data-line=\"\">ZonedDateTime now = ZonedDateTime.now();<\/code><\/pre>\n<p>or by parsing an ISO datetime string as shown in the example below,<br \/>\nwhich includes zone offset and region. The format is:<br \/>\n<em>yyyy-MM-dd\\&#8217;T\\&#8217;HH:mm:ss.nnnnnnnnnXXX\\'[\\&#8217;VV\\&#8217;]\\&#8217;<\/em> and is called<br \/>\n<code class=\"\" data-line=\"\">ISO_ZONED_DATE_TIME<\/code> in Java. See the Java 8 Javadoc for<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/format\/DateTimeFormatter.html\">java.time.format.DateTimeFormatter<\/a><br \/>\nfor more information. The three <code class=\"\" data-line=\"\">ZonedDateTime<\/code>s below are equivalent.<\/p>\n<pre><code class=\"\" data-line=\"\">final String australiaDayStr = &quot;2020-01-26T00:00:00.000000000+11:00[Australia\/Sydney]&quot;;\nfinal ZonedDateTime australiaDay1 = ZonedDateTime.parse(australiaDayStr);\nfinal ZonedDateTime australiaDay2 = ZonedDateTime.parse(australiaDayStr, DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&#039;T&#039;HH:mm:ss.nnnnnnnnnXXX&#039;[&#039;VV&#039;]&#039;&quot;));\nfinal ZonedDateTime australiaDay3 = ZonedDateTime.parse(australiaDayStr, DateTimeFormatter.ISO_ZONED_DATE_TIME);<\/code><\/pre>\n<h3>OffsetDateTime<\/h3>\n<p>If you don\\&#8217;t know the zone region for a datetime value, but you still<br \/>\nwant to handle zone offsets then Java provides <code class=\"\" data-line=\"\">java.time.OffsetDateTime<\/code>.<br \/>\nBecause it lacks a zone region, it doesn\\&#8217;t know the daylight savings<br \/>\ntransitions. You can create one by reading the system clock as shown:<\/p>\n<pre><code class=\"\" data-line=\"\">OffsetDateTime now = OffsetDateTime.now();<\/code><\/pre>\n<p>or by parsing an ISO datetime string as shown in the example below,<br \/>\nwhich includes zone offset but not the region. The format is:<br \/>\n<em>yyyy-MM-dd\\&#8217;T\\&#8217;HH:mm:ss.nnnnnnnnnXXX<\/em> and is called<br \/>\n<code class=\"\" data-line=\"\">ISO_OFFSET_DATE_TIME<\/code> in Java. See the Java 8 Javadoc for<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/format\/DateTimeFormatter.html\">java.time.format.DateTimeFormatter<\/a><br \/>\nfor more information. The three OffsetDateTimes below are equivalent.<\/p>\n<pre><code class=\"\" data-line=\"\">final String australiaDayStr = &quot;2020-01-26T00:00:00.000000000+11:00&quot;;\nfinal OffsetDateTime australiaDay1 = OffsetDateTime.parse(australiaDayStr);\nfinal OffsetDateTime australiaDay2 = OffsetDateTime.parse(australiaDayStr, DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&#039;T&#039;HH:mm:ss.nnnnnnnnnXXX&quot;));\nfinal OffsetDateTime australiaDay3 = OffsetDateTime.parse(australiaDayStr, DateTimeFormatter.ISO_OFFSET_DATE_TIME;<\/code><\/pre>\n<p><code class=\"\" data-line=\"\">OffsetDateTime<\/code> is convertable to <code class=\"\" data-line=\"\">ZonedDateTime<\/code> via the method:<\/p>\n<pre><code class=\"\" data-line=\"\">final ZonedDateTime nowZdt = OffsetDateTime.now().toZonedDateTime();<\/code><\/pre>\n<p>but be aware that the converted object will not contain the daylight<br \/>\nsavings transitions because you didn\\&#8217;t supply a zone id! If you want to<br \/>\ninclude the zone id, then use this technique:<\/p>\n<pre><code class=\"\" data-line=\"\">final ZonedDateTime nowZdt = OffsetDateTime.now().atZoneSameInstant(ZoneId.of(&quot;Australia\/Sydney&quot;));<\/code><\/pre>\n<h3>LocalDateTime<\/h3>\n<p>If you don\\&#8217;t need to deal with offsets and regions then Java provides<br \/>\n<code class=\"\" data-line=\"\">java.time.LocalDateTime<\/code>. This class stores dates and times that are not<br \/>\nconnected to a particular place. You can create one by reading the<br \/>\nsystem clock as shown:<\/p>\n<pre><code class=\"\" data-line=\"\">LocalDateTime now = LocalDateTime.now();<\/code><\/pre>\n<p>or by parsing an ISO datetime string as shown in the example below,<br \/>\nwhich includes neither the zone offset nor the region. The format is:<br \/>\n<em>yyyy-MM-dd\\&#8217;T\\&#8217;HH:mm:ss.nnnnnnnnn<\/em> and is called <code class=\"\" data-line=\"\">ISO_LOCAL_DATE_TIME<\/code> in<br \/>\nJava. See the Java 8 Javadoc for<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/format\/DateTimeFormatter.html\">java.time.format.DateTimeFormatter<\/a><br \/>\nfor more information. The three LocalDateTimes below are equivalent.<\/p>\n<pre><code class=\"\" data-line=\"\">final String australiaDayStr = &quot;2020-01-26T00:00:00.000000000&quot;;\nfinal LocalDateTime australiaDay1 = LocalDateTime.parse(australiaDayStr);\nfinal LocalDateTime australiaDay2 = LocalDateTime.parse(australiaDayStr, DateTimeFormatter.ofPattern(&quot;yyyy-MM-dd&#039;T&#039;HH:mm:ss.nnnnnnnnn&quot;));\nfinal LocalDateTime australiaDay3 = LocalDateTime.parse(australiaDayStr, DateTimeFormatter.ISO_LOCAL_DATE_TIME);<\/code><\/pre>\n<p><code class=\"\" data-line=\"\">LocalDateTime<\/code> can be combined with a Zone Id to create a <code class=\"\" data-line=\"\">ZonedDateTime<\/code><br \/>\nvia:<\/p>\n<pre><code class=\"\" data-line=\"\">final LocalDateTime australiaDayLdt = LocalDateTime.parse(&quot;2020-01-26T00:00:00.000000000&quot;);\nfinal ZonedDateTime australiaDayZdt = ZonedDateTime.of(australiaDayLdt, ZoneId.of(&quot;Australia\/Sydney&quot;));<\/code><\/pre>\n<h3>LocalDate and LocalTime<\/h3>\n<p>If you only need to deal with whole days then the <code class=\"\" data-line=\"\">java.time.LocalDate<\/code><br \/>\nclass is very handy. Similarly if you only need to deal with times, then<br \/>\nJava provides the <code class=\"\" data-line=\"\">java.time.LocalTime<\/code> class. Both can be created by<br \/>\nreading the system clock, or by parsing a string in the correct format.<\/p>\n<pre><code class=\"\" data-line=\"\">LocalDate today = LocalDate.now();\nLocalTime now = LocalTime.now();<\/code><\/pre>\n<p>These two classes can be combined with a Zone Id to create a<br \/>\n<code class=\"\" data-line=\"\">ZonedDateTime<\/code>:<\/p>\n<pre><code class=\"\" data-line=\"\">LocalDate australiaDay = LocalDate.parse(&quot;2020-01-26&quot;);\nLocalTime midnight = LocalTime.parse(&quot;00:00:00&quot;);\nZonedDateTime australiaDayZdt = ZonedDateTime.of(australiaDay, midnight, ZoneId.of(&quot;Australia\/Sydney&quot;));<\/code><\/pre>\n<p>Be careful when doing calculations on <code class=\"\" data-line=\"\">LocalDate<\/code> and <code class=\"\" data-line=\"\">LocalTime<\/code>! If you<br \/>\ntry, for example, to calculate the number of hours difference between<br \/>\ntwo <code class=\"\" data-line=\"\">LocalDate<\/code>s, the code might compile but then fail at runtime, because<br \/>\n<code class=\"\" data-line=\"\">LocalDate<\/code> has no hours component and doesn\\&#8217;t know how to work with<br \/>\nthem.<\/p>\n<h3>Instant<\/h3>\n<p>Java represents Unix time with <code class=\"\" data-line=\"\">java.time.Instant<\/code>. Objects of this class<br \/>\nstore the number of seconds since midnight, 1<sup>st<\/sup> Jan 1970 UTC, to<br \/>\nnanosecond (10<sup>-9<\/sup> s) precision. Instants are always in UTC and are not<br \/>\nregion-aware. An instant can be created by reading from the system<br \/>\nclock, parsing a datetime string, or reading in a whole number of<br \/>\nseconds, for example:<\/p>\n<pre><code class=\"\" data-line=\"\">Instant now = Instant.now();\nInstant australiaDayUnix = Instant.parse(&quot;2020-01-25T13:00:00Z&quot;);\nInstant australiaDayUnix2 = Instant.ofEpochSecond(1579957200);<\/code><\/pre>\n<p>Note the use of the capital \\&#8217;Z\\&#8217; at the end of the datetime string on<br \/>\nline 2, which denotes UTC.<\/p>\n<p>An instant can be combined with a Zone Id to create a <code class=\"\" data-line=\"\">ZonedDateTime<\/code> as<br \/>\nshown below:<\/p>\n<pre><code class=\"\" data-line=\"\">ZonedDateTime australiaDayZdt = ZonedDateTime.ofInstant(australiaDayUnix, ZoneId.of(&quot;Australia\/Sydney&quot;));<\/code><\/pre>\n<h3>Test Your Knowledge<\/h3>\n<h4>Question 1<\/h4>\n<p>What happens if you omit the zone information when you try to create a<br \/>\n<code class=\"\" data-line=\"\">ZonedDateTime<\/code>, as shown in the example below?<\/p>\n<pre><code class=\"\" data-line=\"\">ZonedDateTime australiaDay = ZonedDateTime.parse(&quot;2020-01-26T00:00:00&quot;);<\/code><\/pre>\n<p>An exception, <code class=\"\" data-line=\"\">java.time.format.DateTimeParseException<\/code>, is thrown at<br \/>\nruntime. The three components necessary to create a <code class=\"\" data-line=\"\">ZonedDateTime<\/code> are:<\/p>\n<ol>\n<li>date<\/li>\n<li>time<\/li>\n<li>offset<\/li>\n<\/ol>\n<p>The zone region (\\&quot;[Australia\/Sydney]\\&quot;) is actually optional, but<br \/>\nwithout it the <code class=\"\" data-line=\"\">ZonedDateTime<\/code> will not contain the daylight savings<br \/>\ntransitions.<\/p>\n<h4>Question 2<\/h4>\n<p>What happens if the offset is wrong for the region? eg the offset for<br \/>\nSydney during summer is UTC+11:00 but the offset given in the example<br \/>\nbelow is UTC-05:00.<\/p>\n<pre><code class=\"\" data-line=\"\">ZonedDateTime weird = ZonedDateTime.parse(&quot;2020-01-26T00:00:00-05:00[Australia\/Sydney]&quot;);<\/code><\/pre>\n<p>A <code class=\"\" data-line=\"\">ZonedDateTime<\/code> is created! Java uses the region to decide what the<br \/>\noffset should be and adjusts the time accordingly. So in the above<br \/>\nexample:<\/p>\n<ol>\n<li>The time is first taken at the offset (UTC-05:00).<\/li>\n<li>\n<p>The time is then adjusted for the region rules, which say the offset<br \/>\nshould be UTC+11:00:<\/p>\n<p><sup>+<\/sup>11 hours &#8211; <sup>&#8211;<\/sup>5 hours = <sup>+<\/sup>16 hours to adjust by.<\/p>\n<p>So the resulting <code class=\"\" data-line=\"\">ZonedDateTime<\/code> is equivalent to:<\/p>\n<\/li>\n<\/ol>\n<pre><code class=\"\" data-line=\"\">ZonedDateTime.parse(&quot;2020-01-26T16:00:00+11:00[Australia\/Sydney]&quot;);<\/code><\/pre>\n<h2>Manipulating Dates and Times<\/h2>\n<p>Suppose you want to watch the final stage of Le Tour de France. At the<br \/>\ntime of writing (Tuesday 15<sup>th<\/sup> Sep 2020), the race starts at 11:30 pm<br \/>\nthis Sunday, Sydney time. You could do that many ways, but here is one<br \/>\nway that illustrates a few of the classes that we\\&#8217;ve already discussed:<\/p>\n<pre><code class=\"\" data-line=\"\">import java.time.DayOfWeek;\nimport java.time.LocalDate;\nimport java.time.ZonedDateTime;\nimport java.time.ZoneId;\n...\nZonedDateTime tdfFinalSydney = LocalDate.now()\n    .with(TemporalAdjusters.next(DayOfWeek.SUNDAY))\n    .atTime(23,30,0)\n    .atZone(ZoneId.of(&quot;Australia\/Sydney&quot;));<\/code><\/pre>\n<p>Line 1 starts with today\\&#8217;s date in a LocalDate object. Line 2 then uses<br \/>\nJava\\&#8217;s very handy<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/temporal\/TemporalAdjusters.html\">TemporalAdjusters<\/a><br \/>\nclass with the <code class=\"\" data-line=\"\">DayOfWeek.SUNDAY<\/code> enum to advance the date to this Sunday.<br \/>\n<code class=\"\" data-line=\"\">TemporalAdjusters<\/code> provides methods to calculate the next and previous<br \/>\ndays of the week, the first and last days of the month and the year, and<br \/>\nthe first date of next year, amongst others. Do check it out. Line 3<br \/>\nthen adds a time component in 24 h time, which is 11:30 pm. This method<br \/>\nreturns a LocalDateTime object. Finally, line 4 adds a zone component to<br \/>\ninternationalise the date and time in a <code class=\"\" data-line=\"\">ZonedDateTime<\/code> object. The<br \/>\nclasses <code class=\"\" data-line=\"\">LocalDate<\/code>, <code class=\"\" data-line=\"\">LocalTime<\/code>, <code class=\"\" data-line=\"\">LocalDateTime<\/code>, <code class=\"\" data-line=\"\">OffsetDateTime<\/code>, and<br \/>\n<code class=\"\" data-line=\"\">ZonedDateTime<\/code> share a lot of methods in common and can be transformed<br \/>\nfrom one to the other, so it is very easy work with them once you learn<br \/>\nthe patterns.<\/p>\n<p>Note here that the Java 8 date and time objects are immutable! Each of<br \/>\nthe methods which operates on a Java 8 date or time object (in the<br \/>\n<code class=\"\" data-line=\"\">java.time<\/code> package), such as is shown in the example above, creates a new<br \/>\nobject and returns it. In the four lines of code above, we performed<br \/>\nfour operations and created four new objects, although we only retained<br \/>\nthe last one created. This design seems strange compared to the old Java<br \/>\n<code class=\"\" data-line=\"\">Date<\/code> and <code class=\"\" data-line=\"\">Calendar<\/code> classes, but it actually simplifies the programming<br \/>\nmodel greatly, and lends itself towards a functional programming style<br \/>\nof working, which is the direction that Java has been going recently.<\/p>\n<h3>When is the Final of Le Tour De France, Paris Time?<\/h3>\n<p>Now suppose that you have a friend in Paris and that you had planned to<br \/>\nwatch the race together. You would calculate the correct time in Paris<br \/>\nfor the start of the race as follows:<\/p>\n<pre><code class=\"\" data-line=\"\">import java.time.ZonedDateTime;\nimport java.time.ZoneId;\n...\nZonedDateTime tdfFinalParis = tdfFinalSydney.withZoneSameInstant(ZoneId.of(&quot;Europe\/Paris&quot;));<\/code><\/pre>\n<p>You can prove that two objects <code class=\"\" data-line=\"\">tdfFinalSydney<\/code> and <code class=\"\" data-line=\"\">tdfFinalParis<\/code>, which<br \/>\nrepresent the start of the race in Sydney and Paris respectively,<br \/>\nrepresent the same moment in time and have no time difference between<br \/>\nthem. Java provides at least two ways to do this, first using the<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/temporal\/ChronoUnit.html\">ChronoUnit.HOURS<\/a><br \/>\nenum:<\/p>\n<pre><code class=\"\" data-line=\"\">import org.junit.jupiter.api.Assertions; \/\/only import this in a JUnit test, not in your main code!\nimport java.time.temporal.ChronoUnit;\nimport java.time.ZonedDateTime;\n...\nfinal long difference = ChronoUnit.HOURS.between(tdfFinalParis, tdfFinalSydney);\nAssertions.assertEquals(0, difference);<\/code><\/pre>\n<p>and secondly using the<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/Duration.html\">Duration<\/a><br \/>\nclass as follows:<\/p>\n<pre><code class=\"\" data-line=\"\">import org.junit.jupiter.api.Assertions; \/\/only import this in a JUnit test, not in your main code!\nimport java.time.Duration;\nimport java.time.ZonedDateTime;\n...\nDuration difference = Duration.between(tdfFinalParis, tdfFinalSydney);\nAssertions.assertEquals(0, difference.getSeconds());<\/code><\/pre>\n<h3>Be Careful!<\/h3>\n<p>Both the between methods above accept objects that implement the<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/temporal\/Temporal.html\">Temporal<\/a><br \/>\ninterface, which includes instances of the date and time classes we have<br \/>\nalready introduced. Be careful, however, because not all of those<br \/>\nclasses will work here, even if the code compiles! For example, if you<br \/>\ntry to calculate the difference between two <code class=\"\" data-line=\"\">LocalDate<\/code> objects as a<br \/>\n<code class=\"\" data-line=\"\">Duration<\/code>, you will get an <code class=\"\" data-line=\"\">UnsupportedTemporalTypeException<\/code> at runtime,<br \/>\nwith a message \\&quot;Unsupported unit: Seconds\\&quot;, because <code class=\"\" data-line=\"\">LocalDate<\/code> is does<br \/>\nnot have a time component and does not know what seconds are. eg:<\/p>\n<pre><code class=\"\" data-line=\"\">import org.junit.jupiter.api.Assertions; \/\/only import this in a JUnit test, not in your main code!\nimport java.time.Duration;\nimport java.time.LocalDate;\nimport java.time.temporal.UnsupportedTemporalTypeException;\n...\nAssertions.assertThrows(UnsupportedTemporalTypeException.class, () -&gt; {\n    LocalDate today = LocalDate.now();\n    LocalDate tomorrow = today.plusDays(1);\n    Duration.between(today, tomorrow); \/\/throws here!\n});<\/code><\/pre>\n<p>Similarly, be careful when comparing <code class=\"\" data-line=\"\">Temporal<\/code>s of different implementing<br \/>\nclasses. For example, comparing a <code class=\"\" data-line=\"\">ZonedDateTime<\/code> with a <code class=\"\" data-line=\"\">LocalDateTime<\/code><br \/>\ndoesn\\&#8217;t work with the <code class=\"\" data-line=\"\">ZonedDateTime<\/code> on the left hand side of the<br \/>\ncomparison, because the <code class=\"\" data-line=\"\">LocalDateTime<\/code> doesn\\&#8217;t know about zone regions.<br \/>\neg the following example compiles but fails with a <code class=\"\" data-line=\"\">DateTimeException<\/code>,<br \/>\n\\&quot;Unable to obtain ZonedDateTime from TemporalAccessor&#8230;\\&quot;:<\/p>\n<pre><code class=\"\" data-line=\"\">import org.junit.jupiter.api.Assertions; \/\/only import this in a JUnit test, not in your main code!\nimport java.time.DateTimeException;\nimport java.time.Duration;\nimport java.time.LocalDateTime;\nimport java.time.ZonedDateTime;\n...\nAssertions.assertThrows(DateTimeException.class, () -&gt; {\n    ZonedDateTime todayZdt = ZonedDateTime.now();\n    LocalDateTime laterLdt = todayZdt.toLocalDateTime().plusMinutes(1);\n    Duration.between(todayZdt, laterLdt); \/\/ throws here!\n});<\/code><\/pre>\n<p>If you swap the comparison order such that the <code class=\"\" data-line=\"\">LocalDateTime<\/code> is on the<br \/>\nleft hand side, however, the comparison works:<\/p>\n<pre><code class=\"\" data-line=\"\">import org.junit.jupiter.api.Assertions; \/\/only import this in a JUnit test, not in your main code!\nimport java.time.Duration;\nimport java.time.LocalDateTime;\nimport java.time.ZonedDateTime;\n...\nLocalDateTime todayLdt = LocalDateTime.now();\nZonedDateTime laterZdt = todayLdt.plusMinutes(1).atZone(ZoneId.of(&quot;Australia\/Sydney&quot;));\nAssertions.assertEquals(&quot;PT1M&quot;, Duration.between(todayLdt, laterZdt).toString())<\/code><\/pre>\n<h3>Throw a Party, not an Exception!<\/h3>\n<p>Back to Le Tour de France. Suppose you want to generate an invitation<br \/>\nfor a party via your favourite video conferencing application, and send<br \/>\nit to your friend in Paris. The party starts one hour before the race<br \/>\nstarts. Java provides at least three ways for you to do this:<\/p>\n<pre><code class=\"\" data-line=\"\">import java.time.temporal.ChronoUnit;\nimport java.time.Duration;\nimport java.time.ZonedDateTime;\n...\nZonedDateTime zoomPartyParis1 = tdfFinalParis.minusHours(1);\nZonedDateTime zoomPartyParis2 = tdfFinalParis.minus(Duration.ofHours(1));\nZonedDateTime zoomPartyParis3 = tdfFinalParis.minus(1, ChronoUnit.HOURS);<\/code><\/pre>\n<p>The date and time classes have many methods for adding and subtracting<br \/>\ntime, a few of which are shown above. They range from <code class=\"\" data-line=\"\">minusNanos(long)<\/code><br \/>\nto <code class=\"\" data-line=\"\">plusYears(long)<\/code>, as well as general purpose methods which accept a<br \/>\n<a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/java\/time\/Period.html\">Period<\/a><br \/>\n(days, months, years or longer) or a <code class=\"\" data-line=\"\">Duration<\/code> (hours, minutes, seconds,<br \/>\nor shorter), or an arbitrary <code class=\"\" data-line=\"\">ChronoUnit<\/code> (from nanoseconds to millenia).<\/p>\n<p>Now suppose that you want to generate a reminder for the party the day<br \/>\nbefore, so that you have sufficient time to go shopping for drinks and<br \/>\nsnacks. Java provides at least three ways for you to do this:<\/p>\n<pre><code class=\"\" data-line=\"\">import java.time.temporal.ChronoUnit;\nimport java.time.Period;\nimport java.time.ZonedDateTime;\n...\nZonedDateTime zoomPartyReminderParis1 = zoomPartyParis1.minusDays(1);\nZonedDateTime zoomPartyReminderParis2 = zoomPartyParis1.minus(Period.ofDays(1));\nZonedDateTime zoomPartyReminderParis3 = zoomPartyParis1.minus(1, ChronoUnit.DAYS);<\/code><\/pre>\n<h2>Old to New<\/h2>\n<p>When Oracle added the Java 8 date and time classes to the Java standard<br \/>\nlibrary, it deprecated many of the methods in the old <code class=\"\" data-line=\"\">Date<\/code> and <code class=\"\" data-line=\"\">Calendar<\/code><br \/>\nclasses, and also made the old classes aware of some of the new classes,<br \/>\nto enable easy conversion between them. So if you need to support APIs<br \/>\nwhich rely on the old classes, you can still expose the old classes in<br \/>\nyour API while using the new classes underneath. Note, however, that the<br \/>\nnew classes have an entirely different set of methods, so your old code<br \/>\nwill need to be reengineered heavily. Java lets you convert between old<br \/>\nand new classes as shown in the example below, with <code class=\"\" data-line=\"\">Date<\/code> being replaced<br \/>\nby <code class=\"\" data-line=\"\">Instant<\/code>:<\/p>\n<pre><code class=\"\" data-line=\"\">import java.util.Date;\nimport java.time.Instant;\n...\nDate now = Date.from(Instant.now());\nInstant now2 = new Date().toInstant();<\/code><\/pre>\n<p>and <code class=\"\" data-line=\"\">GregorianCalendar<\/code> being replaced by <code class=\"\" data-line=\"\">ZonedDateTime<\/code>:<\/p>\n<pre><code class=\"\" data-line=\"\">import java.util.GregorianCalendar;\nimport java.time.ZonedDateTime;\n...\nGregorianCalendar tdfFinalSydneyGregorian = GregorianCalendar.from(tdfFinalSydney);\nZonedDateTime tdfFinalSydney2 = tdfFinalSydneyGregorian.toZonedDateTime();<\/code><\/pre>\n<h2>Further Reading<\/h2>\n<p>Sierra, Bates, and Robson, <em>OCP Java SE 8 Programmer II Exam Guide<\/em>,<br \/>\nOracle Press, 2018, pp.207-220<\/p>\n<p><a href=\"https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/\">https:\/\/docs.oracle.com\/javase\/8\/docs\/api\/<\/a><\/p>\n<h2>Acknowledgements<\/h2>\n<p>The author acknowledges the traditional custodians of the Daruk and the<br \/>\nEora People and pays respect to the Elders past and present.<\/p>\n<p>Oracle\u00ae and Java are registered trademarks of Oracle and\/or its<br \/>\naffiliates.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Why do you need to know about Java 8 date and time classes? In a lot of Java applications it is necessary to calculate business days, or manipulate dates for display or export: eg. calendar events. There is also a lot of old Java code which uses the old date and calendar classes, that needs [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":52,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[8,9,11,17,18],"class_list":["post-51","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-java","tag-calendar","tag-date","tag-java","tag-time","tag-timezone"],"_links":{"self":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/posts\/51","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=51"}],"version-history":[{"count":0,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/posts\/51\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=\/wp\/v2\/media\/52"}],"wp:attachment":[{"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=51"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=51"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/www.cheerfulprogramming.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=51"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}