Hi all,
After discussing with Blake and Gabrielle, I am going with solution [1]
- modifying the getFormattingTimeZone() method to check the date (if
available) and use the corresponding timezone offset.
There will be a new method added to the DateTimeConverter in the API
folder, with the Date an additional argument, and the existing
getFormattingTimeZone() will call this new method.
Please email if you have any questions or concerns with the approach.
Yee-Wah
Yee-wah Lee wrote:
Here is the code relevant to the discussion:
1) DateTimeConverter.java#getFormattingTimeZone(TimeZone tZone)
This effectively creates a timezone with customized id. TimeZone
zone = (TimeZone) tZone.clone();
// set the id as "GMT Sign Hours : Minutes"
StringBuilder zoneId = new StringBuilder(9);
int rawOffset = zone.getRawOffset();
.. code to calculate and append GMT +/- hours:mins
zone.setID(zoneId.toString());
return zone;
2) JDK 1.5: SimpleDateFormat#subFormat()
The 1.5 format code would look up a zone info file using the date's
offset and daylight savings.
case 17: // 'z' - ZONE_OFFSET
int zoneIndex =
formatData.getZoneIndex(calendar.getTimeZone().getID());
if (zoneIndex == -1) {
value = calendar.get(Calendar.ZONE_OFFSET) +
calendar.get(Calendar.DST_OFFSET);
buffer.append(ZoneInfoFile.toCustomID(value));
<---------Uses this code path
}....
3) JDK 6: SimpleDateFormat#subFormat()
The 1.6 code now checks the DateFormatSymbols.locale and
isZoneStringsSet(). By default, the locale would be null and
zoneStringsSet = false unless user overrides either.It then calls
TimeZone.getDisplayName() instead of checking the zoneInfoFile.
case 17: // 'z' - ZONE_OFFSET
if (formatData.locale == null || formatData.isZoneStringsSet) {
..
// same as 1.5, looks up zone info file
String[][] zoneStrings = formatData.getZoneStringsWrapper();
buffer.append(zoneStrings[zoneIndex][index]);
} else {
TimeZone tz = calendar.getTimeZone();
boolean daylight = (calendar.get(Calendar.DST_OFFSET) != 0);
int tzstyle = (count < 4 ? TimeZone.SHORT : TimeZone.LONG);
buffer.append(tz.getDisplayName(daylight, tzstyle,
formatData.locale)); <------------ Uses this code path
}...
4) JDK 1.5/6: TimeZone.getDisplayName()
This method is the same in both JDKs, but only called in JDK 6 case.
If the ID is customized (GMT +/-x), it simply returns that.
String id = getID();
String[] names = getDisplayNames(id, locale);
if (names == null) {
if (id.startsWith("GMT")) {
char sign = id.charAt(3);
if (sign == '+' || sign == '-') {
return id;
Therefore, the display name for the Converter's timezone in JDK 6 is
fixed as its ID (GMT+/-rawOffset).
Notes:
1) Although this used to work in JDK 1.5, I'm not convinced this is a
JDK issue. Since we are creating a custom timezone in
getFormattingTimeZone(), and the JDK documentation states: "No
daylight saving time transition schedule can be specified with a
custom time zone ID."
http://java.sun.com/javase/6/docs/api/java/util/TimeZone.html#setID%28java.lang.String
Arguably, the DateTimeConverter should get the formattingTimeZone()
with the value to be formatted included, so it instead does:
StringBuilder zoneId = new StringBuilder(9);
int offset = zone.getOffset((Date) value);
2) On the other hand, I don't understand the check in #subformat() for
formatData.locale or formatData.isZoneStringsSet. It seems like a
change for the default behavior in SimpleDateFormat since most users
will not plug-in their own DateFormatSymbols, and the defaults for
those fields is false.
Yee-Wah
Yee-wah Lee wrote:
Hi everyone,
The Trinidad DateTimeConverter has a problem when using JDK 6,
because of changes in SimpleDateFormat. I have written a test case to
replicate the converter's behavior.
Test case:
DateFormat df = DateFormat.getDateTimeInstance
(DateFormat.SHORT, DateFormat.LONG);
Date d = new Date();
// getFormattingTimeZone copied from
trinidad-impl\DateTimeConverter.java, it clones the converter's
timezone and gives it a
// customID (GMT +/- offset)./ This affects the display name,
e.g. instead of 'PST' it will display 'GMT-08:00'
TimeZone tz = getFormattingTimeZone (df.getTimeZone());
df.setTimeZone (tz);
System.out.println ("The date is " + d + ", DateFormat.format()
returns " + df.format (d));
On JDK 1.5 this prints:
The date is Wed Jul 08 10:55:25 PDT 2009, DateFormat.format() returns
7/8/09 10:55:25 AM GMT-07:00
On JDK 6:
The date is Wed Jul 08 10:56:39 PDT 2009, DateFormat.format() returns
7/8/09 10:56:39 AM GMT-08:00
Notice that the offset in the second case is 8h. This is incorrect,
the date (Jul 8 09) is in Pacific Daylight time (GMT-7), and if
posted back, it would change the underlying data by +1h.
I can understand why getFormattingTimeZone was originally used:
timezone is thus always displayed in GMT +/- x, which helps when
calculating offsets on the client side. I would like to discuss the
possible fixes for the JDK 6 case (details to follow in second
email), any input is welcome.
I've filed a JIRA tracking this:
https://issues.apache.org/jira/browse/TRINIDAD-1512
Thanks,
Yee-Wah