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

getTimestamp(int,Calendar) can erroneously return null for certain timezones

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P5
    • Resolution: Future Project
    • Affects Version/s: 6
    • Fix Version/s: None
    • Component/s: core-libs
    • Labels:

      Description

      FULL PRODUCT VERSION :
      java version "1.6.0_01"
      Java(TM) SE Runtime Environment (build 1.6.0_01-b06)
      Java HotSpot(TM) Client VM (build 1.6.0_01-b06, mixed mode, sharing)

      ADDITIONAL OS VERSION INFORMATION :
      Microsoft Windows XP [Version 5.1.2600]

      A DESCRIPTION OF THE PROBLEM :
      When getTimestamp(int,Calendar), getTime(int,Calendar), or getDate(int,Calendar) are called with a Calendar argument that has a timezone with the same GMT offset as the current default timezone, the method returns null (even though there is a valid non-null value in the database).

      Further more, the erroneous behaviour that has previously been reported as bug #4881343 is still present. When the GMT offset of the Calendar argument is different to the GMT offset of the current default timezone, the difference between them is applied as an offset to the value obtained from the database, but in the wrong direction.

      Folks, these methods seem to be utterly broken. You have not done yourselves any favours by closing bug #4881343 and muttering "Meh can't be bothered fixing that". Frankly that's pathetic and reflects poorly on the JDK/JRE and Sun in general.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      1. Create an Access database.
      2. Add a table called "Table1" with a single column of type "Date/Time".
      3. Insert a single row with the value "01/01/1970 00:00:00" in the column.
      4. Obtain a connection to the database, execute the query "SELECT * FROM Table1".
      5. Call hasNext() on the result
      6. Create a Calendar object (let's refer to it by "cal") that uses a timezone with the same GMT offset as the timezone returned by TimeZone.getDefault().
      7. Call getTimestamp(1,cal) or getTime(1,cal) or getDate(1,cal).

      The result of either of these calls will be null, despite there being a valid non-null value in the database.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      This is the output I expect to see when I execute the provided test code under the conditions described in the "Steps to Reproduce".
      >>>>>>>>>>>>>>>
      Default time zone is : sun.util.calendar.ZoneInfo[id="Australia/Adelaide",offset=34200000, (... blah blah toString() representation of timezone)
       ------------
      Got date with millisecond val = 0 when calendar has timezone id GMT+0000
      Got date with millisecond val = -14400000 when calendar has timezone id GMT+0400
      Got date with millisecond val = 14400000 when calendar has timezone id GMT-0400
      Got date with millisecond val = -34200000 when calendar has timezone id GMT+0930
      Got date with millisecond val = -34200000 when calendar has timezone id Australia/South
      Got date with millisecond val = -32400000 when calendar has timezone id GMT+0900
       ------------
      Default time zone is now : sun.util.calendar.ZoneInfo[id="GMT+00:00",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
       ------------
      Got date with millisecond val = 0 when calendar has timezone id GMT+0000
      Got date with millisecond val = -14400000 when calendar has timezone id GMT+0400
      Got date with millisecond val = 14400000 when calendar has timezone id GMT-0400
      Got date with millisecond val = -34200000 when calendar has timezone id GMT+0930
      Got date with millisecond val = -34200000 when calendar has timezone id Australia/South
      Got date with millisecond val = -32400000 when calendar has timezone id GMT+0900
      ACTUAL -
      This is the output when I execute the provided test code under the conditions described in the "Steps to Reproduce".
      Note the calls that return null; this is the bug I am reporting.
      Also note the differences in values when the call returns a non-null value; this is the incorrect behaviour reported in bug #4881343 that has yet to be fixed.
      >>>>>>>>>>>>>>>
      Default time zone is : sun.util.calendar.ZoneInfo[id="Australia/Adelaide",offset=34200000, (... blah blah toString() representation of timezone)
       ------------
      Got date with millisecond val = -34200000 when calendar has timezone id GMT+0000
      Got date with millisecond val = -19800000 when calendar has timezone id GMT+0400
      Got date with millisecond val = -48600000 when calendar has timezone id GMT-0400
      Got NULL when calendar has timezone id GMT+0930
      Got NULL when calendar has timezone id Australia/South
      Got date with millisecond val = -1800000 when calendar has timezone id GMT+0900
       ------------
      Default time zone is now : sun.util.calendar.ZoneInfo[id="GMT+00:00",offset=0,dstSavings=0,useDaylight=false,transitions=0,lastRule=null]
       ------------
      Got NULL when calendar has timezone id GMT+0000
      Got date with millisecond val = 14400000 when calendar has timezone id GMT+0400
      Got date with millisecond val = -14400000 when calendar has timezone id GMT-0400
      Got date with millisecond val = 34200000 when calendar has timezone id GMT+0930
      Got date with millisecond val = 34200000 when calendar has timezone id Australia/South
      Got date with millisecond val = 32400000 when calendar has timezone id GMT+0900

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------

      import java.sql.Connection;
      import java.sql.Date;
      import java.sql.DriverManager;
      import java.sql.ResultSet;
      import java.sql.Statement;
      import java.sql.Time;
      import java.sql.Timestamp;

      import java.util.Calendar;
      import java.util.TimeZone;

      public class ODBCTimeZoneTest {

      public static void main(String[] args) throws Exception {

      String conn_str = "jdbc:odbc:DRIVER={Microsoft Access Driver (*.mdb)};DBQ=C:\\Temp\\timezone_test.mdb";
      Connection db_connection = DriverManager.getConnection(conn_str, "", "");
      Statement db_statement = db_connection.createStatement();
      String[] timezone_ids = { "GMT+0000", "GMT+0400", "GMT-0400", "GMT+0930", "Australia/South", "GMT+0900" };

      System.out.println("Default time zone is : " + TimeZone.getDefault());

      System.out.println(" ------------ ");

      for (String tz_id : timezone_ids) {
      ResultSet result_set = db_statement.executeQuery("SELECT * FROM Table1");
      Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(tz_id));
      result_set.next();
      Date date = result_set.getDate(1, cal);
      if (date == null) {
      System.out.println("Got NULL when calendar has timezone id " + tz_id);
      } else {
      System.out.println("Got date with millisecond val = " + date.getTime() + " when calendar has timezone id "
      + tz_id);
      }
      result_set.close();
      }

      System.out.println(" ------------ ");

      TimeZone.setDefault(TimeZone.getTimeZone("GMT+0000"));

      System.out.println("Default time zone is now : " + TimeZone.getDefault());

      System.out.println(" ------------ ");

      for (String tz_id : timezone_ids) {
      ResultSet result_set = db_statement.executeQuery("SELECT * FROM Table1");
      Calendar cal = Calendar.getInstance(TimeZone.getTimeZone(tz_id));
      result_set.next();
      Date date = result_set.getDate("DT_FIELD", cal);
      if (date == null) {
      System.out.println("Got NULL when calendar has timezone id " + tz_id);
      } else {
      System.out.println("Got date with millisecond val = " + date.getTime() + " when calendar has timezone id "
      + tz_id);
      }
      result_set.close();
      }

      }

      }
      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      The only workaround is to not use the methods at all. They are broken. I need to use the methods that work from the default timezone, then manually adjust the returned values into the timezone I want.

      As noted in bug #4380653, the potential workaround of setting the default timezone to the one I want before querying the database is a bad idea. It will have side-effects on anything that also depends on the default timezone. If I am making concurrent access to different databases using different timezones there will be in a race condition.

        Attachments

          Activity

            People

            Assignee:
            lancea Lance Andersen
            Reporter:
            ryeung Roger Yeung (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Dates

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: