]> source.dussan.org Git - jgit.git/commitdiff
Cache SimpleDateFormat in GitDateParser per locale 93/18093/3
authorMatthias Sohn <matthias.sohn@sap.com>
Tue, 5 Nov 2013 15:57:06 +0000 (16:57 +0100)
committerGerrit Code Review @ Eclipse.org <gerrit@eclipse.org>
Sun, 24 Nov 2013 03:06:08 +0000 (22:06 -0500)
Otherwise switching to another locale yields wrong results when parsing
date strings in GitDateParser. Since the MockSystemReader explicitly
uses english locale the tests need to specify the locale to be used when
parsing date strings.

Bug: 420772
Change-Id: I313ef6b1e9ef3bfb43d929ce34712ebd21f2cd9c
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GarbageCollectCommandTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateParserBadlyFormattedTest.java
org.eclipse.jgit.test/tst/org/eclipse/jgit/util/GitDateParserTest.java
org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/GC.java
org.eclipse.jgit/src/org/eclipse/jgit/util/GitDateParser.java
org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java

index 47ebb6b2a3f71473cbe5be19ab353be5dcaf8692..098f2b3b5d3600b3b2c3d1c8c2636747ac2b30b0 100644 (file)
@@ -49,6 +49,7 @@ import java.util.Properties;
 
 import org.eclipse.jgit.junit.RepositoryTestCase;
 import org.eclipse.jgit.util.GitDateParser;
+import org.eclipse.jgit.util.SystemReader;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -68,7 +69,8 @@ public class GarbageCollectCommandTest extends RepositoryTestCase {
 
        @Test
        public void testGConeCommit() throws Exception {
-               Date expire = GitDateParser.parse("now", null);
+               Date expire = GitDateParser.parse("now", null, SystemReader
+                               .getInstance().getLocale());
                Properties res = git.gc().setExpire(expire).call();
                assertTrue(res.size() == 7);
        }
@@ -83,8 +85,11 @@ public class GarbageCollectCommandTest extends RepositoryTestCase {
                writeTrashFile("b.txt", "a couple of words for gc to pack more 2");
                writeTrashFile("c.txt", "a couple of words for gc to pack more 3");
                git.commit().setAll(true).setMessage("commit3").call();
-               Properties res = git.gc().setExpire(GitDateParser.parse("now", null))
-                               .call();
+               Properties res = git
+                               .gc()
+                               .setExpire(
+                                               GitDateParser.parse("now", null, SystemReader
+                                                               .getInstance().getLocale())).call();
                assertTrue(res.size() == 7);
        }
 }
index e0e99a14c2b679e308ceef74a96807bf165b2a8c..a6af3a51436fb05fb8bddc8478ca568c6c65a054 100644 (file)
@@ -92,7 +92,8 @@ public class GitDateParserBadlyFormattedTest {
                Calendar ref = new GregorianCalendar(SystemReader.getInstance()
                                .getTimeZone(), SystemReader.getInstance().getLocale());
                try {
-                       GitDateParser.parse(dateStr, ref);
+                       GitDateParser.parse(dateStr, ref, SystemReader.getInstance()
+                                       .getLocale());
                        fail("The expected ParseException while parsing '" + dateStr
                                        + "' did not occur.");
                } catch (ParseException e) {
@@ -103,7 +104,8 @@ public class GitDateParserBadlyFormattedTest {
        @Theory
        public void badlyFormattedWithoutRef() {
                try {
-                       GitDateParser.parse(dateStr, null);
+                       GitDateParser.parse(dateStr, null, SystemReader.getInstance()
+                                       .getLocale());
                        fail("The expected ParseException while parsing '" + dateStr
                                        + "' did not occur.");
                } catch (ParseException e) {
index 570f4999dd0830868ab8dfc82ab25fad1c6690b3..518ed53fde07bab287cca1a82e0414c66a08087f 100644 (file)
@@ -72,7 +72,8 @@ public class GitDateParserTest {
                GregorianCalendar cal = new GregorianCalendar(SystemReader
                                .getInstance().getTimeZone(), SystemReader.getInstance()
                                .getLocale());
-               Date parse = GitDateParser.parse("yesterday", cal);
+               Date parse = GitDateParser.parse("yesterday", cal, SystemReader
+                               .getInstance().getLocale());
                cal.add(Calendar.DATE, -1);
                cal.set(Calendar.HOUR_OF_DAY, 0);
                cal.set(Calendar.MINUTE, 0);
@@ -87,7 +88,8 @@ public class GitDateParserTest {
                GregorianCalendar cal = new GregorianCalendar(SystemReader
                                .getInstance().getTimeZone(), SystemReader.getInstance()
                                .getLocale());
-               Date parse = GitDateParser.parse("never", cal);
+               Date parse = GitDateParser.parse("never", cal, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(GitDateParser.NEVER, parse);
                parse = GitDateParser.parse("never", null);
                Assert.assertEquals(GitDateParser.NEVER, parse);
@@ -104,7 +106,8 @@ public class GitDateParserTest {
                                .getLocale());
                cal.setTime(refDate);
 
-               Date parse = GitDateParser.parse("now", cal);
+               Date parse = GitDateParser.parse("now", cal, SystemReader.getInstance()
+                               .getLocale());
                Assert.assertEquals(refDate, parse);
                long t1 = SystemReader.getInstance().getCurrentTime();
                parse = GitDateParser.parse("now", null);
@@ -123,7 +126,8 @@ public class GitDateParserTest {
                                .getLocale());
                cal.setTime(refDate);
 
-               Date parse = GitDateParser.parse("2 weeks ago", cal);
+               Date parse = GitDateParser.parse("2 weeks ago", cal, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(df.parse("2007-02-07 15:35:00 +0100"), parse);
        }
 
@@ -138,7 +142,8 @@ public class GitDateParserTest {
                                .getLocale());
                cal.setTime(refDate);
 
-               Date parse = GitDateParser.parse("2 weeks ago", cal);
+               Date parse = GitDateParser.parse("2 weeks ago", cal, SystemReader.getInstance()
+                               .getLocale());
                Assert.assertEquals(df.parse("2007-02-07 15:35:00 +0100"), parse);
                parse = GitDateParser.parse("3 days 2 weeks ago", cal);
                Assert.assertEquals(df.parse("2007-02-04 15:35:00 +0100"), parse);
@@ -151,7 +156,8 @@ public class GitDateParserTest {
                String dateStr = "2007-02-21 15:35:00 +0100";
                Date exp = SystemReader.getInstance()
                                .getSimpleDateFormat("yyyy-MM-dd HH:mm:ss Z").parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 
@@ -161,7 +167,8 @@ public class GitDateParserTest {
                Date exp = SystemReader.getInstance()
                                .getSimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss Z")
                                .parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 
@@ -170,7 +177,8 @@ public class GitDateParserTest {
                String dateStr = "2007-02-21";
                Date exp = SystemReader.getInstance().getSimpleDateFormat("yyyy-MM-dd")
                                .parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 
@@ -179,7 +187,8 @@ public class GitDateParserTest {
                String dateStr = "2007.02.21";
                Date exp = SystemReader.getInstance().getSimpleDateFormat("yyyy.MM.dd")
                                .parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 
@@ -188,7 +197,8 @@ public class GitDateParserTest {
                String dateStr = "02/21/2007";
                Date exp = SystemReader.getInstance().getSimpleDateFormat("MM/dd/yyyy")
                                .parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 
@@ -197,7 +207,8 @@ public class GitDateParserTest {
                String dateStr = "21.02.2007";
                Date exp = SystemReader.getInstance().getSimpleDateFormat("dd.MM.yyyy")
                                .parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 
@@ -207,7 +218,8 @@ public class GitDateParserTest {
                Date exp = SystemReader.getInstance()
                                .getSimpleDateFormat("EEE MMM dd HH:mm:ss yyyy Z")
                                .parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 
@@ -216,7 +228,8 @@ public class GitDateParserTest {
                String dateStr = "Wed Feb 21 15:35:00 2007";
                Date exp = SystemReader.getInstance()
                                .getSimpleDateFormat("EEE MMM dd HH:mm:ss yyyy").parse(dateStr);
-               Date parse = GitDateParser.parse(dateStr, null);
+               Date parse = GitDateParser.parse(dateStr, null, SystemReader
+                               .getInstance().getLocale());
                Assert.assertEquals(exp, parse);
        }
 }
index 9eaeaa8c149b193337f03c05b0e869aa5501562f..e06ff65ee4564e771df56127f8fc946042291701 100644 (file)
@@ -97,6 +97,7 @@ import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.treewalk.filter.TreeFilter;
 import org.eclipse.jgit.util.FileUtils;
 import org.eclipse.jgit.util.GitDateParser;
+import org.eclipse.jgit.util.SystemReader;
 
 /**
  * A garbage collector for git {@link FileRepository}. Instances of this class
@@ -307,7 +308,8 @@ public class GC {
                                        ConfigConstants.CONFIG_KEY_PRUNEEXPIRE);
                        if (pruneExpireStr == null)
                                pruneExpireStr = PRUNE_EXPIRE_DEFAULT;
-                       expire = GitDateParser.parse(pruneExpireStr, null);
+                       expire = GitDateParser.parse(pruneExpireStr, null, SystemReader
+                                       .getInstance().getLocale());
                        expireAgeMillis = -1;
                }
                if (expire != null)
index 8f4e491de6c484c947c64f4f1757a760ce3b349e..32859c9c58b1f48c9e35db4d66025a325f85b9de 100644 (file)
@@ -49,6 +49,7 @@ import java.util.Calendar;
 import java.util.Date;
 import java.util.GregorianCalendar;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 
 import org.eclipse.jgit.internal.JGitText;
@@ -71,23 +72,40 @@ public class GitDateParser {
        // Since SimpleDateFormat instances are expensive to instantiate they should
        // be cached. Since they are also not threadsafe they are cached using
        // ThreadLocal.
-       private static ThreadLocal<Map<ParseableSimpleDateFormat, SimpleDateFormat>> formatCache = new ThreadLocal<Map<ParseableSimpleDateFormat, SimpleDateFormat>>() {
-               protected Map<ParseableSimpleDateFormat, SimpleDateFormat> initialValue() {
-                       return new HashMap<ParseableSimpleDateFormat, SimpleDateFormat>();
+       private static ThreadLocal<Map<Locale, Map<ParseableSimpleDateFormat, SimpleDateFormat>>> formatCache =
+                       new ThreadLocal<Map<Locale, Map<ParseableSimpleDateFormat, SimpleDateFormat>>>() {
+
+               protected Map<Locale, Map<ParseableSimpleDateFormat, SimpleDateFormat>> initialValue() {
+                       return new HashMap<Locale, Map<ParseableSimpleDateFormat, SimpleDateFormat>>();
                }
        };
 
-       // Gets an instance of a SimpleDateFormat. If there is not already an
-       // appropriate instance in the (ThreadLocal) cache the create one and put in
-       // into the cache
-       private static SimpleDateFormat getDateFormat(ParseableSimpleDateFormat f) {
-               Map<ParseableSimpleDateFormat, SimpleDateFormat> map = formatCache
+       // Gets an instance of a SimpleDateFormat for the specified locale. If there
+       // is not already an appropriate instance in the (ThreadLocal) cache then
+       // create one and put it into the cache.
+       private static SimpleDateFormat getDateFormat(ParseableSimpleDateFormat f,
+                       Locale locale) {
+               Map<Locale, Map<ParseableSimpleDateFormat, SimpleDateFormat>> cache = formatCache
                                .get();
+               Map<ParseableSimpleDateFormat, SimpleDateFormat> map = cache
+                               .get(locale);
+               if (map == null) {
+                       map = new HashMap<ParseableSimpleDateFormat, SimpleDateFormat>();
+                       cache.put(locale, map);
+                       return getNewSimpleDateFormat(f, locale, map);
+               }
                SimpleDateFormat dateFormat = map.get(f);
                if (dateFormat != null)
                        return dateFormat;
+               SimpleDateFormat df = getNewSimpleDateFormat(f, locale, map);
+               return df;
+       }
+
+       private static SimpleDateFormat getNewSimpleDateFormat(
+                       ParseableSimpleDateFormat f, Locale locale,
+                       Map<ParseableSimpleDateFormat, SimpleDateFormat> map) {
                SimpleDateFormat df = SystemReader.getInstance().getSimpleDateFormat(
-                               f.formatStr);
+                               f.formatStr, locale);
                map.put(f, df);
                return df;
        }
@@ -115,9 +133,9 @@ public class GitDateParser {
        }
 
        /**
-        * Parses a string into a {@link Date}. Since this parser also supports
-        * relative formats (e.g. "yesterday") the caller can specify the reference
-        * date. These types of strings can be parsed:
+        * Parses a string into a {@link Date} using the default locale. Since this
+        * parser also supports relative formats (e.g. "yesterday") the caller can
+        * specify the reference date. These types of strings can be parsed:
         * <ul>
         * <li>"never"</li>
         * <li>"now"</li>
@@ -151,6 +169,49 @@ public class GitDateParser {
         */
        public static Date parse(String dateStr, Calendar now)
                        throws ParseException {
+               return parse(dateStr, now, Locale.getDefault());
+       }
+
+       /**
+        * Parses a string into a {@link Date} using the given locale. Since this
+        * parser also supports relative formats (e.g. "yesterday") the caller can
+        * specify the reference date. These types of strings can be parsed:
+        * <ul>
+        * <li>"never"</li>
+        * <li>"now"</li>
+        * <li>"yesterday"</li>
+        * <li>"(x) years|months|weeks|days|hours|minutes|seconds ago"<br>
+        * Multiple specs can be combined like in "2 weeks 3 days ago". Instead of
+        * ' ' one can use '.' to seperate the words</li>
+        * <li>"yyyy-MM-dd HH:mm:ss Z" (ISO)</li>
+        * <li>"EEE, dd MMM yyyy HH:mm:ss Z" (RFC)</li>
+        * <li>"yyyy-MM-dd"</li>
+        * <li>"yyyy.MM.dd"</li>
+        * <li>"MM/dd/yyyy",</li>
+        * <li>"dd.MM.yyyy"</li>
+        * <li>"EEE MMM dd HH:mm:ss yyyy Z" (DEFAULT)</li>
+        * <li>"EEE MMM dd HH:mm:ss yyyy" (LOCAL)</li>
+        * </ul>
+        *
+        * @param dateStr
+        *            the string to be parsed
+        * @param now
+        *            the base date which is used for the calculation of relative
+        *            formats. E.g. if baseDate is "25.8.2012" then parsing of the
+        *            string "1 week ago" would result in a date corresponding to
+        *            "18.8.2012". This is used when a JGit command calls this
+        *            parser often but wants a consistent starting point for calls.<br>
+        *            If set to <code>null</code> then the current time will be used
+        *            instead.
+        * @param locale
+        *            locale to be used to parse the date string
+        * @return the parsed {@link Date}
+        * @throws ParseException
+        *             if the given dateStr was not recognized
+        * @since 3.2
+        */
+       public static Date parse(String dateStr, Calendar now, Locale locale)
+                       throws ParseException {
                dateStr = dateStr.trim();
                Date ret;
 
@@ -161,7 +222,7 @@ public class GitDateParser {
                        return ret;
                for (ParseableSimpleDateFormat f : ParseableSimpleDateFormat.values()) {
                        try {
-                               return parse_simple(dateStr, f);
+                               return parse_simple(dateStr, f, locale);
                        } catch (ParseException e) {
                                // simply proceed with the next parser
                        }
@@ -177,9 +238,10 @@ public class GitDateParser {
        }
 
        // tries to parse a string with the formats supported by SimpleDateFormat
-       private static Date parse_simple(String dateStr, ParseableSimpleDateFormat f)
+       private static Date parse_simple(String dateStr,
+                       ParseableSimpleDateFormat f, Locale locale)
                        throws ParseException {
-               SimpleDateFormat dateFormat = getDateFormat(f);
+               SimpleDateFormat dateFormat = getDateFormat(f, locale);
                dateFormat.setLenient(false);
                return dateFormat.parse(dateStr);
        }
index b6028610bf8f028eb5c70bbe55efc8e4615ddf57..e73f100f96b906a8e7bb8d2228daa7a794cb394b 100644 (file)
@@ -229,6 +229,21 @@ public abstract class SystemReader {
                return new SimpleDateFormat(pattern);
        }
 
+       /**
+        * Returns a simple date format instance as specified by the given pattern.
+        *
+        * @param pattern
+        *            the pattern as defined in
+        *            {@link SimpleDateFormat#SimpleDateFormat(String)}
+        * @param locale
+        *            locale to be used for the {@code SimpleDateFormat}
+        * @return the simple date format
+        * @since 3.2
+        */
+       public SimpleDateFormat getSimpleDateFormat(String pattern, Locale locale) {
+               return new SimpleDateFormat(pattern, locale);
+       }
+
        /**
         * Returns a date/time format instance for the given styles.
         *