Allow configuring date formatters with a fixed time zone By default, the date format used by Gitiles includes the time zone, as that matches git tools. However, some users/administrators may prefer normalizing to a particular timezone so times are directly comparable without doing timezone arithmetic. Allow this arrangement by setting gitiles.fixedTimeZone to a valid Java TimeZone ID. This causes all dates in the UI to be implicitly converted to this timezone, and the now-redundant timezone offset to be dropped from the output. (Server administrators may communicate to their users out-of-band about what the fixed timezone is.) Bug: 48 Change-Id: I11f369471121403d35dae56137fb7fb82a9b10eb
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/DateFormatterBuilder.java b/gitiles-servlet/src/main/java/com/google/gitiles/DateFormatterBuilder.java index 00d7372..e7c0549 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/DateFormatterBuilder.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/DateFormatterBuilder.java
@@ -14,6 +14,7 @@ package com.google.gitiles; +import com.google.common.base.Optional; import com.google.common.collect.Lists; import org.eclipse.jgit.lib.PersonIdent; @@ -48,18 +49,22 @@ public String format(PersonIdent ident) { DateFormat df = getDateFormat(format); - TimeZone tz = ident.getTimeZone(); - if (tz == null) { - tz = SystemReader.getInstance().getTimeZone(); + if (!fixedTz.isPresent()) { + TimeZone tz = ident.getTimeZone(); + if (tz == null) { + tz = SystemReader.getInstance().getTimeZone(); + } + df.setTimeZone(tz); } - df.setTimeZone(tz); return df.format(ident.getWhen()); } } + private final Optional<TimeZone> fixedTz; private final ThreadLocal<List<DateFormat>> dfs; - DateFormatterBuilder() { + DateFormatterBuilder(Optional<TimeZone> fixedTz) { + this.fixedTz = fixedTz; this.dfs = new ThreadLocal<List<DateFormat>>(); } @@ -79,7 +84,12 @@ } DateFormat df = result.get(format.ordinal()); if (df == null) { - df = new SimpleDateFormat(format.fmt + " Z"); + if (fixedTz.isPresent()) { + df = new SimpleDateFormat(format.fmt); + df.setTimeZone(fixedTz.get()); + } else { + df = new SimpleDateFormat(format.fmt + " Z"); + } result.set(format.ordinal(), df); } return result.get(format.ordinal());
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java b/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java index 34503c3..e4de1c0 100644 --- a/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java +++ b/gitiles-servlet/src/main/java/com/google/gitiles/GitilesFilter.java
@@ -21,6 +21,7 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Objects; +import com.google.common.base.Optional; import com.google.common.collect.FluentIterable; import com.google.common.collect.ImmutableMap; import com.google.common.collect.LinkedListMultimap; @@ -50,6 +51,7 @@ import java.util.Arrays; import java.util.Iterator; import java.util.Map; +import java.util.TimeZone; import java.util.regex.Pattern; import javax.servlet.Filter; @@ -423,7 +425,14 @@ private void setDefaultDateFormatterBuilder() { if (dateFormatterBuilder == null) { - dateFormatterBuilder = new DateFormatterBuilder(); + String tzStr = config.getString("gitiles", null, "fixedTimeZone"); + Optional<TimeZone> tz; + if (tzStr == null) { + tz = Optional.absent(); + } else { + tz = Optional.of(TimeZone.getTimeZone(tzStr)); + } + dateFormatterBuilder = new DateFormatterBuilder(tz); } }
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/DateFormatterBuilderTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/DateFormatterBuilderTest.java index c730fa9..915a9ef 100644 --- a/gitiles-servlet/src/test/java/com/google/gitiles/DateFormatterBuilderTest.java +++ b/gitiles-servlet/src/test/java/com/google/gitiles/DateFormatterBuilderTest.java
@@ -16,6 +16,7 @@ import static org.junit.Assert.assertEquals; +import com.google.common.base.Optional; import static com.google.gitiles.DateFormatterBuilder.Format.DEFAULT; import static com.google.gitiles.DateFormatterBuilder.Format.ISO; @@ -30,18 +31,52 @@ public class DateFormatterBuilderTest { @Test public void defaultIncludingTimeZone() throws Exception { - DateFormatterBuilder dfb = new DateFormatterBuilder(); + DateFormatterBuilder dfb = + new DateFormatterBuilder(Optional.<TimeZone> absent()); PersonIdent ident = newIdent("Mon Jan 2 15:04:05 2006", "-0700"); assertEquals("Mon Jan 02 15:04:05 2006 -0700", dfb.create(DEFAULT).format(ident)); } @Test + public void defaultWithUtc() throws Exception { + DateFormatterBuilder dfb = + new DateFormatterBuilder(Optional.of(TimeZone.getTimeZone("UTC"))); + PersonIdent ident = newIdent("Mon Jan 2 15:04:05 2006", "-0700"); + assertEquals("Mon Jan 02 22:04:05 2006", dfb.create(DEFAULT).format(ident)); + } + + @Test + public void defaultWithOtherTimeZone() throws Exception { + DateFormatterBuilder dfb = + new DateFormatterBuilder(Optional.of(TimeZone.getTimeZone("GMT-0400"))); + PersonIdent ident = newIdent("Mon Jan 2 15:04:05 2006", "-0700"); + assertEquals("Mon Jan 02 18:04:05 2006", dfb.create(DEFAULT).format(ident)); + } + + @Test public void isoIncludingTimeZone() throws Exception { - DateFormatterBuilder dfb = new DateFormatterBuilder(); + DateFormatterBuilder dfb = + new DateFormatterBuilder(Optional.<TimeZone> absent()); PersonIdent ident = newIdent("Mon Jan 2 15:04:05 2006", "-0700"); assertEquals("2006-01-02 15:04:05 -0700", dfb.create(ISO).format(ident)); } + @Test + public void isoWithUtc() throws Exception { + DateFormatterBuilder dfb = + new DateFormatterBuilder(Optional.of(TimeZone.getTimeZone("UTC"))); + PersonIdent ident = newIdent("Mon Jan 2 15:04:05 2006", "-0700"); + assertEquals("2006-01-02 22:04:05", dfb.create(ISO).format(ident)); + } + + @Test + public void isoWithOtherTimeZone() throws Exception { + DateFormatterBuilder dfb = + new DateFormatterBuilder(Optional.of(TimeZone.getTimeZone("GMT-0400"))); + PersonIdent ident = newIdent("Mon Jan 2 15:04:05 2006", "-0700"); + assertEquals("2006-01-02 18:04:05", dfb.create(ISO).format(ident)); + } + private PersonIdent newIdent(String whenStr, String tzStr) throws ParseException { whenStr += " " + tzStr; Date when = GitDateParser.parse(whenStr, null);
diff --git a/gitiles-servlet/src/test/java/com/google/gitiles/RepositoryIndexServletTest.java b/gitiles-servlet/src/test/java/com/google/gitiles/RepositoryIndexServletTest.java index e5a821c..dff8f57 100644 --- a/gitiles-servlet/src/test/java/com/google/gitiles/RepositoryIndexServletTest.java +++ b/gitiles-servlet/src/test/java/com/google/gitiles/RepositoryIndexServletTest.java
@@ -16,6 +16,7 @@ import static com.google.gitiles.TestGitilesUrls.URLS; +import com.google.common.base.Optional; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; @@ -28,6 +29,7 @@ import java.io.IOException; import java.util.Map; +import java.util.TimeZone; import javax.servlet.http.HttpServletRequest; @@ -43,7 +45,7 @@ servlet = new RepositoryIndexServlet( new TestGitilesAccess(repo.getRepository()), new DefaultRenderer(), - new DateFormatterBuilder(), + new DateFormatterBuilder(Optional.<TimeZone> absent()), new TimeCache()); }