You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by se...@apache.org on 2014/12/11 14:12:47 UTC

svn commit: r1644626 - /commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java

Author: sebb
Date: Thu Dec 11 13:12:47 2014
New Revision: 1644626

URL: http://svn.apache.org/r1644626
Log:
NET-562 FTPFile.toFormattedString should print only signficant parts of the parsed date
More efficient implementation - only parse format string when it is set up
Ensure formats always set via private setter method
Clear all insignificant fields below the least significant parsed field

Modified:
    commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java

Modified: commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java
URL: http://svn.apache.org/viewvc/commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java?rev=1644626&r1=1644625&r2=1644626&view=diff
==============================================================================
--- commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java (original)
+++ commons/proper/net/trunk/src/main/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java Thu Dec 11 13:12:47 2014
@@ -43,17 +43,107 @@ public class FTPTimestampParserImpl impl
 
     /** The date format for all dates, except possibly recent dates. Assumed to include the year. */
     private SimpleDateFormat defaultDateFormat;
+    /* The index in CALENDAR_UNITS of the smallest time unit in defaultDateFormat */
+    private int defaultDateSmallestUnitIndex;
+
     /** The format used for recent dates (which don't have the year). May be null. */
     private SimpleDateFormat recentDateFormat;
+    /* The index in CALENDAR_UNITS of the smallest time unit in recentDateFormat */
+    private int recentDateSmallestUnitIndex;
+    
     private boolean lenientFutureDates = false;
 
+    /*
+     * List of units in order of increasing significance.
+     * This allows the code to clear all units in the Calendar until it
+     * reaches the least significant unit in the parse string.
+     * The date formats are analysed to find the least significant
+     * unit (e.g. Minutes or Milliseconds) and the appropriate index to
+     * the array is saved.
+     * This is done by searching the array for the unit specifier,
+     * and returning the index. When clearing the Calendar units,
+     * the code loops through the array until the previous entry.
+     * e.g. for MINUTE it would clear MILLISECOND and SECOND
+     */
+    private static final int[] CALENDAR_UNITS = {
+        Calendar.MILLISECOND, 
+        Calendar.SECOND,
+        Calendar.MINUTE, 
+        Calendar.HOUR_OF_DAY,
+        Calendar.DAY_OF_MONTH,
+        Calendar.MONTH,
+        Calendar.YEAR};
+
+    /*
+     * Return the index to the array representing the least significant
+     * unit found in the date format.
+     * Default is 0 (to avoid dropping precision)
+     */
+    private static int getEntry(SimpleDateFormat dateFormat) {
+        if (dateFormat == null) {
+            return 0;
+        }
+        final String FORMAT_CHARS="SsmHdM";
+        final String pattern = dateFormat.toPattern();
+        for(char ch : FORMAT_CHARS.toCharArray()) {
+            if (pattern.indexOf(ch) != -1){ // found the character
+                switch(ch) {
+                case 'S':
+                    return indexOf(Calendar.MILLISECOND);
+                case 's':
+                    return indexOf(Calendar.SECOND);
+                case 'm':
+                    return indexOf(Calendar.MINUTE);
+                case 'H':
+                    return indexOf(Calendar.HOUR_OF_DAY);
+                case 'd':
+                    return indexOf(Calendar.DAY_OF_MONTH);
+                case 'M':
+                    return indexOf(Calendar.MONTH);
+                }
+            }
+        }
+        return 0;
+    }
+
+    /*
+     * Find the entry in the CALENDAR_UNITS array.
+     */
+    private static int indexOf(int calendarUnit) {
+        int i;
+        for(i = 0; i <CALENDAR_UNITS.length; i++) {
+            if (calendarUnit == CALENDAR_UNITS[i]) {
+                return i;
+            }
+        }
+        return 0;
+    }
+
+    /*
+     * Sets the Calendar precision (used by FTPFile#toFormattedDate) by clearing
+     * the units which were not in the format used to parse the date
+     */
+    private static void setPrecision(int index, Calendar working) {
+        int i = 0;
+        for(i = 0; i < index; i++) {
+            final int field = CALENDAR_UNITS[i];
+            // Just in case the analysis is wrong, stop clearing if
+            // field value is not the default.
+            final int value = working.get(field);
+            if (value != 0) {
+// DEBUG:                new Throwable("Unexpected value "+value).printStackTrace();
+                break; // stop clearing any further fields
+            }
+            working.clear(field);
+        }
+    }
 
     /**
      * The only constructor for this class.
      */
     public FTPTimestampParserImpl() {
-        setDefaultDateFormat(DEFAULT_SDF);
-        setRecentDateFormat(DEFAULT_RECENT_SDF);
+        setDefaultDateFormat(DEFAULT_SDF, null);
+        setRecentDateFormat(DEFAULT_RECENT_SDF, null);
     }
 
     /**
@@ -129,7 +219,7 @@ public class FTPTimestampParserImpl impl
                 if (working.after(now)) { // must have been last year instead
                     working.add(Calendar.YEAR, -1);
                 }
-                setPrecision(recentDateFormat, working);
+                setPrecision(recentDateSmallestUnitIndex, working);
                 return working;
             }
         }
@@ -151,39 +241,10 @@ public class FTPTimestampParserImpl impl
                         +serverTime.getTime().toString(),
                     pp.getErrorIndex());
         }
-        setPrecision(defaultDateFormat, working);
+        setPrecision(defaultDateSmallestUnitIndex, working);
         return working;
     }
 
-    private void setPrecision(SimpleDateFormat dateFormat, Calendar working) {
-        final String FORMAT_CHARS="HmsS"; // assume date is always present
-        String pattern = dateFormat.toPattern();
-        char lastChar=0;
-        for(char ch : FORMAT_CHARS.toCharArray()) {
-            if (pattern.indexOf(ch) == -1){
-                lastChar = ch;
-                break;
-            }
-        }
-        if (lastChar == 0) { // matched the lot
-            return;
-        }
-        switch(lastChar) {
-        case 'S':
-            working.clear(Calendar.MILLISECOND);
-            break;
-        case 's':
-            working.clear(Calendar.SECOND);
-            break;
-        case 'm':
-            working.clear(Calendar.MINUTE);
-            break;
-        case 'H':
-            working.clear(Calendar.HOUR_OF_DAY);
-            break;
-        }
-    }
-
     /**
      * @return Returns the defaultDateFormat.
      */
@@ -197,13 +258,21 @@ public class FTPTimestampParserImpl impl
         return defaultDateFormat.toPattern();
     }
     /**
-     * @param defaultDateFormat The defaultDateFormat to be set.
+     * @param format The defaultDateFormat to be set.
+     * @param dfs the symbols to use (may be null)
      */
-    private void setDefaultDateFormat(String format) {
+    private void setDefaultDateFormat(String format, DateFormatSymbols dfs) {
         if (format != null) {
-            this.defaultDateFormat = new SimpleDateFormat(format);
+            if (dfs != null) {
+                this.defaultDateFormat = new SimpleDateFormat(format, dfs);
+            } else {
+                this.defaultDateFormat = new SimpleDateFormat(format);                
+            }
             this.defaultDateFormat.setLenient(false);
+        } else {
+            this.defaultDateFormat = null;
         }
+        this.defaultDateSmallestUnitIndex = getEntry(this.defaultDateFormat);
     }
     /**
      * @return Returns the recentDateFormat.
@@ -218,13 +287,21 @@ public class FTPTimestampParserImpl impl
         return recentDateFormat.toPattern();
     }
     /**
-     * @param recentDateFormat The recentDateFormat to set.
+     * @param format The recentDateFormat to set.
+     * @param dfs the symbols to use (may be null)
      */
-    private void setRecentDateFormat(String format) {
+    private void setRecentDateFormat(String format, DateFormatSymbols dfs) {
         if (format != null) {
-            this.recentDateFormat = new SimpleDateFormat(format);
+            if (dfs != null) {
+                this.recentDateFormat = new SimpleDateFormat(format, dfs);
+            } else {
+                this.recentDateFormat = new SimpleDateFormat(format);
+            }
             this.recentDateFormat.setLenient(false);
+        } else {
+            this.recentDateFormat = null;
         }
+        this.recentDateSmallestUnitIndex = getEntry(this.recentDateFormat);
     }
 
     /**
@@ -297,19 +374,13 @@ public class FTPTimestampParserImpl impl
 
 
         String recentFormatString = config.getRecentDateFormatStr();
-        if (recentFormatString == null) {
-            this.recentDateFormat = null;
-        } else {
-            this.recentDateFormat = new SimpleDateFormat(recentFormatString, dfs);
-            this.recentDateFormat.setLenient(false);
-        }
+        setRecentDateFormat(recentFormatString, dfs);
 
         String defaultFormatString = config.getDefaultDateFormatStr();
         if (defaultFormatString == null) {
             throw new IllegalArgumentException("defaultFormatString cannot be null");
         }
-        this.defaultDateFormat = new SimpleDateFormat(defaultFormatString, dfs);
-        this.defaultDateFormat.setLenient(false);
+        setDefaultDateFormat(defaultFormatString, dfs);
 
         setServerTimeZone(config.getServerTimeZoneId());