Parse string to date using different formats/patterns - java

I need to parse a string to a date but have no prior knowledge which pattern the string will be in. This is similar to the question How to convert String to Date without knowing the format?.
To solve this I adopted couple of patterns to test the outcome. However, what I am getting is a bit strange.
Example 1:
import java.util.Date;
import org.apache.commons.lang3.time.DateUtils;
public Date extractDate(String dateStr) {
String [] datePatterns = {"yyyy-MM-dd", "dd-MM-yyyy"};
Date date = null;
try {
date = DateUtils.parseDate(dateStr, datePatterns);
}
catch (Exception except) {
except.printStackTrace();
}
return date;
}
public static void main(String[] args) throws Exception {
System.out.println ("2013-09-30:" + extractDate("2013-09-30") );
System.out.println ("30-09-2013:" + extractDate("30-09-2013") );
}
This gives:
2013-10-30:Wed Oct 30 00:00:00 EAT 2013
30-09-2013:Mon Mar 05 00:00:00 EAT 36
The result from parsing '30-09-2013' is obviously strange.
Example 2: Here I only switch the pattern
String [] datePatterns = {"dd-MM-yyyy", "yyyy-MM-dd"};
This gives:
2013-10-30:Mon Mar 05 00:00:00 EAT 36
30-09-2013:Mon Sep 30 00:00:00 EAT 2013
In example 2 the result from parsing '2013-10-30' is strange.
How can one parse date strings using different formats/patterns so that the resulting dates are correct?

Update to use parseDateStrictly. When I did this I got the following output:
2013-09-30:Mon Sep 30 00:00:00 EDT 2013
30-09-2013:Mon Sep 30 00:00:00 EDT 2013

My answer would be same. Without any prior knowledge of the format you can't parse date.
Few examples of writing a date would be: DD-MM-YYYY, MM-DD-YYYY, DD/MM/YYYY, MM/DD/YYYY, MM/DD/YY, DD/MM/YY. For only these many types of dates can you find any common pattern?
NO! Without knowing the format which user enters you can't parse it.
If you come up with pattern matching, a date such as 10-09-2010 which matches with MM-DD-YYYY format and DD-MM-YYYY format too. Here you will have a problem

Related

Unparseable Date Or Wrong date

Hi I know there are many post on this but I can't figure out what's happening. I'm getting a date as a String from db and trying to convert it to another form.
Didn't understand that had to FIRST parse the string and then use another SimpleDateFormat to Format that date. I know get what I expected when printed.
Date one: Mon Jun 16 04:00:00 EDT 2014
06-16-2014
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class DateCheck {
public static void main(String[] args) {
try {
String str = "2014-06-16 04:00:00.0";
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date1 = df.parse(str);
System.out.println(" Date one: " + date1);
SimpleDateFormat df2 = new SimpleDateFormat("MM-dd-yyyy");
System.out.println(df2.format(date1));
} catch (ParseException e) {
e.printStackTrace();
}
}
}
2 things to note, if i uncomment out the setLenient method i get unparseable date exception.
If commented out i get:Mon Oct 06 00:00:00 EDT 2183
Any help?
EDIT: Sorry that was just stupid. I know get Thu Jan 16 00:06:00 EST 2014
which is correct but i wanted it like 01-16-14
Your format doesn't match your input String.
The input String is in the format of "yyyy-MM-dd hh:mm.s" (there is an assumption on the format as we don't have enough information to make an accurate prediction)
String str = "2014-06-09 00:00.0";
DateFormat df = new SimpleDateFormat("MM-dd-yy");
df.setLenient(true);
Date result = df.parse(str);
Which outputs
Mon Jun 09 00:00:00 EST 2014
So either your format is wrong or the value in the database is wrong. This will depended on your requirements

Best efficient way to sort Months and Year in Java

I have a list which contains dates in format (MON-YYYY) in string format, I need to sort this list.The approach I have followed till now is reading the list and converting the string in date format and using compare option, but i am not getting the desired result
Code Snippet
List<String> abc = new ArrayList<String>();
List<Date> xyz = new ArrayList<Date>();
abc.add("JAN-2010");
abc.add("JAN-2011");
abc.add("APR-2013");
abc.add("NOV-2009");
try {
for (String abc1 : abc) {
Date date;
date = new SimpleDateFormat("MMM-yyyy", Locale.ENGLISH)
.parse(abc1);
xyz.add(date);
}
Collections.sort(xyz, new Comparator<Date>() {
public int compare(Date arg0, Date arg1) {
// return arg0.getDate().compareTo(o2.getDate());
return arg0.compareTo(arg1);
}
});
for (Date date1 : xyz) {
System.out.println("Sorted : " + date1);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
Output
Sorted : Sun Nov 01 00:00:00 IST 2009
Sorted : Fri Jan 01 00:00:00 IST 2010
Sorted : Sat Jan 01 00:00:00 IST 2011
Sorted : Mon Apr 01 00:00:00 IST 2013
Expected Output
NOV-2009
JAN-2010
JAN-2011
APR-2013
I am also not sure if the above code is perfect in performance perspective as converting the string and parsing would take a long time if I have thousands of dates in MON-YYYY format in the list.
Ok, I see you corrected the typo.
Now, remember you need to use a DateFormatter also when you present the data, in addition to when you parse it.
So please try this:
for (Date date1 : xyz) {
System.out.println("Sorted : " + new SimpleDateFormat("MMM-yyyy", Locale.ENGLISH).format(date1));
}
You might want to make the SimpleDateFormat available to all methods of your class as a field.
Additional info: please be aware SimpleDateFormat is known to not be thread-safe. You can use ThreadLocal as one solution to that.
Good luck.
You've parsed your dateString to actual Date object. And java.util.Date can't be formatted. Only a String representation of that Date object can be got.
You need to change your comparator to compare your dateString format by internally converting the Strings to date.
If you are gonna sort the Date objects, you'll get the output you've got. Also, as mentioned by #darijan, change your logic in the comparator.
First i think it's better to have only one instance of SimpleDateFormat and always use this to parse your dates.
I also suggest to create this instance of SimpleDateFormat in front of your try block, so you solve your second problem and can use SimpleDateFormat.format(date) to parse your dates back to requested stringformat.

Working with Dates in Java

I need to work with dates and I wasn't sure how to go about that in Java since I have never done it before.
I am pulling dates from the Excel file and they can be retrieved in the Data format which would represent the date.
Ex:
2/1/2010
5/12/2011
8/15/2011
9/1/2011
9/1/2011
All my codes are pretty irrelvent to the question, but I am setting up a getter/setter method:
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
So my question is this, in what way when I am pulling the data from Excel:
temp.setDate((row.getCell(3).getDateCellValue());
I can set the limit so it only retrieves data from x amount of months. 8, 12, et.. from the last month/year displayed in the file, instead of going back all the way to 2010? I can provide more details if needed.
Edit: This is what I have now:
import java.util.Date;
Date date;
date = row.getCell(3).getDateCellValue();
It shows: Tue June 01 00:00:00
I don't care about Tuesday or 00:00:00, I just have a whole list of data and I only want to show x amount of months.
Edit: I figured it out. :)
The question is pretty vague, but if you are using Excel I have found it very beneficial to save the file as a 'filename.csv'. This format very easy to work with, it is comma delimited going across and newlines going down. If you are periodically checking the month, it would be easy to ensure that you only go x months backwards.
First you need to parse the dates accordingly using the SimpleDateFormat class. The result is a date object.
SimpleDateFormat df = new SimpleDateFormat( "M/d/yyyy" );
Date date = df.parse(row.getCell(3).getDateCellValue());
Then:
Calendar cal = Calendar.getInstance();
will return you an object ob type Calendar, where you can set the date by
cal.setTime(date);
Finally your loop reading the Excel file can determine according to the calendar object, if the date should be included / further processed by using:
int month = cal.get(Calendar.MONTH); // e.g. 11 for Nov
int year = cal.get(Calendar.YEAR); // e.g. 2011
You have to work with DateFormat.class fo parse the cell, or use a Calendar to put Day Month Year
EDIT
You can also use Calendar.class
final String[] tabDate = {"2/1/2010", "5/12/2011", "8/15/2011",
"9/1/2011", "9/1/2011"};
// Extract field's value
final Calendar c = Calendar.getInstance();
// Parse the list of stringDate
for (final String string : tabDate) {
System.out.println("Input string: " + string);
final String[] shortDate = string.split("/");
// Build Calendar
c.set(Integer.valueOf(shortDate[2]), Integer.valueOf(shortDate[0]),
Integer.valueOf(shortDate[1]));
// Extract date as you like
System.out.format("%25s : %d/%d/%d\t%s\n\n", c.getTime(),
c.get(Calendar.MONTH), c.get(Calendar.DATE),
c.get(Calendar.YEAR), c.getTimeInMillis());
}
Console :
Input string: 2/1/2010
Mon Mar 01 09:09:48 CET 2010 : 2/1/2010 1267430988109
Input string: 5/12/2011
Sun Jun 12 09:09:48 CEST 2011 : 5/12/2011 1307862588109
Input string: 8/15/2011
Thu Sep 15 09:09:48 CEST 2011 : 8/15/2011 1316070588109
Input string: 9/1/2011
Sat Oct 01 09:09:48 CEST 2011 : 9/1/2011 1317452988109
Input string: 9/1/2011
Sat Oct 01 09:09:48 CEST 2011 : 9/1/2011 1317452988109

Inconsistent ParseExeption with Data Format in Java

I wrote a simple Util method to convert a String in Java to util.Date. What I am not able to figure out is why the method works for the first input, and fails for the second one, given that the inputs are identical:
Code:
package util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class StringToDate {
public Date getDateFromString(String strDate, String dateFormat) {
DateFormat df = new SimpleDateFormat(dateFormat);
Date date = null;
try {
date = df.parse(strDate);
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println(date);
return date;
}
public static void main(String[] args) {
StringToDate s2d = new StringToDate();
s2d.getDateFromString("12-18-11, 10:36 AM","MM-dd-yy, hh:mm a");
s2d.getDateFromString("02-04-12, 01:17 PM","MM-dd-yy, hh:mm a");
}
}
Output:
Sun Dec 18 10:36:00 CET 2011
null
java.text.ParseException: Unparseable date: "02-04-12, 01:17 PM"
at java.text.DateFormat.parse(DateFormat.java:337)
at util.StringToDate.getDateFromString(StringToDate.java:17)
at util.StringToDate.main(StringToDate.java:33)
Logically, the output should've been Sat Feb 04 13:17:00 CET 2012 going by the first output. Why is the ParseException being thrown?
EDIT: The following two lines work correctly:
s2d.getDateFromString("02-04-12", "MM-dd-yy");
s2d.getDateFromString("01:17 PM", "hh:mm a");
Output:
Sat Feb 04 00:00:00 CET 2012
Thu Jan 01 13:17:00 CET 1970
But the exception happens when I try to parse both date and time together.
Do you have a non-breaking space, or some other Unicode space character, somewhere in either your date string or format mask?
I was able to reproduce your error if I replaced one of the spaces in the second of your date strings with a non-breaking space, such as Unicode character 160.

SimpleDateFormat is not parsing the milliseconds correctly

Background:
In my database table, I have two timestamps
timeStamp1 = 2011-08-23 14:57:26.662
timeStamp2 = 2011-08-23 14:57:26.9
When I do an "ORDER BY TIMESTAMP ASC", timeStamp2 is considered as the greater timestamp(which is correct).
Requirement: I need to get the difference of these timestamps (timeStamp2 - timeStamp1)
My implementation:
public static String timeDifference(String now, String prev) {
try {
final Date currentParsed = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(now);
final Date previousParsed = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").parse(prev);
long difference = currentParsed.getTime() - previousParsed.getTime();
return "" + difference;
} catch (ParseException e) {
return "Unknown";
}
}
The answer should have been 238ms, but the value that is returned is -653ms.
I'm not sure what I'm doing wrong. Any suggestions?
The format you are parsing and the format uses doesn't match. You expect a three digit field and are only providing one digits. It takes 9 and assumes you mean 009 when what you want is 900. Date formats are complicated and when you prove dates in a different format it may parse them differently to you.
The documentation says S means the number of milli-seconds and the number in that field is 9, so it is behaving correctly.
EDIT: This example may help
final SimpleDateFormat ss_SSS = new SimpleDateFormat("ss.SSS");
ss_SSS.setTimeZone(TimeZone.getTimeZone("GMT"));
for (String text : "0.9, 0.456, 0.123456".split(", ")) {
System.out.println(text + " parsed as \"ss.SSS\" is "
+ ss_SSS.parse(text).getTime() + " millis");
}
prints
0.9 parsed as "ss.SSS" is 9 millis
0.456 parsed as "ss.SSS" is 456 millis
0.123456 parsed as "ss.SSS" is 123456 millis
I'm not entirely sure, but the JavaDoc states this:
For parsing, the number of pattern letters is ignored unless it's needed to separate two adjacent fields.
This indicates that the milliseconds from 2011-08-23 14:57:26.9 would be parsed as 9 instead of 900. Adding the trailing zeros might work: 2011-08-23 14:57:26.900.
I'd suggest using Joda-Time. It handles these situations properly. In the following example, the milliseconds are correctly parsed as 200ms.
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class ParseMillis {
public static void main(String[] args) {
String s = "00:00:01.2";
DateTimeFormatter format = DateTimeFormat.forPattern("HH:mm:ss.S");
DateTime dateTime = format.parseDateTime(s);
System.out.println(dateTime.getMillisOfSecond());
}
}
I had the same problem with too accurate time from my logfiles with 6 digit milliseconds. Parsing Time gave up to 16 minutes difference! WTF?
16-JAN-12 04.00.00.999999 PM GMT --> 16 Jan 2012 04:16:39 GMT
Changing the number of digits reduced the erroneous difference and thanks to this thread I could identify the problem:
16-JAN-12 04.00.00.99999 PM GMT --> 16 Jan 2012 04:01:39 GMT
16-JAN-12 04.00.00.9999 PM GMT --> 16 Jan 2012 04:00:09 GMT
16-JAN-12 04.00.00.999 PM GMT --> 16 Jan 2012 04:00:00 GMT
As SimpleDateFormat internally handles only 3 digits I removed the unnecessary with a small regex (ignoring round-off errors, working for 1 up to n digits):
str = str.replaceAll("(\\.[0-9]{3})[0-9]*( [AP]M)", "$1$2");
Thanks to #Peter Lawrey for your answer, prevented me going insane :-)

Categories