Have a function that creates a time-only Date object. (why this is required is a long story which is irrelevant in this context but I need to compare to some stuff in XML wo
The diagnosis in the accepted answer is correct. I am providing the modern answer: do use java.time, the modern Java date and time API, for your date and time work. In Java 7 too. SimpleDateFormat
is notoriously troublesome, its lack of thread safety is only one of its many problems. So don’t use that class.
You want the current time only, though with an offset from UTC, if your format pattern is to be believed. We have got a method exactly for that in java.time, the modern Java date and time API. So no reason to format into a string and parse back.
OffsetTime timeOnly = OffsetTime.now(ZoneId.systemDefault());
System.out.println(timeOnly);
When I ran the code just now in my time zone, Europe/Copenhagen, on jdk.1.7.0_67, the output was:
06:21:55.419+01:00
By the way this is also the XML format for the concept of a time with time zone. Are we done?
The Date
class you were returning is poorly designed and long outdated, so avoid it if you can. If you need one for a legacy API that you cannot afford to change just now, convert like this:
Instant asInstant = LocalDate.of(1970, Month.JANUARY, 1)
.atTime(timeOnly)
.toInstant();
Date oldfashionedDateObject = DateTimeUtils.toDate(asInstant);
System.out.println("As java.util.Date: " + oldfashionedDateObject);
As java.util.Date: Thu Jan 01 06:21:55 CET 1970
Environment: Java 7
java.time just requires at least Java 6.
Date.from(asInstant)
for converting from Instant
to Date
instead of the way shown in the code above.org.threeten.bp
with subpackages.java.time
was first described.java.time
to Java 6 and 7 (ThreeTen for JSR-310).FYI, the Joda-Time 2.3 library provides a class expressly for your purpose, time-only, without any date: LocalTime. And, it is thread-safe (immutable instances). Seems a much better option than manhandling the troublesome java.util.Date class.
LocalTime localTime = new LocalTime();
Dump to console…
System.out.println( "localTime: " + localTime );
When run…
localTime: 16:26:28.065
Java 8 brings the new java.time package, inspired by Joda-Time, defined by JSR 310.
In java.time, you will find a LocalTime class similar to the one in Joda-Time.
While the correct answer is the one by Clockwork-Muse (the cause of the problems is the fact that SimpleDateFormat
isn't thread safe) I just wanted to deliver another method of creating a time-only Date object:
public static Date getCurrentTimeOnly() {
Calendar rightNow = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
int hour = rightNow.get(Calendar.HOUR_OF_DAY);
int minute = rightNow.get(Calendar.MINUTE);
int second = rightNow.get(Calendar.SECOND);
int msecond = rightNow.get(Calendar.MILLISECOND);
long millisSinceMidnight
= (hour * 60 * 60 * 1000)
+ (minute * 60 * 1000)
+ (second * 1000)
+ (msecond);
return new Date(millisSinceMidnight);
}
This method is somewhat more formally correct, i.e. it handles leap-seconds. It doesn't assume, like other methods, that all days since epoch has always had 24*60*60*1000 milliseconds in them.
It doesn't however handle the case where the leap second is on the current day.
You can use "sychronized" block to make it thread safe. Something like:
synchronized (lastUpdatedFormat) {
date =
lastUpdatedFormat.parse(lastUpdatedFormat.format(currentDate));
}
SimpleDateFormat is not thread safe. the following program will reproduce NumberFormatException
while parsing string represented date to date object.
public class MaintainEqualThreadsPatallel {
static int parallelCount = 20;
public static void main(String[] args) throws Exception {
ExecutorService executorPool = Executors.newFixedThreadPool(parallelCount);
int numberOfThreads = 150; // Total thread count = 150*2= 300.
List<Future<Object>> futureReturns = new LinkedList<Future<Object>>();
for (int i = 0; i < numberOfThreads; i++) {
int uniqueRandomValues = uniqueRandomValues(1, 10);
// Callable Thread - call()
Future<Object> submit = executorPool.submit( new WorkerCallable(uniqueRandomValues) );
futureReturns.add(submit);
// Runnable Thread - run()
executorPool.execute( new WorkerThread(uniqueRandomValues) );
}
// WorkerCallable: Blocking main thread until task completes.
waitTillThreadsCompleteWork(futureReturns);
// Terminate Pool threads in-order to terminate main thread
executorPool.shutdown();
}
private static final SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
public static Date numberFormatEx(Date date) throws ParseException { // synchronized
String dateStr = sdf.format(date);
Date dateParsed = sdf.parse(dateStr); // NumberFormatException: For input string: "186E.2186E2"
System.out.println("Date :"+ dateParsed);
return dateParsed;
}
protected void loopFunction(int repeatCount) {
String threadName = Thread.currentThread().getName();
System.out.println(threadName +":START");
for (int i = 1; i <= repeatCount; i++) {
try {
System.out.println(threadName +":"+ i);
sleepThread(100);
numberFormatEx(new Date());
} catch (Exception e) {
e.printStackTrace();
}
}
System.out.println(threadName +":END");
}
public static void waitTillThreadsCompleteWork(List<Future<Object>> futureReturns) throws Exception {
for (Future<Object> future : futureReturns) {
int threadReturnVal = (int) future.get();
System.out.println("Future Response : "+threadReturnVal);
}
}
public static int uniqueRandomValues(int min, int max) {
int nextInt = ThreadLocalRandom.current().nextInt(min, max);
System.out.println("Random Vlaue : "+nextInt);
return nextInt;
}
public void sleepThread(long mills) {
try {
Thread.sleep(mills);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
class WorkerThread extends MaintainEqualThreadsPatallel implements Runnable {
int randomValue = 0;
public WorkerThread(int randomValue) {
this.randomValue = randomValue;
}
@Override
public void run() {
// As separate stack run() function doesn't accepts parameters, pass to constructor.
loopFunction(randomValue);
}
}
class WorkerCallable extends MaintainEqualThreadsPatallel implements Callable<Object> {
int randomValue = 0;
public WorkerCallable(int randomValue) {
this.randomValue = randomValue;
}
public Object call() {
// As separate stack run() function doesn't accepts parameters, pass to constructor.
loopFunction(randomValue);
return randomValue;
}
}
NumberFormatException with different messages:
java.lang.NumberFormatException: multiple points
java.lang.NumberFormatException: For input string: ""
java.lang.NumberFormatException: For input string: "186E.2"
java.lang.NumberFormatException: For input string: "186E.2186E2"
java.lang.NumberFormatException: For input string: "22200222E.222002224EE4"
java.lang.NumberFormatException: For input string: "22200222E.222002224EE44"
at sun.misc.FloatingDecimal.readJavaFormatString(FloatingDecimal.java:2043)
at sun.misc.FloatingDecimal.parseDouble(FloatingDecimal.java:110)
at java.lang.Double.parseDouble(Double.java:538)
at java.text.DigitList.getDouble(DigitList.java:169)
at java.text.DecimalFormat.parse(DecimalFormat.java:2056)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1869)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1514)
at java.text.DateFormat.parse(DateFormat.java:364)
In Multi-Threading
/Web Application with Multi-Requests
concept parse function leads to NumberFormatException
which can be handled using synchronized block.
To overcome NumberFormatException on parse()
function use any of the following scenarios.
public static Date numberFormatEx(Date date) throws ParseException {
SimpleDateFormat ObjInstance = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
String dateStr = ObjInstance.format(date);
Date dateParsed = ObjInstance.parse(dateStr);
System.out.println("Date :"+ dateParsed);
return dateParsed;
}
Unnecessary creating reusable object for each thread.
""/"186E.2186E2"
at some point and leads to error. static SimpleDateFormat objStatic = new SimpleDateFormat("dd-MMM-yyyy HH:mm:ss");
public static synchronized Date numberFormatEx(Date date) throws ParseException {
String dateStr = objStatic.format(date);
Date dateParsed = objStatic.parse(dateStr); // NumberFormatException: For input string: "186E.2186E2"
System.out.println("Date :"+ dateParsed);
return dateParsed;
}
NOTE: In case of Memory management it better to use synchronized block with static object which is reusable.
The likely cause is the fact that SimpleDateFormat
isn't threadsafe, and you're referencing it from multiple threads. While extremely difficult to prove (and about as hard to test for), there is some evidence this is the case:
.11331133EE22
- notice how everything is doubled880044E.3880044E3
- same hereYou probably have at least two threads interleaving. The E
was throwing me, I was thinking it was attempting to deal with scientific notation (1E10, etc), but it's likely part of the time zone.
Thankfully, the (formatting) basic fix is simple:
private static final String FORMAT_STRING = "HH:mm:ss.SSSZ";
public static Date getCurrentTimeOnly() {
SimpleDateFormat formatter = new SimpleDateFormat(FORMAT_STRING);
String onlyTimeStr = formatter.format(new Date());
return formatter.parse(onlyTimeStr);
}
There's a couple of other things you could be doing here, too, with a few caveats:
1 - If the timezone is UTC (or any without DST), this is trivial
public static Date getCurrentTimeOnly() {
Date time = new Date();
time.setTime(time.getTime() % (24 * 60 * 60 * 1000));
return time;
}
2 - You're going to have trouble testing this method, because you can't safely pause the clock (you can change the timezone/locale). For a better time dealing with date/time in Java, use something like JodaTime. Note that LocalTime
doesn't have a timezone attached, but Date
only returns an offset in integer hours (and there are zones not on the hour); for safety, you need to either return a Calendar
(with the full timezone), or just return something without it:
// This method is now more testable. Note this is only safe for non-DST zones
public static Calendar getCurrentTimeOnly() {
Calendar cal = new Calendar();
// DateTimeUtils is part of JodaTime, and is a class allowing you to pause time!
cal.setTimeInMillis(DateTimeUtils.currentTimeMillis() % (24 * 60 * 60 * 1000));
return cal;
}