-
Bug
-
Resolution: Fixed
-
P4
-
7u71, 8u66, 9
-
b133
-
x86
-
os_x
FULL PRODUCT VERSION :
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Darwin XXX 14.4.0 Darwin Kernel Version 14.4.0: Thu May 28 11:35:04 PDT 2015; root:xnu-2782.30.5~1/RELEASE_X86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
A java.util.Date cannot be compared safely to a java.sql.Timestamp if the Timestamp has milliseconds != 0.
This is due to the fact that the Timestamp "outsources the millis part of it's the java.util.Date member variable "fastTime" to it's own member "nanos" and sets the millis part in fastTime to 000.
However, java.util.Date.after (and before) use getMillisOf, which in turn returns fastTime in most cases, to compare this with the argument. So if the argument given to after of before is a java.sql.Timestamp, the results are flawed.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run this:
package bugs.java;
public class DateTimestampBug {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
for (int i = 0; i < 10000; i++) {
java.util.Date d = new java.util.Date();
java.sql.Timestamp ts = new java.sql.Timestamp(d.getTime());
System.out.println((d.after(ts) ? "FAIL! (" : "Huh? (") + d.getTime() + ")");
Thread.sleep(1);
}
}
}
You will see Huh? approx. 10x in the output.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
See Huh? all the time ;-)
ACTUAL -
…
FAIL! (1440161647997)
FAIL! (1440161647998)
FAIL! (1440161647999)
Huh? (1440161648000)
FAIL! (1440161648001)
FAIL! (1440161648003)
FAIL! (1440161648004)
FAIL! (1440161648005)
…
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package bugs.java;
public class DateTimestampBug {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
for (int i = 0; i < 10000; i++) {
java.util.Date d = new java.util.Date();
java.sql.Timestamp ts = new java.sql.Timestamp(d.getTime());
System.out.println((d.after(ts) ? "FAIL! (" : "Huh? (") + d.getTime() + ")");
Thread.sleep(1);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Do not use java.util.Date.after with anything _derived_ from java.util.Date. But how?
java version "1.7.0_71"
Java(TM) SE Runtime Environment (build 1.7.0_71-b14)
Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Darwin XXX 14.4.0 Darwin Kernel Version 14.4.0: Thu May 28 11:35:04 PDT 2015; root:xnu-2782.30.5~1/RELEASE_X86_64 x86_64
A DESCRIPTION OF THE PROBLEM :
A java.util.Date cannot be compared safely to a java.sql.Timestamp if the Timestamp has milliseconds != 0.
This is due to the fact that the Timestamp "outsources the millis part of it's the java.util.Date member variable "fastTime" to it's own member "nanos" and sets the millis part in fastTime to 000.
However, java.util.Date.after (and before) use getMillisOf, which in turn returns fastTime in most cases, to compare this with the argument. So if the argument given to after of before is a java.sql.Timestamp, the results are flawed.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Run this:
package bugs.java;
public class DateTimestampBug {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
for (int i = 0; i < 10000; i++) {
java.util.Date d = new java.util.Date();
java.sql.Timestamp ts = new java.sql.Timestamp(d.getTime());
System.out.println((d.after(ts) ? "FAIL! (" : "Huh? (") + d.getTime() + ")");
Thread.sleep(1);
}
}
}
You will see Huh? approx. 10x in the output.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
See Huh? all the time ;-)
ACTUAL -
…
FAIL! (1440161647997)
FAIL! (1440161647998)
FAIL! (1440161647999)
Huh? (1440161648000)
FAIL! (1440161648001)
FAIL! (1440161648003)
FAIL! (1440161648004)
FAIL! (1440161648005)
…
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package bugs.java;
public class DateTimestampBug {
public static void main(String[] args) throws InterruptedException {
// TODO Auto-generated method stub
for (int i = 0; i < 10000; i++) {
java.util.Date d = new java.util.Date();
java.sql.Timestamp ts = new java.sql.Timestamp(d.getTime());
System.out.println((d.after(ts) ? "FAIL! (" : "Huh? (") + d.getTime() + ")");
Thread.sleep(1);
}
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
Do not use java.util.Date.after with anything _derived_ from java.util.Date. But how?