Archiv für den Monat: März 2014

The new Date and Time API in Java 8 (JSR310) in practice

Since the beginning of my developer carrier I had to deal with dates and times. Software for public energy distributer has to handle always with time series including any kind of calculation and manipulation.

Last week at the JUGF I heart an introduction about the new features in Java 8. One of the added features is the new Date and Time API (JSR 310). To get known about this new API I decided to refactor parts of a date utility class.

As in introduction into the new API I used the tutorial provided by Oracle.

Some of the new features that I discovered:

  • Date objects are now immutable like BigDecimal
    If any operations are performed on the date objects a new object will be created
  • You have to decide if you want to have a date object without time (LocalDate) or with time (LocalDateTime)
  • LocalDate and LocalDateTime can be easily converted between each other
  • It’s much more complicated to find out, if a date object is in DST or not
  • There are now Enums and not only constants for month and day of week. But in java.util.Calendar JANUARY has the value 0 and in java.time.Month JANUARY has the value 1! So be cautious if you rewrite your code.

Formatting and Parsing

Prior to Java 8 formatting of java.util.Date was done using the non thread-safe java.util.Formatter. It was not encouraged to hold instances of the Formatter in a static variable. With the new date and time API a DateTimeFormatter class is introduced. A quote from the Java tutorial:

The DateTimeFormatter class is both immutable and thread-safe; it can (and should) be assigned to a static constant where appropriate.

For parsing and formatting form and to a String the classes LocalDate and LocalDateTime provide parse and format method. As a parameter you need to specify an instance of DateTimeFormatter. This class has some predefined formatter but you can also define your own pattern with the syntax known from the “old” java.util.SimpleDateFormat.

Some code snippets

Creating date objects with time 0 o’clock is really simple.

LocalDate friday = LocalDate.of(2014, Month.FEBRUARY, 28);

compared to

Calendar friday = Calendar.getInstance();
friday.set(2014, Calendar.FEBRUARY, 28, 0, 0, 0);
friday.set(Calendar.MILLISECOND, 0);

In the next sample a more advanced function will be compared. My date utility class has a function to create a new date object with the last day of the same month as the given date. Here is the original code with java util.Calendar:

    /**
     * Creates a new date object with the last day of the same month as the
     * given date.
     */
    public static Calendar endOfMonth(Calendar cal) {
      Calendar result = Calendar.getInstance();
      result.setTimeInMillis(cal.getTimeInMillis());
      result.add(Calendar.MONTH, 1);
      result.set(Calendar.DAY_OF_MONTH, 1);
      setTimeToZero(result);
      result.add(Calendar.DAY_OF_MONTH, -1);
      return result;
    }

In Java the same result looks like this:

    public static LocalDate endOfMonth(LocalDate date) {
      return date.withDayOfMonth(date.lengthOfMonth());
    }

In the next sample the Enum DayOfWeek is used to calculate the previous working day to the given day:

    /**
     * The methods calculates the previous working day. It only recognize
     * Saturday and Sunday as non -working days.
     *
     * @param date
     *            Date as starting point for the calculation, cannot be null
     * @return The previous working day
     */
    public static LocalDate getPreviousWorkingDay(LocalDate date) {
      DayOfWeek dayOfWeek = DayOfWeek.of(date.get(ChronoField.DAY_OF_WEEK));
      switch (dayOfWeek) {
        case MONDAY:
          return date.minus(3, ChronoUnit.DAYS);
        case SUNDAY:
          return date.minus(2, ChronoUnit.DAYS);
        default:
          return date.minus(1, ChronoUnit.DAYS);
      }
    }

With the old java.util.Calendar the code is more verbose:

    public static Calendar getPreviousWorkingDay(Calendar cal) {
      Calendar result = Calendar.getInstance();
      result.setTimeInMillis(cal.getTimeInMillis());
      int dayOfWeek = cal.get(Calendar.DAY_OF_WEEK);
      switch (dayOfWeek) {
        case Calendar.MONDAY:
          result.set(Calendar.DAY_OF_MONTH,
            cal.get(Calendar.DAY_OF_MONTH) - 3);
          break;
        case Calendar.SUNDAY:
          result.set(Calendar.DAY_OF_MONTH,
            cal.get(Calendar.DAY_OF_MONTH) - 2);
          break;
        default:
          result.set(Calendar.DAY_OF_MONTH,
            cal.get(Calendar.DAY_OF_MONTH) - 1);
      }
      return result;
    }

The full source code including complete JUnit tests can be found on Github.