commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bay...@apache.org
Subject svn commit: r795597 - in /commons/proper/lang/trunk/src: java/org/apache/commons/lang/time/DateUtils.java test/org/apache/commons/lang/time/DateUtilsTest.java
Date Sun, 19 Jul 2009 19:21:05 GMT
Author: bayard
Date: Sun Jul 19 19:21:04 2009
New Revision: 795597

URL: http://svn.apache.org/viewvc?rev=795597&view=rev
Log:
Applying Robert Scholte's patch to Travis Reeder's request for a DateUtils.ceiling(...) method
to complete truncate(...) and round(...) in LANG-434

Modified:
    commons/proper/lang/trunk/src/java/org/apache/commons/lang/time/DateUtils.java
    commons/proper/lang/trunk/src/test/org/apache/commons/lang/time/DateUtilsTest.java

Modified: commons/proper/lang/trunk/src/java/org/apache/commons/lang/time/DateUtils.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/java/org/apache/commons/lang/time/DateUtils.java?rev=795597&r1=795596&r2=795597&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/java/org/apache/commons/lang/time/DateUtils.java (original)
+++ commons/proper/lang/trunk/src/java/org/apache/commons/lang/time/DateUtils.java Sun Jul
19 19:21:04 2009
@@ -31,7 +31,7 @@
  * 
  * <p>DateUtils contains a lot of common methods considering manipulations
  * of Dates or Calendars. Some methods require some extra explanation.
- * The truncate and round methods could be considered the Math.floor(),
+ * The truncate, ceiling and round methods could be considered the Math.floor(),
  * Math.ceil() or Math.round versions for dates
  * This way date-fields will be ignored in bottom-up order.
  * As a complement to these methods we've introduced some fragment-methods.
@@ -125,6 +125,25 @@
      * A month range, the week starting on Monday.
      */
     public final static int RANGE_MONTH_MONDAY = 6;
+    
+    /**
+     * Constant marker for truncating 
+     * @since 3.0
+     */
+    public final static int MODIFY_TRUNCATE = 0;
+
+    /**
+     * Constant marker for rounding
+     * @since 3.0
+     */
+    public final static int MODIFY_ROUND = 1;
+    
+    /**
+     * Constant marker for ceiling
+     * @since 3.0
+     */
+    public final static int MODIFY_CEILING= 2;
+    
 
     /**
      * <p><code>DateUtils</code> instances should NOT be constructed in
@@ -584,7 +603,7 @@
         }
         Calendar gval = Calendar.getInstance();
         gval.setTime(date);
-        modify(gval, field, true);
+        modify(gval, field, MODIFY_ROUND);
         return gval.getTime();
     }
 
@@ -621,7 +640,7 @@
             throw new IllegalArgumentException("The date must not be null");
         }
         Calendar rounded = (Calendar) date.clone();
-        modify(rounded, field, true);
+        modify(rounded, field, MODIFY_ROUND);
         return rounded;
     }
 
@@ -691,7 +710,7 @@
         }
         Calendar gval = Calendar.getInstance();
         gval.setTime(date);
-        modify(gval, field, false);
+        modify(gval, field, MODIFY_TRUNCATE);
         return gval.getTime();
     }
 
@@ -716,7 +735,7 @@
             throw new IllegalArgumentException("The date must not be null");
         }
         Calendar truncated = (Calendar) date.clone();
-        modify(truncated, field, false);
+        modify(truncated, field, MODIFY_TRUNCATE);
         return truncated;
     }
 
@@ -752,6 +771,91 @@
             throw new ClassCastException("Could not truncate " + date);
         }
     }
+    
+  //-----------------------------------------------------------------------
+    /**
+     * <p>Ceil this date, leaving the field specified as the most
+     * significant field.</p>
+     *
+     * <p>For example, if you had the datetime of 28 Mar 2002
+     * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
+     * 2002 13:00:00.000.  If this was passed with MONTH, it would
+     * return 1 Mar 2002 0:00:00.000.</p>
+     * 
+     * @param date  the date to work with
+     * @param field  the field from <code>Calendar</code>
+     *  or <code>SEMI_MONTH</code>
+     * @return the rounded date
+     * @throws IllegalArgumentException if the date is <code>null</code>
+     * @throws ArithmeticException if the year is over 280 million
+     */
+    public static Date ceiling(Date date, int field) {
+        if (date == null) {
+            throw new IllegalArgumentException("The date must not be null");
+        }
+        Calendar gval = Calendar.getInstance();
+        gval.setTime(date);
+        modify(gval, field, MODIFY_CEILING);
+        return gval.getTime();
+    }
+
+    /**
+     * <p>Ceil this date, leaving the field specified as the most
+     * significant field.</p>
+     *
+     * <p>For example, if you had the datetime of 28 Mar 2002
+     * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
+     * 2002 13:00:00.000.  If this was passed with MONTH, it would
+     * return 1 Mar 2002 0:00:00.000.</p>
+     * 
+     * @param date  the date to work with
+     * @param field  the field from <code>Calendar</code>
+     *  or <code>SEMI_MONTH</code>
+     * @return the rounded date (a different object)
+     * @throws IllegalArgumentException if the date is <code>null</code>
+     * @throws ArithmeticException if the year is over 280 million
+     */
+    public static Calendar ceiling(Calendar date, int field) {
+        if (date == null) {
+            throw new IllegalArgumentException("The date must not be null");
+        }
+        Calendar ceiled = (Calendar) date.clone();
+        modify(ceiled, field, MODIFY_CEILING);
+        return ceiled;
+    }
+
+    /**
+     * <p>Ceil this date, leaving the field specified as the most
+     * significant field.</p>
+     *
+     * <p>For example, if you had the datetime of 28 Mar 2002
+     * 13:45:01.231, if you passed with HOUR, it would return 28 Mar
+     * 2002 13:00:00.000.  If this was passed with MONTH, it would
+     * return 1 Mar 2002 0:00:00.000.</p>
+     * 
+     * @param date  the date to work with, either <code>Date</code>
+     *  or <code>Calendar</code>
+     * @param field  the field from <code>Calendar</code>
+     *  or <code>SEMI_MONTH</code>
+     * @return the rounded date
+     * @throws IllegalArgumentException if the date
+     *  is <code>null</code>
+     * @throws ClassCastException if the object type is not a
+     *  <code>Date</code> or <code>Calendar</code>
+     * @throws ArithmeticException if the year is over 280 million
+     */
+    public static Date ceiling(Object date, int field) {
+        if (date == null) {
+            throw new IllegalArgumentException("The date must not be null");
+        }
+        if (date instanceof Date) {
+            return ceiling((Date) date, field);
+        } else if (date instanceof Calendar) {
+            return ceiling((Calendar) date, field).getTime();
+        } else {
+            throw new ClassCastException("Could not find ceiling of for type: " + date.getClass());
+        }
+    }
 
     //-----------------------------------------------------------------------
     /**
@@ -759,10 +863,10 @@
      * 
      * @param val  the calendar
      * @param field  the field constant
-     * @param round  true to round, false to truncate
+     * @param modType  type to truncate, round or ceiling
      * @throws ArithmeticException if the year is over 280 million
      */
-    private static void modify(Calendar val, int field, boolean round) {
+    private static void modify(Calendar val, int field, int modType) {
         if (val.get(Calendar.YEAR) > 280000000) {
             throw new ArithmeticException("Calendar value too large for accurate calculations");
         }
@@ -783,7 +887,7 @@
 
         // truncate milliseconds
         int millisecs = val.get(Calendar.MILLISECOND);
-        if (!round || millisecs < 500) {
+        if (MODIFY_TRUNCATE == modType || millisecs < 500) {
             time = time - millisecs;
         }
         if (field == Calendar.SECOND) {
@@ -792,7 +896,7 @@
 
         // truncate seconds
         int seconds = val.get(Calendar.SECOND);
-        if (!done && (!round || seconds < 30)) {
+        if (!done && (MODIFY_TRUNCATE == modType || seconds < 30)) {
             time = time - (seconds * 1000L);
         }
         if (field == Calendar.MINUTE) {
@@ -801,7 +905,7 @@
 
         // truncate minutes
         int minutes = val.get(Calendar.MINUTE);
-        if (!done && (!round || minutes < 30)) {
+        if (!done && (MODIFY_TRUNCATE == modType || minutes < 30)) {
             time = time - (minutes * 60000L);
         }
 
@@ -817,7 +921,7 @@
             for (int j = 0; j < fields[i].length; j++) {
                 if (fields[i][j] == field) {
                     //This is our field... we stop looping
-                    if (round && roundUp) {
+                    if (modType == MODIFY_CEILING || (modType == MODIFY_ROUND &&
roundUp)) {
                         if (field == DateUtils.SEMI_MONTH) {
                             //This is a special case that's hard to generalize
                             //If the date is 1, we round up to 16, otherwise

Modified: commons/proper/lang/trunk/src/test/org/apache/commons/lang/time/DateUtilsTest.java
URL: http://svn.apache.org/viewvc/commons/proper/lang/trunk/src/test/org/apache/commons/lang/time/DateUtilsTest.java?rev=795597&r1=795596&r2=795597&view=diff
==============================================================================
--- commons/proper/lang/trunk/src/test/org/apache/commons/lang/time/DateUtilsTest.java (original)
+++ commons/proper/lang/trunk/src/test/org/apache/commons/lang/time/DateUtilsTest.java Sun
Jul 19 19:21:04 2009
@@ -763,7 +763,7 @@
                 dateTimeParser.parse("February 4, 2002 00:00:00.000"),
                 DateUtils.round((Object) calAmPm4, Calendar.AM_PM));
         
-        // Fix for http://issues.apache.org/bugzilla/show_bug.cgi?id=25560
+        // Fix for http://issues.apache.org/bugzilla/show_bug.cgi?id=25560 / LANG-13
         // Test rounding across the beginning of daylight saving time
         TimeZone.setDefault(zone);
         dateTimeParser.setTimeZone(zone);
@@ -1156,6 +1156,243 @@
         // restore default time zone
         TimeZone.setDefault(defaultZone);
     }
+    
+    /**
+     * Tests various values with the ceiling method
+     */
+    public void testCeil() throws Exception {
+    	// tests public static Date ceiling(Date date, int field)
+    	assertEquals("ceiling year-1 failed",
+                dateParser.parse("January 1, 2003"),
+                DateUtils.ceiling(date1, Calendar.YEAR));
+        assertEquals("ceiling year-2 failed",
+                dateParser.parse("January 1, 2002"),
+                DateUtils.ceiling(date2, Calendar.YEAR));
+        assertEquals("ceiling month-1 failed",
+                dateParser.parse("March 1, 2002"),
+                DateUtils.ceiling(date1, Calendar.MONTH));
+        assertEquals("ceiling month-2 failed",
+                dateParser.parse("December 1, 2001"),
+                DateUtils.ceiling(date2, Calendar.MONTH));
+        assertEquals("ceiling semimonth-1 failed",
+                dateParser.parse("February 16, 2002"),
+                DateUtils.ceiling(date1, DateUtils.SEMI_MONTH));
+        assertEquals("ceiling semimonth-2 failed",
+                dateParser.parse("December 1, 2001"),
+                DateUtils.ceiling(date2, DateUtils.SEMI_MONTH));
+        assertEquals("ceiling date-1 failed",
+                dateParser.parse("February 13, 2002"),
+                DateUtils.ceiling(date1, Calendar.DATE));
+        assertEquals("ceiling date-2 failed",
+                dateParser.parse("November 19, 2001"),
+                DateUtils.ceiling(date2, Calendar.DATE));
+        assertEquals("ceiling hour-1 failed",
+                dateTimeParser.parse("February 12, 2002 13:00:00.000"),
+                DateUtils.ceiling(date1, Calendar.HOUR));
+        assertEquals("ceiling hour-2 failed",
+                dateTimeParser.parse("November 18, 2001 2:00:00.000"),
+                DateUtils.ceiling(date2, Calendar.HOUR));
+        assertEquals("ceiling minute-1 failed",
+                dateTimeParser.parse("February 12, 2002 12:35:00.000"),
+                DateUtils.ceiling(date1, Calendar.MINUTE));
+        assertEquals("ceiling minute-2 failed",
+                dateTimeParser.parse("November 18, 2001 1:24:00.000"),
+                DateUtils.ceiling(date2, Calendar.MINUTE));
+        assertEquals("ceiling second-1 failed",
+                dateTimeParser.parse("February 12, 2002 12:34:57.000"),
+                DateUtils.ceiling(date1, Calendar.SECOND));
+        assertEquals("ceiling second-2 failed",
+                dateTimeParser.parse("November 18, 2001 1:23:12.000"),
+                DateUtils.ceiling(date2, Calendar.SECOND));
+        assertEquals("ceiling ampm-1 failed",
+                dateTimeParser.parse("February 3, 2002 12:00:00.000"),
+                DateUtils.ceiling(dateAmPm1, Calendar.AM_PM));
+        assertEquals("ceiling ampm-2 failed",
+                dateTimeParser.parse("February 3, 2002 12:00:00.000"),
+                DateUtils.ceiling(dateAmPm2, Calendar.AM_PM));
+        assertEquals("ceiling ampm-3 failed",
+                dateTimeParser.parse("February 4, 2002 00:00:00.000"),
+                DateUtils.ceiling(dateAmPm3, Calendar.AM_PM));
+        assertEquals("ceiling ampm-4 failed",
+                dateTimeParser.parse("February 4, 2002 00:00:00.000"),
+                DateUtils.ceiling(dateAmPm4, Calendar.AM_PM));
+        
+     // tests public static Date ceiling(Object date, int field)
+        assertEquals("ceiling year-1 failed",
+                dateParser.parse("January 1, 2003"),
+                DateUtils.ceiling((Object) date1, Calendar.YEAR));
+        assertEquals("ceiling year-2 failed",
+                dateParser.parse("January 1, 2002"),
+                DateUtils.ceiling((Object) date2, Calendar.YEAR));
+        assertEquals("ceiling month-1 failed",
+                dateParser.parse("March 1, 2002"),
+                DateUtils.ceiling((Object) date1, Calendar.MONTH));
+        assertEquals("ceiling month-2 failed",
+                dateParser.parse("December 1, 2001"),
+                DateUtils.ceiling((Object) date2, Calendar.MONTH));
+        assertEquals("ceiling semimonth-1 failed",
+                dateParser.parse("February 16, 2002"),
+                DateUtils.ceiling((Object) date1, DateUtils.SEMI_MONTH));
+        assertEquals("ceiling semimonth-2 failed",
+                dateParser.parse("December 1, 2001"),
+                DateUtils.ceiling((Object) date2, DateUtils.SEMI_MONTH));
+        assertEquals("ceiling date-1 failed",
+                dateParser.parse("February 13, 2002"),
+                DateUtils.ceiling((Object) date1, Calendar.DATE));
+        assertEquals("ceiling date-2 failed",
+                dateParser.parse("November 19, 2001"),
+                DateUtils.ceiling((Object) date2, Calendar.DATE));
+        assertEquals("ceiling hour-1 failed",
+                dateTimeParser.parse("February 12, 2002 13:00:00.000"),
+                DateUtils.ceiling((Object) date1, Calendar.HOUR));
+        assertEquals("ceiling hour-2 failed",
+                dateTimeParser.parse("November 18, 2001 2:00:00.000"),
+                DateUtils.ceiling((Object) date2, Calendar.HOUR));
+        assertEquals("ceiling minute-1 failed",
+                dateTimeParser.parse("February 12, 2002 12:35:00.000"),
+                DateUtils.ceiling((Object) date1, Calendar.MINUTE));
+        assertEquals("ceiling minute-2 failed",
+                dateTimeParser.parse("November 18, 2001 1:24:00.000"),
+                DateUtils.ceiling((Object) date2, Calendar.MINUTE));
+        assertEquals("ceiling second-1 failed",
+                dateTimeParser.parse("February 12, 2002 12:34:57.000"),
+                DateUtils.ceiling((Object) date1, Calendar.SECOND));
+        assertEquals("ceiling second-2 failed",
+                dateTimeParser.parse("November 18, 2001 1:23:12.000"),
+                DateUtils.ceiling((Object) date2, Calendar.SECOND));
+        assertEquals("ceiling ampm-1 failed",
+                dateTimeParser.parse("February 3, 2002 12:00:00.000"),
+                DateUtils.ceiling((Object) dateAmPm1, Calendar.AM_PM));
+        assertEquals("ceiling ampm-2 failed",
+                dateTimeParser.parse("February 3, 2002 12:00:00.000"),
+                DateUtils.ceiling((Object) dateAmPm2, Calendar.AM_PM));
+        assertEquals("ceiling ampm-3 failed",
+                dateTimeParser.parse("February 4, 2002 00:00:00.000"),
+                DateUtils.ceiling((Object) dateAmPm3, Calendar.AM_PM));
+        assertEquals("ceiling ampm-4 failed",
+                dateTimeParser.parse("February 4, 2002 00:00:00.000"),
+                DateUtils.ceiling((Object) dateAmPm4, Calendar.AM_PM));
+        
+        assertEquals("ceiling calendar second-1 failed",
+                dateTimeParser.parse("February 12, 2002 12:34:57.000"),
+                DateUtils.ceiling((Object) cal1, Calendar.SECOND));
+        assertEquals("ceiling calendar second-2 failed",
+                dateTimeParser.parse("November 18, 2001 1:23:12.000"),
+                DateUtils.ceiling((Object) cal2, Calendar.SECOND));
+        
+        assertEquals("ceiling ampm-1 failed",
+                dateTimeParser.parse("February 3, 2002 12:00:00.000"),
+                DateUtils.ceiling((Object) calAmPm1, Calendar.AM_PM));
+        assertEquals("ceiling ampm-2 failed",
+                dateTimeParser.parse("February 3, 2002 12:00:00.000"),
+                DateUtils.ceiling((Object) calAmPm2, Calendar.AM_PM));
+        assertEquals("ceiling ampm-3 failed",
+                dateTimeParser.parse("February 4, 2002 00:00:00.000"),
+                DateUtils.ceiling((Object) calAmPm3, Calendar.AM_PM));
+        assertEquals("ceiling ampm-4 failed",
+                dateTimeParser.parse("February 4, 2002 00:00:00.000"),
+                DateUtils.ceiling((Object) calAmPm4, Calendar.AM_PM));
+
+        try {
+            DateUtils.ceiling((Date) null, Calendar.SECOND);
+            fail();
+        } catch (IllegalArgumentException ex) {}
+        try {
+            DateUtils.ceiling((Calendar) null, Calendar.SECOND);
+            fail();
+        } catch (IllegalArgumentException ex) {}
+        try {
+            DateUtils.ceiling((Object) null, Calendar.SECOND);
+            fail();
+        } catch (IllegalArgumentException ex) {}
+        try {
+            DateUtils.ceiling("", Calendar.SECOND);
+            fail();
+        } catch (ClassCastException ex) {}
+        try {
+            DateUtils.ceiling(date1, -9999);
+            fail();
+        } catch(IllegalArgumentException ex) {}
+
+        
+        // Fix for http://issues.apache.org/bugzilla/show_bug.cgi?id=25560
+        // Test ceiling across the beginning of daylight saving time
+    	TimeZone.setDefault(zone);
+        dateTimeParser.setTimeZone(zone);
+
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling(date4, Calendar.DATE));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling((Object) cal4, Calendar.DATE));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling(date5, Calendar.DATE));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling((Object) cal5, Calendar.DATE));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling(date6, Calendar.DATE));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling((Object) cal6, Calendar.DATE));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling(date7, Calendar.DATE));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 31, 2003 00:00:00.000"),
+                DateUtils.ceiling((Object) cal7, Calendar.DATE));
+        
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 30, 2003 03:00:00.000"),
+                DateUtils.ceiling(date4, Calendar.HOUR_OF_DAY));
+        assertEquals("ceiling MET date across DST change-over",
+                dateTimeParser.parse("March 30, 2003 03:00:00.000"),
+                DateUtils.ceiling((Object) cal4, Calendar.HOUR_OF_DAY));
+        if (SystemUtils.isJavaVersionAtLeast(1.4f)) {
+            assertEquals("ceiling MET date across DST change-over",
+                    dateTimeParser.parse("March 30, 2003 03:00:00.000"),
+                    DateUtils.ceiling(date5, Calendar.HOUR_OF_DAY));
+            assertEquals("ceiling MET date across DST change-over",
+                    dateTimeParser.parse("March 30, 2003 03:00:00.000"),
+                    DateUtils.ceiling((Object) cal5, Calendar.HOUR_OF_DAY));
+            assertEquals("ceiling MET date across DST change-over",
+                    dateTimeParser.parse("March 30, 2003 04:00:00.000"),
+                    DateUtils.ceiling(date6, Calendar.HOUR_OF_DAY));
+            assertEquals("ceiling MET date across DST change-over",
+                    dateTimeParser.parse("March 30, 2003 04:00:00.000"),
+                    DateUtils.ceiling((Object) cal6, Calendar.HOUR_OF_DAY));
+            assertEquals("ceiling MET date across DST change-over",
+                    dateTimeParser.parse("March 30, 2003 04:00:00.000"),
+                    DateUtils.ceiling(date7, Calendar.HOUR_OF_DAY));
+            assertEquals("ceiling MET date across DST change-over",
+                    dateTimeParser.parse("March 30, 2003 04:00:00.000"),
+                    DateUtils.ceiling((Object) cal7, Calendar.HOUR_OF_DAY));
+        } else {
+            this.warn("WARNING: Some date ceiling tests not run since the current version
is " + SystemUtils.JAVA_VERSION);
+        }
+    	TimeZone.setDefault(defaultZone);
+        dateTimeParser.setTimeZone(defaultZone);
+        
+     // Bug 31395, large dates
+        Date endOfTime = new Date(Long.MAX_VALUE); // fyi: Sun Aug 17 07:12:55 CET 292278994
-- 807 millis
+        GregorianCalendar endCal = new GregorianCalendar();
+        endCal.setTime(endOfTime);
+        try {
+            DateUtils.ceiling(endCal, Calendar.DATE);
+            fail();
+        } catch (ArithmeticException ex) {}
+        endCal.set(Calendar.YEAR, 280000001);
+        try {
+            DateUtils.ceiling(endCal, Calendar.DATE);
+            fail();
+        } catch (ArithmeticException ex) {}
+        endCal.set(Calendar.YEAR, 280000000);
+        Calendar cal = DateUtils.ceiling(endCal, Calendar.DATE);
+        assertEquals(0, cal.get(Calendar.HOUR));
+    }
 
     /**
      * Tests the iterator exceptions



Mime
View raw message