Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -591,7 +591,7 @@ public String getPattern() {
* This zone is always used for {@link Date} formatting.
* </p>
*
* @return The time zone.
* @return A copy of the time zone, changing it has no effect on this formatter.
*/
@Override
public TimeZone getTimeZone() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -940,7 +940,8 @@ protected FastDateParser(final String pattern, final TimeZone timeZone, final Lo
*/
protected FastDateParser(final String pattern, final TimeZone timeZone, final Locale locale, final Date centuryStart) {
this.pattern = Objects.requireNonNull(pattern, "pattern");
this.timeZone = Objects.requireNonNull(timeZone, "timeZone");
// TimeZone is mutable and instances are shared through the FastDateFormat cache.
this.timeZone = (TimeZone) Objects.requireNonNull(timeZone, "timeZone").clone();
this.locale = LocaleUtils.toLocale(locale);
final Calendar definingCalendar = Calendar.getInstance(timeZone, this.locale);
final int centuryStartYear;
Expand Down Expand Up @@ -1108,7 +1109,7 @@ private Strategy getStrategy(final char f, final int width, final Calendar defin
*/
@Override
public TimeZone getTimeZone() {
return timeZone;
return (TimeZone) timeZone.clone();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,8 @@ static String getTimeZoneDisplay(final TimeZone tz, final boolean daylight, fina
*/
protected FastDatePrinter(final String pattern, final TimeZone timeZone, final Locale locale) {
this.pattern = pattern;
this.timeZone = timeZone;
// TimeZone is mutable and instances are shared through the FastDateFormat cache.
this.timeZone = (TimeZone) timeZone.clone();
this.locale = LocaleUtils.toLocale(locale);
init();
}
Expand Down Expand Up @@ -1304,7 +1305,7 @@ public String getPattern() {
*/
@Override
public TimeZone getTimeZone() {
return timeZone;
return (TimeZone) timeZone.clone();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -478,4 +478,32 @@ void testTimeDefaults() {
assertEquals(FastDateFormat.getTimeInstance(FastDateFormat.LONG),
FastDateFormat.getTimeInstance(FastDateFormat.LONG, TimeZone.getDefault(), Locale.getDefault()));
}

/**
* Mutating the TimeZone passed to the factory must not change the cached, shared instance.
*/
@Test
void testTimeZoneArgumentIsCopied() throws ParseException {
final TimeZone timeZone = TimeZones.getTimeZone("UTC");
final FastDateFormat printer = FastDateFormat.getInstance("yyyy-MM-dd HH:mm Z", timeZone, Locale.US);
final FastDateFormat parser = FastDateFormat.getInstance("yyyy-MM-dd HH:mm", timeZone, Locale.US);
timeZone.setRawOffset(5 * 3_600_000);
assertEquals(TimeZones.getTimeZone("UTC"), printer.getTimeZone());
assertEquals("1970-01-01 00:00 +0000", printer.format(new Date(0)));
assertEquals(new Date(0), parser.parse("1970-01-01 00:00"));
}

/**
* Mutating the TimeZone returned by the getter must not change the cached, shared instance.
*/
@Test
void testTimeZoneGetterReturnsCopy() throws ParseException {
final FastDateFormat printer = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss Z", TimeZones.getTimeZone("UTC"), Locale.US);
final FastDateFormat parser = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss", TimeZones.getTimeZone("UTC"), Locale.US);
printer.getTimeZone().setRawOffset(5 * 3_600_000);
parser.getTimeZone().setRawOffset(5 * 3_600_000);
assertEquals(TimeZones.getTimeZone("UTC"), printer.getTimeZone());
assertEquals("1970-01-01 00:00:00 +0000", printer.format(new Date(0)));
assertEquals(new Date(0), parser.parse("1970-01-01 00:00:00"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,20 @@ void testSpecialCharacters(final TriFunction<String, TimeZone, Locale, DateParse
testSdfAndFdp(dpProvider, "yyyy-MM-dd 'QED'", "2003-02-10 qed", true);
}

/**
* Mutating the TimeZone passed to the constructor or returned by the getter must not change the parser.
*/
@Test
void testTimeZoneIsCopied() throws ParseException {
final TimeZone timeZone = TimeZones.getTimeZone("UTC");
final FastDateParser parser = new FastDateParser("yyyy-MM-dd HH:mm", timeZone, Locale.US);
timeZone.setRawOffset(5 * 3_600_000);
assertEquals(new Date(0), parser.parse("1970-01-01 00:00"));
parser.getTimeZone().setRawOffset(5 * 3_600_000);
assertEquals(TimeZones.getTimeZone("UTC"), parser.getTimeZone());
assertEquals(new Date(0), parser.parse("1970-01-01 00:00"));
}

@Test
@ReadsDefaultLocale
void testTimeZoneMatches() {
Expand Down
Loading