I have a problem. I am trying to convert some strings to date, and I don't know the format the date is arriving.
It might come as yyyy.mm.dd hh:mm:ss
or MM.dd.yy hh:mm:ss
and so on.
How can I convert these strings to Date? I tried this:
DateFormat formatter = new SimpleDateFormat("dd-MM-yyyy hh:mm:ss开发者_如何学编程");
Date d = (Date)formatter.parse(someDate);
But when I printed out someDate it printed out like this: 2010-08-05 12:42:48.638 CEST which means yyyy.mm.dd hh:mm:ss
, however when I ran the above code, the date object now became Sat Jan 31 00:42:48 CET 11
which is strange to say the least.
Any ideas how I can correctly format strings to date?
You cant!
If you have the date 2010-08-05
then it can be either 5th August 2010, or 8th May 2010 - you need to know the date format (or at least prioritise one format over the over) to tell them apart.
I agree with Kragen that in the general case there is no correct solution. However, if the following conditions hold, you may use the solution below:
You have a set of all possible formats
There is no ambiguity between the formats; no date expression can be successfully parsed by two of them.
Consider the following solution which iterates over a list of possible formats. This solution makes use of ThreadLocal
, in order to make date parsing efficient in a multi-threaded environment (remember that SimpleDateFormat
isn't thread safe):
public class FlexibleDateParser {
private List<ThreadLocal<SimpleDateFormat>> threadLocals = new ArrayList<ThreadLocal<SimpleDateFormat>>();
public FlexibleDateParser(List<String> formats, final TimeZone tz){
threadLocals.clear();
for (final String format : formats) {
ThreadLocal<SimpleDateFormat> dateFormatTL = new ThreadLocal<SimpleDateFormat>() {
protected SimpleDateFormat initialValue() {
SimpleDateFormat sdf = new SimpleDateFormat(format);
sdf.setTimeZone(tz);
sdf.setLenient(false);
return sdf;
}
};
threadLocals.add(dateFormatTL);
}
}
public Date parseDate(String dateStr) throws ParseException {
for (ThreadLocal<SimpleDateFormat> tl : threadLocals) {
SimpleDateFormat sdf = tl.get();
try {
return sdf.parse(dateStr);
} catch (ParseException e) {
// Ignore and try next date parser
}
}
// All parsers failed
return null;
}
}
As noted before, you need to at least have an ordered list of pattern candidates. Once you have that, Apache DateUtils has a parseDate(String dateString, String[] patterns)
method that lets you easily try out a list of patterns on your date string, and parse it by the first one that matches:
public static Date parseDate(String str,
String[] parsePatterns)
throws ParseException
Parses a string representing a date by trying a variety of different parsers.
The parse will try each parse pattern in turn. A parse is only deemed successful if it parses the whole of the input string. If no parse patterns match, a ParseException is thrown.
The parser will be lenient toward the parsed date.
Here is a quick and dirty solution based on american date formats.
public Date parseDate(String strDate) throws Exception
{
if (strDate != null && !strDate.isEmpty())
{
SimpleDateFormat[] formats =
new SimpleDateFormat[] {new SimpleDateFormat("MM-dd-yyyy"), new SimpleDateFormat("yyyyMMdd"),
new SimpleDateFormat("MM/dd/yyyy")};
Date parsedDate = null;
for (int i = 0; i < formats.length; i++)
{
try
{
parsedDate = formats[i].parse(strDate);
return parsedDate;
}
catch (ParseException e)
{
continue;
}
}
}
throw new Exception("Unknown date format: '" + strDate + "'");
}
Your problem is related to Internationalization. As Kragen answered, you can't just parse date in unknown format. Although you can scan all possible locales and parse something, but you wouldn't know if it was parsed correctly.
Just a little i18n background:
Q: Can you tell me what day month and year this date is referring to:
09/11/10?
A: Without knowing the locale, you can't. It could be anything. September, 11th in USA. November, 9th in Great Britain. And so on.
I once had a task to write a code that would parse a String to date where date format was not known in advance. I.e. I had to parse any valid date format. I wrote a project and after that I wrote an article that described the idea behind my implementation. Here is the link to the article: Java 8 java.time package: parsing any string to date. General Idea is to write all the patterns that you wish to support into external properties file and read them from there and try to parse your String by those formats one by one until you succeed or run out of formats. Note that the order also would be important as some Strings may be valid for several formats (US/European differences). Advantage is that you can keep adding/removing formats to the file without changing your code. So such project could also be customized for different customers
If its a protocol; define the format - perhaps ISO that will irritate everyone except us in sweden...
If it input from users; Let them set their locale. If you can do it, show the parsed date in full format so the user can verify it, like November 10, 2009.
My only guess, is that you should gather some statistics first to figure out the format.
If you're lucky, you will have date like "2010/08/13" which can be parsed unambiguously
Here is the simple solution, which is worked for me. This is the simple method to parse the date, pass the String as argument & parse it in any format those you want.
String dateToConvert(String date) {
String strDate = "";
try {
//create SimpleDateFormat object with source string date format
DateFormat sdfSource = new SimpleDateFormat("yyyy-MM-dd");
//parse the string into Date object
Date d = sdfSource.parse(date);
LocalLog.e(LOG_TAG, d.toString());
//create SimpleDateFormat object with desired date format
SimpleDateFormat sdfDestination = new SimpleDateFormat(AppConstants.UNIVERSAL_DATE_FORMAT);
//parse the date into another format
strDate = sdfDestination.format(d);
LocalLog.e(LOG_TAG, strDate);
} catch (ParseException pe) {
System.out.println("Parse Exception : " + pe);
}
return strDate;
}
I created a utility that tries to parse some common date formats.
It tries to check which digit is greater than 12 or else if both are less than 12 it prefers user-defined boolean preferMonthFirst based on which it will choose between MM/dd/yyyy
or dd/MM/yyyy
It also accepts prefer24HourTime boolean for parsing time.
I did not use the list and iterate over it and try to parse it and tried to catch exception because Exceptions are costlier. So based on separator and length I tried to find the date format.
You can find usages in the test cases.
https://github.com/rajat-g/DateParser
public String compareDate( PaymentTxnRequest request ) throws ParseException {
Date debitDate= request.getPaymentTxn().getCrValDt();
Date now = new Date();
String response="";
SimpleDateFormat sdfDate = new SimpleDateFormat("dd/MM/yyyy");
String strCurrDate = sdfDate.format(now);
String strDebitDate = sdfDate.format(debitDate);
System.out.println("Current Date: " + strCurrDate);
Date currentDate = new SimpleDateFormat("dd/MM/yyyy").parse(strCurrDate);
Date txnDate = new SimpleDateFormat("dd/MM/yyyy").parse(strDebitDate);
System.out.println("C -> "+currentDate);
System.out.println("C -> "+txnDate);
if (txnDate!=null){
if (currentDate.equals(txnDate))
{
System.out.println("Valid Txn");
response="valid";
}
if (currentDate.after(txnDate))
{
System.out.println("--> Not Valid TXN Past");
response="notValid";
}
if (currentDateenter code here.before(txnDate)){
System.out.println("Future Valid TXn");
response="future";
}
}
return response;
}
精彩评论