Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8184321

Date format combined with calendar setters applies timezone offset twice

    Details

    • Subcomponent:
    • CPU:
      generic
    • OS:
      generic

      Description

      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.

        Activity

        Hide
        psonal Pallavi Sonal added a comment -
        To submitter:
        I am unable to reproduce the issue with the test case provided in the bug report. Attached is the test case I tried. With JDK 8u121, JDK 8u131 and JDK 9-ea+174, I got the same output:
        PASSED for input '06/14/2004 07:17 UTC' -> 2004-06-14 07:17:59,999 UTC
        PASSED for input '06/14/2005 07:17 UTC' -> 2005-06-14 07:17:59,999 UTC

        Can you please clarify more and provide further inputs to reproduce the issue at my end.
        Show
        psonal Pallavi Sonal added a comment - To submitter: I am unable to reproduce the issue with the test case provided in the bug report. Attached is the test case I tried. With JDK 8u121, JDK 8u131 and JDK 9-ea+174, I got the same output: PASSED for input '06/14/2004 07:17 UTC' -> 2004-06-14 07:17:59,999 UTC PASSED for input '06/14/2005 07:17 UTC' -> 2005-06-14 07:17:59,999 UTC Can you please clarify more and provide further inputs to reproduce the issue at my end.
        Hide
        psonal Pallavi Sonal added a comment -
        From submitter:
        Thanks for re-testing that fast and for your reply.

        I cannot reproduce it anymore ... and I believe that it has been fixed already, and that fact has slipped my attention for unknown reasons.

        When I reproduced and reported the bug, I used JDK 1.8.0_60 . The bug report form asked me to use the latest available version and I activated the use of JDK 1.8.0_121 ... and continued to see it. I must have done something wrong when activating 121 in my eclipse or the runtime classpath was wrong; I do not know. The state now is:

        JDK 1.8.0_121 PASSES the test.
        JDK 1.8.0_60 FAILS.

        The issue must be a duplicate and has already been fixed.

        Sorry for not realizing this earlier. Please close the issue.
        Show
        psonal Pallavi Sonal added a comment - From submitter: Thanks for re-testing that fast and for your reply. I cannot reproduce it anymore ... and I believe that it has been fixed already, and that fact has slipped my attention for unknown reasons. When I reproduced and reported the bug, I used JDK 1.8.0_60 . The bug report form asked me to use the latest available version and I activated the use of JDK 1.8.0_121 ... and continued to see it. I must have done something wrong when activating 121 in my eclipse or the runtime classpath was wrong; I do not know. The state now is: JDK 1.8.0_121 PASSES the test. JDK 1.8.0_60 FAILS. The issue must be a duplicate and has already been fixed. Sorry for not realizing this earlier. Please close the issue.

          People

          • Assignee:
            psonal Pallavi Sonal
            Reporter:
            webbuggrp Webbug Group
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: