I have a private method which takes date in as String type and returns XMLGregorianCalendar object with specific format. This method is being invoked from various other methods within the same class.
The format defined as SimpleDateFormat which is same for every invocation. Below are the 2 versions of the method.
Version 1:
private XMLGregorianCalendar getXmlGregorianCalendar(final String strDt) throws ParseException, DatatypeConfigurationException{
Date date = null;
// local variable dtFormat
DateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd-hh.mm.ss");
if (strDt != null) {
date = dtFormat.parse(strDt);
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
return xmlCal;
}else {
return DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
}
}
Version 2:
// declare date format once, global variable
private DateFormat dtFormat = new SimpleDateFormat("yyyy-MM-dd-hh.mm.ss");
// getter setter for dtFormat
private XMLGregorianCalendar getXmlGregorianCalendar(final String strDt) throws ParseException, DatatypeConfigurationException{
Date date = null;
if (strDt != null) {
date = this.dtFormat.parse(strDt); // of course, getDtFormat() can be used
GregorianCalendar cal = new GregorianCalendar();
cal.setTime(date);
XMLGregorianCalendar xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
return xmlCal;
}else {
return DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar());
}
}
Version 1 vs Version 2. Which has better performance?
Note: The enclosed class is annotated as #Component and involved in creating response for my web service.
SimpleDateFormat is not thread-safe, so that would be something to consider. Performance has little to do with this question, unless you really don't have any other performance hotspots (which would be surprising).
You can however use a ThreadLocal SimpleDateFormat, but remember that ThreadLocals have their own issues, and it probably doesn't really matter.
If that SimpleDateFormat is a constant, you can make it static final and it would improve your performance just a little bit. But you should be aware of the concept of static fields in classes. static fields are allocated once in memory for all instances of your #Component class. So if this cannot creating a bug in your code, it's better to define it as a constant using static final keywords.
Using a pattern very similar to that described in a recent question, for a multithreaded application, I am getting weird date values (e.g., years like 2025 or 2035, when clearly no such value exists in the source data). It seems that a concurrency issue is occuring.
The source code looks something like
// Various Java DateFormat patterns, e.g. "yyyy-MM-dd".
private static final String[] DATE_PATTERNS = new String[] {...};
private static SimpleDateFormat[] getFormats(final String[] patterns)
{
ThreadLocal<SimpleDateFormat[]> LOCAL_FORMATS = new ThreadLocal<SimpleDateFormat[]>()
{
#Override
protected SimpleDateFormat[] initialValue()
{
List<SimpleDateFormat> formatList = new ArrayList<SimpleDateFormat>();
for (String pattern:patterns)
{
formatList.add(new SimpleDateFormat(pattern));
}
return formatList.toArray(new SimpleDateFormat[formatList.size()]);
}
};
return LOCAL_FORMATS.get(); // Create a thread-local copy
}
private static final SimpleDateFormat[] DATE_FORMATS = getFormats(DATE_PATTERNS);
After its static initialization, the DATE_FORMATS array is accessed by numerous classes, which in turn use the SimpleDateFormat objects of the array for parsing or formatting several date strings.
Can there be any concurrency issue in such a usage scenario, especially given the use of ThreadLocal?
Yes, there can be concurrency issues. Your thread local variable doesn't serve any purpose. It's only used when the class is initialized, to temporarily store an array of date formats that is immediately retrieved and stored in a static constant.
All the threads, after, always use the same instances of date formats concurrently, without getting them from any thread local variable.
The code should rather be:
private static final String[] DATE_PATTERNS = new String[] {...};
private static final ThreadLocal<SimpleDateFormat[]> DATE_FORMATS =
new ThreadLocal<SimpleDateFormat[]>() {
#Override
protected SimpleDateFormat[] initialValue() {
List<SimpleDateFormat> formatList = new ArrayList<SimpleDateFormat>();
for (String pattern : DATE_PATTERNS)
{
formatList.add(new SimpleDateFormat(pattern));
}
return formatList.toArray(new SimpleDateFormat[formatList.size()]);
}
};
public static SimpleDateFormat[] getDateFormats() {
return DATE_FORMATS.get();
}
I would also use an unmodifiable List<SimpleDateFormat> rather than an array, to be safer.
// Various Java DateFormat patterns, e.g. "yyyy-mm-dd".
The format 'yyyy-mm-dd' is likely to give you weird results because 'mm' is minutes and not months. From the javadoc:
M Month in year Month July; Jul; 07
...
m Minute in hour Number 30
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally
The above line is mentioned in the JavaDoc of SimpleDateFormat class.
Does it mean that we should not create the SimpleDateFormat objects as Static.
And If we create it as static, so wherever we are using this object we need to keep it in Synchronised Block.
That's true. You can find already questions concerning this issue on StackOverflow. I use to declare it as ThreadLocal:
private static final ThreadLocal<DateFormat> THREAD_LOCAL_DATEFORMAT = new ThreadLocal<DateFormat>() {
protected DateFormat initialValue() {
return new SimpleDateFormat("yyyyMMdd");
}
};
and in the code:
DateFormat df = THREAD_LOCAL_DATEFORMAT.get();
Yes SimpleDateFormat is not thread safe and it is also recommended when you are parsing date it should access in synchronized manner.
public Date convertStringToDate(String dateString) throws ParseException {
Date result;
synchronized(df) {
result = df.parse(dateString);
}
return result;
}
one other way is on http://code.google.com/p/safe-simple-date-format/downloads/list
Thats correct. FastDateFormat from Apache Commons Lang is a nice threadsafe alternative.
Since version 3.2 it supports also parsing, before 3.2 only formatting.
I have this code copied from one of questions from SO:
public static String getCurrentTimeStamp() {
SimpleDateFormat sdfDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date now = new Date();
String strDate = sdfDate.format(now);
return strDate;
}
I want to get only the system time and NOT the date. Then I must change second line of code to:
SimpleDateFormat sdfDate = new SimpleDateFormat(" HH:mm:ss") ;
Then, DATE() must get the current time. Clear upto this point but I can't understand the format() function used.
I mean cant we simply output variable now instead of strdate?
Is it just because that the return type of function getCurrentTimeStamp() is String?
Please clarify and if there is any other simpler and one line code for getting system time alone, do share.
I mean cant we simply output variable now instead of strdate.
Well you could return now.toString() - but that will use the format that Date.toString() happens to choose, whereas you want a specific format. The point of the SimpleDateFormat object in this case is to convert a Date (which is a point in time, without reference to any particular calendar or time zone) into a String, applying an appropriate time zone, calendar system, and text format (in your case HH:mm:ss).
You can still simplify your method somewhat though, by removing the local variables (which are each only used once):
public static String getCurrentTimeStamp() {
return new SimpleDateFormat("HH:mm:ss").format(new Date());
}
Or maybe you'd find it more readable to keep the variable for the date format, but not the date and the return value:
public static String getCurrentTimeStamp() {
DateFormat format = new SimpleDateFormat("HH:mm:ss");
return format.format(new Date());
}
Personally I'd recommend using Joda Time instead, mind you - it's a much nicer date/time API, and its formatted are thread-safe so you could easily keep a reference to a single formatting object.
public static String getCurrentTimeStampwithTimeOnly() {
return new SimpleDateFormat("HH:mm:ss").format(new Date());
}
Helps you to do this.
you can call this line any time
Date now = new Date();
The now variable will contain the current timestamp
The format function just generates a String from this timestamp
also take a look at the Calendar class ( Calendar.getInstance())
I have this situation where I am reading about 130K records containing dates stored as String fields. Some records contain blanks (nulls), some contain strings like this: 'dd-MMM-yy' and some contain this 'dd/MM/yyyy'.
I have written a method like this:
public Date parsedate(String date){
if(date !== null){
try{
1. create a SimpleDateFormat object using 'dd-MMM-yy' as the pattern
2. parse the date
3. return the parsed date
}catch(ParseException e){
try{
1. create a SimpleDateFormat object using 'dd/MM/yyy' as the pattern
2. parse the date
3. return parsed date
}catch(ParseException e){
return null
}
}
}else{
return null
}
}
So you may have already spotted the problem. I am using the try .. catch as part of my logic. It would be better is I can determine before hand that the String actually contains a parseable date in some format then attempt to parse it.
So, is there some API or library that can help with this? I do not mind writing several different Parse classes to handle the different formats and then creating a factory to select the correct6 one, but, how do I determine which one?
Thanks.
See Lazy Error Handling in Java for an overview of how to eliminate try/catch blocks using an Option type.
Functional Java is your friend.
In essence, what you want to do is to wrap the date parsing in a function that doesn't throw anything, but indicates in its return type whether parsing was successful or not. For example:
import fj.F; import fj.F2;
import fj.data.Option;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import static fj.Function.curry;
import static fj.Option.some;
import static fj.Option.none;
...
F<String, F<String, Option<Date>>> parseDate =
curry(new F2<String, String, Option<Date>>() {
public Option<Date> f(String pattern, String s) {
try {
return some(new SimpleDateFormat(pattern).parse(s));
}
catch (ParseException e) {
return none();
}
}
});
OK, now you've a reusable date parser that doesn't throw anything, but indicates failure by returning a value of type Option.None. Here's how you use it:
import fj.data.List;
import static fj.data.Stream.stream;
import static fj.data.Option.isSome_;
....
public Option<Date> parseWithPatterns(String s, Stream<String> patterns) {
return stream(s).apply(patterns.map(parseDate)).find(isSome_());
}
That will give you the date parsed with the first pattern that matches, or a value of type Option.None, which is type-safe whereas null isn't.
If you're wondering what Stream is... it's a lazy list. This ensures that you ignore patterns after the first successful one. No need to do too much work.
Call your function like this:
for (Date d: parseWithPatterns(someString, stream("dd/MM/yyyy", "dd-MM-yyyy")) {
// Do something with the date here.
}
Or...
Option<Date> d = parseWithPatterns(someString,
stream("dd/MM/yyyy", "dd-MM-yyyy"));
if (d.isNone()) {
// Handle the case where neither pattern matches.
}
else {
// Do something with d.some()
}
Don't be too hard on yourself about using try-catch in logic: this is one of those situations where Java forces you to so there's not a lot you can do about it.
But in this case you could instead use DateFormat.parse(String, ParsePosition).
You can take advantage of regular expressions to determine which format the string is in, and whether it matches any valid format. Something like this (not tested):
(Oops, I wrote this in C# before checking to see what language you were using.)
Regex test = new Regex(#"^(?:(?<formatA>\d{2}-[a-zA-Z]{3}-\d{2})|(?<formatB>\d{2}/\d{2}/\d{3}))$", RegexOption.Compiled);
Match match = test.Match(yourString);
if (match.Success)
{
if (!string.IsNullOrEmpty(match.Groups["formatA"]))
{
// Use format A.
}
else if (!string.IsNullOrEmpty(match.Groups["formatB"]))
{
// Use format B.
}
...
}
If you formats are exact (June 7th 1999 would be either 07-Jun-99 or 07/06/1999: you are sure that you have leading zeros), then you could just check for the length of the string before trying to parse.
Be careful with the short month name in the first version, because Jun may not be June in another language.
But if your data is coming from one database, then I would just convert all dates to the common format (it is one-off, but then you control the data and its format).
In this limited situation, the best (and fastest method) is certinally to parse out the day, then based on the next char either '/' or '-' try to parse out the rest. and if at any point there is unexpected data, return NULL then.
Assuming the patterns you gave are the only likely choices, I would look at the String passed in to see which format to apply.
public Date parseDate(final String date) {
if (date == null) {
return null;
}
SimpleDateFormat format = (date.charAt(2) == '/') ? new SimpleDateFormat("dd/MMM/yyyy")
: new SimpleDateFormat("dd-MMM-yy");
try {
return format.parse(date);
} catch (ParseException e) {
// Log a complaint and include date in the complaint
}
return null;
}
As others have mentioned, if you can guarantee that you will never access the DateFormats in a multi-threaded manner, you can make class-level or static instances.
Looks like three options if you only have two, known formats:
check for the presence of - or / first and start with that parsing for that format.
check the length since "dd-MMM-yy" and "dd/MM/yyyy" are different
use precompiled regular expressions
The latter seems unnecessary.
Use regular expressions to parse your string. Make sure that you keep both regex's pre-compiled (not create new on every method call, but store them as constants), and compare if it actually is faster then the try-catch you use.
I still find it strange that your method returns null if both versions fail rather then throwing an exception.
you could use split to determine which format to use
String[] parts = date.split("-");
df = (parts.length==3 ? format1 : format2);
That assumes they are all in one or the other format, you could improve the checking if need be
An alternative to creating a SimpleDateFormat (or two) per iteration would be to lazily populate a ThreadLocal container for these formats. This will solve both Thread safety concerns and concerns around object creation performance.
A simple utility class I have written for my project. Hope this helps someone.
Usage examples:
DateUtils.multiParse("1-12-12");
DateUtils.multiParse("2-24-2012");
DateUtils.multiParse("3/5/2012");
DateUtils.multiParse("2/16/12");
public class DateUtils {
private static List<SimpleDateFormat> dateFormats = new ArrayList<SimpleDateFormat>();
private Utils() {
dateFormats.add(new SimpleDateFormat("MM/dd/yy")); // must precede yyyy
dateFormats.add(new SimpleDateFormat("MM/dd/yyyy"));
dateFormats.add(new SimpleDateFormat("MM-dd-yy"));
dateFormats.add(new SimpleDateFormat("MM-dd-yyyy"));
}
private static Date tryToParse(String input, SimpleDateFormat format) {
Date date = null;
try {
date = format.parse(input);
} catch (ParseException e) {
}
return date;
}
public static Date multiParse(String input) {
Date date = null;
for (SimpleDateFormat format : dateFormats) {
date = tryToParse(input, format);
if (date != null) break;
}
return date;
}
}
On one hand I see nothing wrong with your use of try/catch for the purpose, it’s the option I would use. On the other hand there are alternatives:
Take a taste from the string before deciding how to parse it.
Use optional parts of the format pattern string.
For my demonstrations I am using java.time, the modern Java date and time API, because the Date class used in the question was always poorly designed and is now long outdated. For a date without time of day we need a java.time.LocalDate.
try-catch
Using try-catch with java.time looks like this:
DateTimeFormatter ddmmmuuFormatter = DateTimeFormatter.ofPattern("dd-MMM-uu", Locale.ENGLISH);
DateTimeFormatter ddmmuuuuFormatter = DateTimeFormatter.ofPattern("dd/MM/uuuu");
String dateString = "07-Jun-09";
LocalDate result;
try {
result = LocalDate.parse(dateString, ddmmmuuFormatter);
} catch (DateTimeParseException dtpe) {
result = LocalDate.parse(dateString, ddmmuuuuFormatter);
}
System.out.println("Date: " + result);
Output is:
Date: 2009-06-07
Suppose instead we defined the string as:
String dateString = "07/06/2009";
Then output is still the same.
Take a taste
If you prefer to avoid the try-catch construct, it’s easy to make a simple check to decide which of the formats your string conforms to. For example:
if (dateString.contains("-")) {
result = LocalDate.parse(dateString, ddmmmuuFormatter);
} else {
result = LocalDate.parse(dateString, ddmmuuuuFormatter);
}
The result is the same as before.
Use optional parts in the format pattern string
This is the option I like the least, but it’s short and presented for some measure of completeness.
DateTimeFormatter dateFormatter
= DateTimeFormatter.ofPattern("[dd-MMM-uu][dd/MM/uuuu]", Locale.ENGLISH);
LocalDate result = LocalDate.parse(dateString, dateFormatter);
The square brackets denote optional parts of the format. So Java first tries to parse using dd-MMM-uu. No matter if successful or not it then tries to parse the remainder of the string using dd/MM/uuuu. Given your two formats one of the attempts will succeed, and you have parsed the date. The result is still the same as above.
Link
Oracle tutorial: Date Time explaining how to use java.time.