File commons-net-ftp-leap-year-parsing.patch of Package jakarta-commons-net
Index: src/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java
===================================================================
--- src/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java.orig 2005-12-03 17:05:48.000000000 +0100
+++ src/java/org/apache/commons/net/ftp/parser/FTPTimestampParserImpl.java 2012-03-13 10:30:30.520993343 +0100
@@ -67,44 +67,74 @@
*
*/
public Calendar parseTimestamp(String timestampStr) throws ParseException {
- Calendar now = Calendar.getInstance();
- now.setTimeZone(this.getServerTimeZone());
-
- Calendar working = Calendar.getInstance();
- working.setTimeZone(this.getServerTimeZone());
- ParsePosition pp = new ParsePosition(0);
+ Calendar now = Calendar.getInstance();
+ return parseTimestamp(timestampStr, now);
+ }
- Date parsed = null;
- if (this.recentDateFormat != null) {
- parsed = recentDateFormat.parse(timestampStr, pp);
- }
- if (parsed != null && pp.getIndex() == timestampStr.length())
- {
- working.setTime(parsed);
- working.set(Calendar.YEAR, now.get(Calendar.YEAR));
- if (working.after(now)) {
- working.add(Calendar.YEAR, -1);
- }
- } else {
- pp = new ParsePosition(0);
- parsed = defaultDateFormat.parse(timestampStr, pp);
- // note, length checks are mandatory for us since
- // SimpleDateFormat methods will succeed if less than
- // full string is matched. They will also accept,
- // despite "leniency" setting, a two-digit number as
- // a valid year (e.g. 22:04 will parse as 22 A.D.)
- // so could mistakenly confuse an hour with a year,
- // if we don't insist on full length parsing.
- if (parsed != null && pp.getIndex() == timestampStr.length()) {
- working.setTime(parsed);
- } else {
- throw new ParseException(
- "Timestamp could not be parsed with older or recent DateFormat",
- pp.getIndex());
- }
- }
- return working;
- }
+ /**
+ * If the recentDateFormat member has been defined, try to parse the
+ * supplied string with that. If that parse fails, or if the recentDateFormat
+ * member has not been defined, attempt to parse with the defaultDateFormat
+ * member. If that fails, throw a ParseException.
+ *
+ * This method allows a {@link Calendar} instance to be passed in which represents the
+ * current (system) time.
+ *
+ * @see FTPTimestampParser#parseTimestamp(String)
+ * @param timestampStr The timestamp to be parsed
+ * @param serverTime The current time for the server
+ * @since 1.5
+ */
+ public Calendar parseTimestamp(String timestampStr, Calendar serverTime) throws ParseException {
+ Calendar working = (Calendar) serverTime.clone();
+ working.setTimeZone(getServerTimeZone()); // is this needed?
+
+ Date parsed = null;
+
+ if (recentDateFormat != null) {
+ Calendar now = (Calendar) serverTime.clone();// Copy this, because we may change it
+ now.setTimeZone(this.getServerTimeZone());
+ // Temporarily add the current year to the short date time
+ // to cope with short-date leap year strings.
+ // e.g. Java's DateFormatter will assume that "Feb 29 12:00" refers to
+ // Feb 29 1970 (an invalid date) rather than a potentially valid leap year date.
+ // This is pretty bad hack to work around the deficiencies of the JDK date/time classes.
+ String year = Integer.toString(now.get(Calendar.YEAR));
+ String timeStampStrPlusYear = timestampStr + " " + year;
+ SimpleDateFormat hackFormatter = new SimpleDateFormat(recentDateFormat.toPattern() + " yyyy",
+ recentDateFormat.getDateFormatSymbols());
+ hackFormatter.setLenient(false);
+ hackFormatter.setTimeZone(recentDateFormat.getTimeZone());
+ ParsePosition pp = new ParsePosition(0);
+ parsed = hackFormatter.parse(timeStampStrPlusYear, pp);
+ // Check if we parsed the full string, if so it must have been a short date originally
+ if (parsed != null && pp.getIndex() == timeStampStrPlusYear.length()) {
+ working.setTime(parsed);
+ if (working.after(now)) { // must have been last year instead
+ working.add(Calendar.YEAR, -1);
+ }
+ return working;
+ }
+ }
+
+ ParsePosition pp = new ParsePosition(0);
+ parsed = defaultDateFormat.parse(timestampStr, pp);
+ // note, length checks are mandatory for us since
+ // SimpleDateFormat methods will succeed if less than
+ // full string is matched. They will also accept,
+ // despite "leniency" setting, a two-digit number as
+ // a valid year (e.g. 22:04 will parse as 22 A.D.)
+ // so could mistakenly confuse an hour with a year,
+ // if we don't insist on full length parsing.
+ if (parsed != null && pp.getIndex() == timestampStr.length()) {
+ working.setTime(parsed);
+ } else {
+ throw new ParseException(
+ "Timestamp could not be parsed with older or recent DateFormat",
+ pp.getErrorIndex());
+ }
+ return working;
+ }
/**
* @return Returns the defaultDateFormat.