Is there some sort of exception in Java to catch an invalid Date object? I'm trying to use it in the following method, but I don't know what type of exception to look for. Is it a ParseException.
public boolean setDate(Date date) {
this.date = date;
return true;
}
In the method you provide, there is no way to catch an exception, because none will be thrown by the simple assignment. All you can do is maybe the below change:
if(date == null) return false;
But even that's not graceful. You may want to do something with this.date or throw an exception up if that's the desired behavior.
What you are really seeking is either:
ParseException - thrown by a DateFormat object when it attempts to parse(), which would happen before your set method
IllegalArgumentException - thrown by a SimpleDateFormat constructor, again it would happen before your set method. Indicates you provided an invalid format string.
You'd want to catch one of those (probably #1). But it has to happen before your method call. Once you have a Date object, it is either null or valid.
This might not be related to the original question. But you must notice the method name, which is setDate(). Do you think it sounds like it will return something? Or if it may, then do you think its a good idea to return a boolean there? IMO, do something like this,
public void setDate(Date date) {
this.date = date;
}
public boolean isDateNull() { // or something
return this.date == null;
}
In this method, there is no need to worry about an exception. The date is already created by the time you get into this method. If you are parsing a date, it would have done outside of this code. The best you could do is make sure the date is not null.
It depends on what you mean by an invalid date. Did you mean to give us a method signature that looked more like this?
public void setDate(String date) throws ParseException {
this.date = SomeDateFormat.getInstance().format(date);
}
Otherwise, as the others stated the simple act of assigning a Java date object to a field shouldn't be exceptional as it is either an instance of Date already, or null.
If you are just trying to parse a string into a java.util.Date, look at DateFormat, FastDateFormat (apache, thread safe), or Joda Time.
Related
I have created a class called Person which uses Optional<LocalDate> to store a person's birthday as a field. I have a method called timeToNextBirthday which computes the interval between the time of calling and the next birthday. The problem I'm having is that since birthday is optional, the method sometimes has nothing it can return. I don't know if I should throw an exception or just return some default object. I also considered making the return type optional and returning an empty optional if the birthday is unknown. This is a snippet of my code so far, using the exception option.
public class Person {
private Optional<LocalDate> dateOfBirth;
public Period timeToNextBirthday() throws NoSuchElementException {
if(!dateOfBirth.isPresent()) {
throw new NoSuchElementException("Birthday is unknown");
}
LocalDate currentDate = LocalDate.now();
// Assume this year's birthday has not passed and set next birthday to this year
LocalDate nextBirthday = dateOfBirth.get().withYear(currentDate.getYear());
// Add a year to nextBirthday if this year's birthday has already passed or is today
if (currentDate.isAfter(nextBirthday) || currentDate.equals(nextBirthday)) {
nextBirthday = nextBirthday.plusYears(1);
}
return Period.between(currentDate, nextBirthday);
}
}
How should I proceed?
Consider this: Changing the method's return type to Optional<Period> would make it very clear to the user of this method that it may not result in an usable Period due to dateOfBirth being optional and the user space code must be made to accomodate for this fact.
This sort of type carry-over is just fine if you don't want to throw exceptions (like you currently do) as it allows you as an API designer to assist the user of your code to cover all bases in a secure, null safe and self documenting way. Of course writing a bit of javadoc explaining why the return type is wrapped in Optional won't hurt either :)
I am trying to get two dates from a SQL query, and compare them. So to compare them, I believe I will need to use the "Date" type. Here is what I am trying, I know I am getting the date from the resultSet incorrectly, but I am not sure how to do it.
Date validDate = new Date(0);
Date currentDate = new Date(0);
// query
if (result.next()) {
validDate = (result.getObject("validDate")!=null)?result.getObject("validDate").toDate():"";
currentDate = (result.getObject("currentDate")!=null)?result.getObject("currentDate").toDate():"";
}
if (currentDate > validDate) {
//do something
}
So again, this was my attempt, but I cant seem to get it to run. Thanks in advance.
EDIT: the query has TO_CHAR(column, 'MM-DD-YYYY') on the two dates that I am getting.
EDIT: Now you've mentioned that your query converts the date to a string, stop doing that. You'll end up reparsing it on the calling side - so why perform two conversions pointlessly? Keep string conversions to the absolute minimum - stay in the most appropriate data type wherever possible.
Original answer
You haven't shown what result is, but you probably want something like ResultSet.getDate() to fetch the date values.
Note that your comparison code won't work either because there's no > for Date - you'd need something like:
if (currentDate.after(validDate))
Or fetch the underlying number of millis:
if (currentDate.getTime() > validDate.getTime())
Additionally:
You can't assign "" to a Date variable - a string isn't a Date.
You can just call ResultSet.getDate() and check whether the returned value is null, rather than calling getObject first and then getDate()
Try currentDate.after(validDate)
To compdare dates I always use the before and after methodes of Date.
Some nasty things can happen when accessing dates via the getObject method. You should try to use the rs.getTimestamp (with timeinfo) or the rs.getDate (without timeinfo) methods.
Also, because of the rather complex hierarchy of Date-objects you should compare Dates only using the date1.compareTo(date2) > 0 method.
if your result object is ResultSet, then
Date validDate = result.getTimestamp("validDate");
Date currentDate= result.getTimestamp("currentDate");
// you can add null checks here too....
// you can also use if (currentDate.getTime() > validDate.getTime()){}
if (currentDate.before(validDate)) {
//some code inhere...
}
There are at least three things wrong with your code:
"" is a String literal, so you cannot use it int your ternary expressions to be assigned to a variable of type Date - use null instead so you don't need a ternary
ResultSet.getObject() returns an Object, which does not have a toDate() method. Instead, simply use ResultSet.getDate()
You cannot compare Date instances using a > operator. You have to use the before() and after() methods of the Date class
Taking all this together, the following code might work:
Date validDate = new Date(0);
Date currentDate = new Date(0);
if (result.next()) {
validDate = result.getDate("validDate");
currentDate = result.getDate("currentDate");
}
if (currentDate.after(validDate)) {
//do something
}
The if clause may have to include some extra logic to deal with null values though. It's better to do that than to leave that to implicit conversions, too.
Greetings,
I have one simple condition that never passes:
if(datas.date.getTime()-temps.date.getTime()>=5000)
I want to check if it has been 5 seconds from one to another.
Update:
Here is setter and getter:
public class Data{
Date date;
public Date getDate() {
return date;
}
public void setDate() {
Date now = new Date();
this.date = now;
}
}
So, I call
Data data;
data.setDate();
processValues(data);
this is processValues:
public void processValues(Data dat){
if(datas.size()==7){
writeValues(datas);
datas=new Vector<Data>();
temps=new Vector<Data>();
}
temps.add(dat);
datas.add(dat);
}
this is writeValues:
public void writeValues(Vector<Data> datas){
for(i=0;i<temps.size();i++)
for(j=0;j<datas.size();j++){
if(temps.elementAt(i).epc==datas.elementAt(j).epc)
if(datas.elementAt(j).date.getTime()-temps.elementAt(i).date.getTime()>=5000)
try {
dao.writeToDatabase(datas.elementAt(j));
i=j;
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
If you output datas.date.getTime() and temps.date.getTime(), which one is higher? My guess is that they are reversed and the subtraction is giving a negative number - which of course would never be greater than 5000. Or the data points aren't 5 seconds apart.
You said that your processValues() method looks like this:
public void processValues(Data dat){
if(datas.size()==7){
writeValues(datas);
datas=new Vector<Data>();
temps=new Vector<Data>();
}
temps.add(dat);
datas.add(dat);
}
You're adding the same instance ("dat") to both vectors. If you update one it will necessarily update the other, so there can never be a difference in the date field.
You say you have a getter that looks like this:
public Date getDate() {
return date;
}
Date objects are mutable, so you should probably copy defensively. You can use clone() for this.
Based on that and the syptoms of your problem, perhaps your two Date objects are actually the same object. Have you tried using == (or !=) to confirm that they are indeed separate objects?
Update
Based on the updated information I can see why that condition never passes. I don't really understand what you want you code to do, however. You're essentially just testing if you can create 7 objects in less than 5 seconds, and if you can't then you write some of them out. Either way you clear temps and datas, whether you wrote the objects out or not. My guess is that you do not want to clear these vectors of elements that were not written out. I also don;t understnad why you have both datas and temps when they contain exactly the same elements.
So I have function that formats a date to coerce to given enum DateType{CURRENT, START, END}
what would be the best way to handling return value with cases that use switch statement
public static String format(Date date, DateType datetype) {
..validation checks
switch(datetype){
case CURRENT:{
return getFormattedDate(date, "yyyy-MM-dd hh:mm:ss");
}
...
default:throw new ("Something strange happend");
}
}
OR throw excpetion at the end
public static String format(Date date, DateType datetype) {
..validation checks
switch(datetype){
case CURRENT:{
return getFormattedDate(date, "yyyy-MM-dd hh:mm:ss");
}
...
}
//It will never reach here, just to make compiler happy
throw new IllegalArgumentException("Something strange happend");
}
OR return null
public static String format(Date date, DateType datetype) {
..validation checks
switch(datetype){
case CURRENT:{
return getFormattedDate(date, "yyyy-MM-dd hh:mm:ss");
}
...
}
return null;
}
What would be the best practice here ? Also all the enum values will be handled in the case statement
Throw an exception, since this is an exceptional case.
And throw it outside the switch, it would be more readable. Otherwise it sounds like "the default case is exceptional".
I think that throw new IllegalArgumentException("Something strange happend") is the best pratice.
Using null will just presumibly cause a NullPointerException somewhere when you use the return value but it will be less informative than raising a specific exception that describes the problem!
And you know: clear errors = better developing.
I would go with the first approach (but with IllegalArgumentException as in your second approach). You should include a default statement to guard against cases when someone modifys (extends) your enum. Putting the exception in the default-statement makes clear to the reader that the code is never supposed to get past the switch-statement. Otherwise they would have to check if really all of the enum values are in the switch.
Exceptions, as you can obey more to the parent than a single return int can. Usually you use Exceptions where they exist (C++), and return values where not (C).
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.