458757: DateUtility: add additional truncation methods 

Change-Id: I693e83961524df2230224590c0dad9226966f60f
Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=458757
Reviewed-on: https://git.eclipse.org/r/40643
Tested-by: Hudson CI
Reviewed-by: Andi Bur <andi.bur@gmail.com>
diff --git a/org.eclipse.scout.commons.test/src/org/eclipse/scout/commons/DateUtilityTest.java b/org.eclipse.scout.commons.test/src/org/eclipse/scout/commons/DateUtilityTest.java
index a45edb4..1033ae4 100644
--- a/org.eclipse.scout.commons.test/src/org/eclipse/scout/commons/DateUtilityTest.java
+++ b/org.eclipse.scout.commons.test/src/org/eclipse/scout/commons/DateUtilityTest.java
@@ -33,6 +33,7 @@
  * </p>
  */
 public class DateUtilityTest {
+  private static final String DATE_FORMAT_COMPLETE = "yyyy-MM-dd HH:mm:ss.SSS";
   private static final String EXPEC_DATE_1970_01_01_000000 = "1970-01-01_00:00:00.000";
   private static final String EXPEC_DATE_1970_01_01_003000 = "1970-01-01_00:30:00.000";
   private static final String EXPEC_DATE_1970_01_01_010000 = "1970-01-01_01:00:00.000";
@@ -719,4 +720,166 @@
 
     assertEquals(DateUtility.isWeekend(todayCalendar.getTime()), DateUtility.isWeekend(todayCalendar.getTime(), Locale.getDefault()));
   }
+
+  @Test
+  public void testTruncDateToHalfYear() {
+    assertNull(DateUtility.truncDateToHalfYear(null));
+
+    // 1. half year
+    assertDateEquals("2015-01-01 00:00:00.000", DateUtility.truncDateToHalfYear(dateOf("2015-01-01 00:00:00.000")));
+    assertDateEquals("2015-01-01 00:00:00.000", DateUtility.truncDateToHalfYear(dateOf("2015-06-30 23:59:59.999")));
+
+    // 2. half year
+    assertDateEquals("2015-07-01 00:00:00.000", DateUtility.truncDateToHalfYear(dateOf("2015-07-01 00:00:00.000")));
+    assertDateEquals("2015-07-01 00:00:00.000", DateUtility.truncDateToHalfYear(dateOf("2015-12-31 23:59:59.999")));
+
+    // leap year
+    assertDateEquals("2012-01-01 00:00:00.000", DateUtility.truncDateToHalfYear(dateOf("2012-02-29 15:30:53.458")));
+  }
+
+  @Test
+  public void testTruncCalendarToHalfYear() {
+    DateUtility.truncCalendarToHalfYear(null);
+
+    Calendar cal = calendarOf("2015-01-01 00:00:00.000");
+    DateUtility.truncCalendarToHalfYear(cal);
+    assertCalendarEquals("2015-01-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-06-30 23:59:59.999");
+    DateUtility.truncCalendarToHalfYear(cal);
+    assertCalendarEquals("2015-01-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-07-01 00:00:00.000");
+    DateUtility.truncCalendarToHalfYear(cal);
+    assertCalendarEquals("2015-07-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-12-31 23:59:59.999");
+    DateUtility.truncCalendarToHalfYear(cal);
+    assertCalendarEquals("2015-07-01 00:00:00.000", cal);
+  }
+
+  @Test
+  public void testTruncDateToQuarter() {
+    assertNull(DateUtility.truncDateToQuarter(null));
+
+    // 1. quarter
+    assertDateEquals("2015-01-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-01-01 00:00:00.000")));
+    assertDateEquals("2015-01-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-03-31 23:59:59.999")));
+
+    // 2. quarter
+    assertDateEquals("2015-04-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-04-01 00:00:00.000")));
+    assertDateEquals("2015-04-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-06-30 23:59:59.999")));
+
+    // 3. quarter
+    assertDateEquals("2015-07-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-07-01 00:00:00.000")));
+    assertDateEquals("2015-07-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-09-30 23:59:59.999")));
+
+    // 4. quarter
+    assertDateEquals("2015-10-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-10-01 00:00:00.000")));
+    assertDateEquals("2015-10-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2015-12-31 23:59:59.999")));
+
+    // leap year
+    assertDateEquals("2012-01-01 00:00:00.000", DateUtility.truncDateToQuarter(dateOf("2012-02-29 15:30:53.458")));
+  }
+
+  @Test
+  public void testTruncCalendarToQuarter() {
+    DateUtility.truncCalendarToQuarter(null);
+
+    // 1. quarter
+    Calendar cal = calendarOf("2015-01-01 00:00:00.000");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-01-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-03-30 23:59:59.999");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-01-01 00:00:00.000", cal);
+
+    // 2. quarter
+    cal = calendarOf("2015-04-01 00:00:00.000");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-04-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-06-30 23:59:59.999");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-04-01 00:00:00.000", cal);
+
+    // 3. quarter
+    cal = calendarOf("2015-07-01 00:00:00.000");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-07-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-09-30 23:59:59.999");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-07-01 00:00:00.000", cal);
+
+    // 4. quarter
+    cal = calendarOf("2015-10-01 00:00:00.000");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-10-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-12-31 23:59:59.999");
+    DateUtility.truncCalendarToQuarter(cal);
+    assertCalendarEquals("2015-10-01 00:00:00.000", cal);
+  }
+
+  @Test
+  public void testTruncDateToHour() {
+    assertNull(DateUtility.truncDateToHour(null));
+    assertDateEquals("2015-01-01 00:00:00.000", DateUtility.truncDateToHour(dateOf("2015-01-01 00:00:00.000")));
+    assertDateEquals("2015-01-01 18:00:00.000", DateUtility.truncDateToHour(dateOf("2015-01-01 18:17:25.831")));
+    assertDateEquals("2015-01-01 23:00:00.000", DateUtility.truncDateToHour(dateOf("2015-01-01 23:59:59.999")));
+  }
+
+  @Test
+  public void testTruncCalendarToHour() {
+    DateUtility.truncCalendarToHour(null);
+
+    Calendar cal = calendarOf("2015-01-01 00:00:00.000");
+    DateUtility.truncCalendarToHour(cal);
+    assertCalendarEquals("2015-01-01 00:00:00.000", cal);
+
+    cal = calendarOf("2015-01-01 18:17:25.831");
+    DateUtility.truncCalendarToHour(cal);
+    assertCalendarEquals("2015-01-01 18:00:00.000", cal);
+
+    cal = calendarOf("2015-01-01 23:59:59.999");
+    DateUtility.truncCalendarToHour(cal);
+    assertCalendarEquals("2015-01-01 23:00:00.000", cal);
+  }
+
+  public static void assertDateEquals(String expectedDate, Date date) {
+    assertEquals(expectedDate, stringOf(date));
+  }
+
+  public static void assertCalendarEquals(String expectedDate, Calendar cal) {
+    assertDateEquals(expectedDate, DateUtility.convertCalendar(cal));
+  }
+
+  /**
+   * Parses the given string into a {@link Calendar}.
+   *
+   * @param dateString
+   *          staring representation using format yyyy-MM-dd HH:mm:ss.SSS
+   */
+  public static Calendar calendarOf(String dateString) {
+    return DateUtility.convertDate(dateOf(dateString));
+  }
+
+  /**
+   * Parses the given string into a {@link Date}.
+   *
+   * @param dateString
+   *          staring representation using format yyyy-MM-dd HH:mm:ss.SSS
+   */
+  public static Date dateOf(String dateString) {
+    return DateUtility.parse(dateString, DATE_FORMAT_COMPLETE);
+  }
+
+  /**
+   * Formats the given date using format yyyy-MM-dd HH:mm:ss.SSS
+   */
+  public static String stringOf(Date date) {
+    return DateUtility.format(date, DATE_FORMAT_COMPLETE);
+  }
 }
diff --git a/org.eclipse.scout.commons/src/org/eclipse/scout/commons/DateUtility.java b/org.eclipse.scout.commons/src/org/eclipse/scout/commons/DateUtility.java
index e5fac77..af7aa64 100644
--- a/org.eclipse.scout.commons/src/org/eclipse/scout/commons/DateUtility.java
+++ b/org.eclipse.scout.commons/src/org/eclipse/scout/commons/DateUtility.java
@@ -190,7 +190,7 @@
     Calendar c = Calendar.getInstance();
     c.setTime(d);
     truncCalendar(c);
-    return new Date(c.getTime().getTime());
+    return c.getTime();
   }
 
   public static Date truncDateToMinute(Date d) {
@@ -201,7 +201,7 @@
     c.setTime(d);
     c.set(Calendar.SECOND, 0);
     c.set(Calendar.MILLISECOND, 0);
-    return new Date(c.getTime().getTime());
+    return c.getTime();
   }
 
   public static Date truncDateToSecond(Date d) {
@@ -211,7 +211,7 @@
     Calendar c = Calendar.getInstance();
     c.setTime(d);
     c.set(Calendar.MILLISECOND, 0);
-    return new Date(c.getTime().getTime());
+    return c.getTime();
   }
 
   /**
@@ -224,7 +224,7 @@
     Calendar c = Calendar.getInstance();
     c.setTime(d);
     truncCalendarToWeek(c, -1);
-    return new Date(c.getTime().getTime());
+    return c.getTime();
   }
 
   /**
@@ -237,7 +237,7 @@
     Calendar c = Calendar.getInstance();
     c.setTime(d);
     truncCalendarToMonth(c);
-    return new Date(c.getTime().getTime());
+    return c.getTime();
   }
 
   /**
@@ -250,13 +250,61 @@
     Calendar c = Calendar.getInstance();
     c.setTime(d);
     truncCalendarToYear(c);
-    return new Date(c.getTime().getTime());
+    return c.getTime();
+  }
+
+  /**
+   * truncate the date to half year (i.e. jan 1 or jul 1 of the given year)
+   *
+   * @since 4.2
+   */
+  public static Date truncDateToHalfYear(Date d) {
+    if (d == null) {
+      return null;
+    }
+    Calendar c = Calendar.getInstance();
+    c.setTime(d);
+    truncCalendarToHalfYear(c);
+    return c.getTime();
+  }
+
+  /**
+   * truncate the date to quarter year (i.e. jan 1, apr 1, jul 1 or oct 1 of the given year)
+   *
+   * @since 4.2
+   */
+  public static Date truncDateToQuarter(Date d) {
+    if (d == null) {
+      return null;
+    }
+    Calendar c = Calendar.getInstance();
+    c.setTime(d);
+    truncCalendarToQuarter(c);
+    return c.getTime();
+  }
+
+  /**
+   * truncate the date to hour
+   *
+   * @since 4.2
+   */
+  public static Date truncDateToHour(Date d) {
+    if (d == null) {
+      return null;
+    }
+    Calendar c = Calendar.getInstance();
+    c.setTime(d);
+    truncCalendarToHour(c);
+    return c.getTime();
   }
 
   /**
    * truncate the calendar to a day with time 00:00:00.000
    */
   public static void truncCalendar(Calendar c) {
+    if (c == null) {
+      return;
+    }
     c.set(Calendar.HOUR_OF_DAY, 0);
     c.set(Calendar.MINUTE, 0);
     c.set(Calendar.SECOND, 0);
@@ -270,6 +318,9 @@
    *          +1 or -1
    */
   public static void truncCalendarToWeek(Calendar c, int adjustIncrement) {
+    if (c == null) {
+      return;
+    }
     if (adjustIncrement < -1) {
       adjustIncrement = -1;
     }
@@ -293,6 +344,9 @@
    * truncate the calendar to month
    */
   public static void truncCalendarToMonth(Calendar c) {
+    if (c == null) {
+      return;
+    }
     c.set(Calendar.DATE, 1);
     c.set(Calendar.HOUR_OF_DAY, 0);
     c.set(Calendar.MINUTE, 0);
@@ -304,6 +358,9 @@
    * truncate the calendar to year
    */
   public static void truncCalendarToYear(Calendar c) {
+    if (c == null) {
+      return;
+    }
     c.set(Calendar.MONTH, Calendar.JANUARY);
     c.set(Calendar.DATE, 1);
     c.set(Calendar.HOUR_OF_DAY, 0);
@@ -313,6 +370,70 @@
   }
 
   /**
+   * truncate the calendar to half year (i.e. jan 1 or jul 1 of the given year)
+   *
+   * @since 4.2
+   */
+  public static void truncCalendarToHalfYear(Calendar c) {
+    if (c == null) {
+      return;
+    }
+    int month = c.get(Calendar.MONTH);
+    truncCalendarToYear(c);
+    if (month >= Calendar.JULY) {
+      c.set(Calendar.MONTH, Calendar.JULY);
+    }
+  }
+
+  /**
+   * truncate the calendar to half year (i.e. jan 1, apr 1, jul 1 or oct 1 of the given year)
+   *
+   * @since 4.2
+   */
+  public static void truncCalendarToQuarter(Calendar c) {
+    if (c == null) {
+      return;
+    }
+    final int month = c.get(Calendar.MONTH);
+    truncCalendarToYear(c);
+    int quarterMonth = Calendar.JANUARY;
+    switch (month) {
+      case Calendar.APRIL:
+      case Calendar.MAY:
+      case Calendar.JUNE:
+        quarterMonth = Calendar.APRIL;
+        break;
+      case Calendar.JULY:
+      case Calendar.AUGUST:
+      case Calendar.SEPTEMBER:
+        quarterMonth = Calendar.JULY;
+        break;
+      case Calendar.OCTOBER:
+      case Calendar.NOVEMBER:
+      case Calendar.DECEMBER:
+        quarterMonth = Calendar.OCTOBER;
+        break;
+    }
+    if (quarterMonth != Calendar.JANUARY) {
+      c.set(Calendar.MONTH, quarterMonth);
+    }
+  }
+
+  /**
+   * truncate the calendar to hour
+   *
+   * @since 4.2
+   */
+  public static void truncCalendarToHour(Calendar c) {
+    if (c == null) {
+      return;
+    }
+    c.set(Calendar.MINUTE, 0);
+    c.set(Calendar.SECOND, 0);
+    c.set(Calendar.MILLISECOND, 0);
+  }
+
+  /**
    * @return true if d is in the range [minDate,maxDate]
    */
   public static boolean isInRange(Date minDate, Date d, Date maxDate) {
@@ -360,7 +481,7 @@
     Calendar c = Calendar.getInstance();
     c.setTime(d);
     c.add(Calendar.DATE, 1);
-    Date dNew = new Date(c.getTime().getTime());
+    Date dNew = c.getTime();
     return dNew;
   }