-
Bug
-
Resolution: Not an Issue
-
P4
-
None
-
8, 9
-
generic
-
generic
FULL PRODUCT VERSION :
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.2.9200]
A DESCRIPTION OF THE PROBLEM :
We parse dates and autocomplete the missing values by "upper bounds". Interestingly, this fails if
* the year is greater than 2004
* there is a timezone in the input date format.
Apparently, the date format applies the (some?) timezone offset in an unexpected (wrong) way.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please execute the attached main program (see below).
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The attached main program throws an exception showing the mismatch.
ACTUAL -
The attached main program shows and contains the actual result.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.TimeZone;
public class Main
{
/**
* @param actual
* @return
*/
private static String toString(Date actual)
{
SimpleDateFormat toString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S zzz");
toString.setTimeZone(TimeZone.getTimeZone("UTC"));
String actualFormatted = toString.format(actual);
return actualFormatted;
}
public static void main(String[] args) throws Exception
{
test("2004-06-14 07:17:59,999 UTC", "06/14/2004 07:17 UTC");
test("2005-06-14 07:17:59,999 UTC", "06/14/2005 07:17 UTC");
}
/**
* @param expected
* @param input
* @throws AssertionError
*/
private static void test(String expected, String input) throws AssertionError
{
SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yyyy HH:mm zzz");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
final ParsePosition pos = new ParsePosition(0);
Date result = fmt.parse(input, pos);
if (pos.getIndex() > 0)
{
Calendar calendar = fmt.getCalendar();
//TimeZone timeZone = calendar.getTimeZone();
// THIS FIXES THE PROBLEM: calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
final boolean isMillisSet = calendar.isSet(Calendar.MILLISECOND);
final boolean isSecondSet = calendar.isSet(Calendar.SECOND);
final boolean isMinuteSet = calendar.isSet(Calendar.MINUTE);
final boolean isHourSet = calendar.isSet(Calendar.HOUR_OF_DAY);
final boolean isDaySet = calendar.isSet(Calendar.DAY_OF_MONTH);
final boolean isMonthSet = calendar.isSet(Calendar.MONTH);
if (!isMillisSet)
{
calendar.set(Calendar.MILLISECOND, 999);
}
if (!isSecondSet)
{
calendar.set(Calendar.SECOND, 59);
}
if (!isMinuteSet)
{
calendar.set(Calendar.MINUTE, 59);
}
if (!isHourSet)
{
calendar.set(Calendar.HOUR_OF_DAY, 23);
}
if (!isMonthSet)
{
calendar.set(Calendar.MONTH, 11);
}
if (!isDaySet)
{
// see above, a month is set, so we can get the last day of the month
final int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
calendar.set(Calendar.DAY_OF_MONTH, maxDay);
}
//calendar.setTimeZone(timeZone);
result = calendar.getTime();
}
String actual = toString(result);
if (!expected.equals(actual))
{
throw new AssertionError("Expected '" + expected + "' but was '" + actual + "'");
}
System.out.println("PASSED for input '" + input + "' -> " + actual);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
If you remove the comments near "THIS FIXES THE PROBLEM" in the source code, the example works. We use this (combined with the comments related to the "timeZone" member in order to work around the problem.
java version "1.8.0_121"
Java(TM) SE Runtime Environment (build 1.8.0_121-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.2.9200]
A DESCRIPTION OF THE PROBLEM :
We parse dates and autocomplete the missing values by "upper bounds". Interestingly, this fails if
* the year is greater than 2004
* there is a timezone in the input date format.
Apparently, the date format applies the (some?) timezone offset in an unexpected (wrong) way.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Please execute the attached main program (see below).
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The attached main program throws an exception showing the mismatch.
ACTUAL -
The attached main program shows and contains the actual result.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.TimeZone;
public class Main
{
/**
* @param actual
* @return
*/
private static String toString(Date actual)
{
SimpleDateFormat toString = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S zzz");
toString.setTimeZone(TimeZone.getTimeZone("UTC"));
String actualFormatted = toString.format(actual);
return actualFormatted;
}
public static void main(String[] args) throws Exception
{
test("2004-06-14 07:17:59,999 UTC", "06/14/2004 07:17 UTC");
test("2005-06-14 07:17:59,999 UTC", "06/14/2005 07:17 UTC");
}
/**
* @param expected
* @param input
* @throws AssertionError
*/
private static void test(String expected, String input) throws AssertionError
{
SimpleDateFormat fmt = new SimpleDateFormat("MM/dd/yyyy HH:mm zzz");
fmt.setTimeZone(TimeZone.getTimeZone("GMT"));
final ParsePosition pos = new ParsePosition(0);
Date result = fmt.parse(input, pos);
if (pos.getIndex() > 0)
{
Calendar calendar = fmt.getCalendar();
//TimeZone timeZone = calendar.getTimeZone();
// THIS FIXES THE PROBLEM: calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
final boolean isMillisSet = calendar.isSet(Calendar.MILLISECOND);
final boolean isSecondSet = calendar.isSet(Calendar.SECOND);
final boolean isMinuteSet = calendar.isSet(Calendar.MINUTE);
final boolean isHourSet = calendar.isSet(Calendar.HOUR_OF_DAY);
final boolean isDaySet = calendar.isSet(Calendar.DAY_OF_MONTH);
final boolean isMonthSet = calendar.isSet(Calendar.MONTH);
if (!isMillisSet)
{
calendar.set(Calendar.MILLISECOND, 999);
}
if (!isSecondSet)
{
calendar.set(Calendar.SECOND, 59);
}
if (!isMinuteSet)
{
calendar.set(Calendar.MINUTE, 59);
}
if (!isHourSet)
{
calendar.set(Calendar.HOUR_OF_DAY, 23);
}
if (!isMonthSet)
{
calendar.set(Calendar.MONTH, 11);
}
if (!isDaySet)
{
// see above, a month is set, so we can get the last day of the month
final int maxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
calendar.set(Calendar.DAY_OF_MONTH, maxDay);
}
//calendar.setTimeZone(timeZone);
result = calendar.getTime();
}
String actual = toString(result);
if (!expected.equals(actual))
{
throw new AssertionError("Expected '" + expected + "' but was '" + actual + "'");
}
System.out.println("PASSED for input '" + input + "' -> " + actual);
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
If you remove the comments near "THIS FIXES THE PROBLEM" in the source code, the example works. We use this (combined with the comments related to the "timeZone" member in order to work around the problem.