Difference, in minutes, between two dates - java

I need to get the number of minutes between two dates. I know Joda is the best to use, but this is for an Android project, so I prefer to use a little external libraries as possible, and the app I'm building doesn't require the calculation to be surgically precise.
However, the code I'm using doesn't seem to be working. I'm trying to get the number of minutes between "11/21/2011 7:00:00 AM" and "11/21/2011 1:00:00 PM" (which should be 360 minutes), but the code I'm using returns 0:
int diff = minutesDiff(GetItemDate("11/21/2011 7:00:00 AM"), GetItemDate("11/21/2011 1:00:00 PM"));
public static Date GetItemDate(final String date)
{
final Calendar cal = Calendar.getInstance(TimeZone.getDefault());
final SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss a");
format.setCalendar(cal);
try {
return format.parse(date);
} catch (ParseException e) {
return null;
}
}
public static int minutesDiff(Date earlierDate, Date laterDate)
{
if( earlierDate == null || laterDate == null ) return 0;
return (int)((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
}

If your GetItemDate is failing for either date, you will get zero. On the catch statement, place a println or debug to output the issue and see if that tells you something.
Also, just as a matter of practice, I'd change:
return (int)((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
to:
long result = ((laterDate.getTime()/60000) - (earlierDate.getTime()/60000));
return (int) result;
This gives you the opportunity to view the result of the math in an IDE.

I debugged through your code: there is ParseException in GetItemDate() for both of the date strings like:
Unparseable date: 11/21/2011 07:00:00 AM
The problem is that parsing AM/PM hours only works with "hh" (small caps!) or "KK". At least that is the case in my phone (it seems some of us didn't see this issue at all). I tested it also works with a single "h" too.
hh = 1-12
KK = 0-11
HH = 0-23
kk = 1-24
Change your SimpleDateFormat line to this:
final SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy hh:mm:ss a", Locale.US);
This post explains the "a" and Locale: Unable to parse DateTime-string with AM/PM marker
PS. I'm from Finland so I must use the "Locale.US" part for this to work. US residents may test the code without it, I think.

Related

Java Date .after() method not comparing 12:00 correctly [duplicate]

This question already has answers here:
12:xx shown as 00:xx in SimpleDateFormat.format("hh:mm:ss")
(1 answer)
Comparing two times in android
(4 answers)
Closed 2 years ago.
After some debugging, I found that it was because 12:00 was being set to 0:00, but surely if this was a 24-hour clock only 24:00 would be set to 0:00
SimpleDateFormat time_format = new SimpleDateFormat ("hh:mm");
String start_time = "11:00"
String end_time = "12:00"
try { //parses both times to the date data type
start_time_format = time_format.parse(start_time);
end_time_format = time_format.parse(end_time);
} catch (ParseException e) {
e.printStackTrace();
}
if (end_time_format.after(start_time_format)){
}else{
//how come this is always true
}
This is because those old Date and SimpleDateFormat are troublesome.
What happens here is that, because hh is used, the number 12 'overflows' to 0 here. The code which actually does this is found in the SimpleDateFormat source code, in the subParse method.
You should use HH. And while you're at it – you should use modern Java Date and Time API from the java.time package:
String startTimeStr = "11:00";
String endTimeStr = "12:00";
LocalTime startTime = LocalTime.parse(startTimeStr);
LocalTime endTime = LocalTime.parse(endTimeStr);
// No need for a explicit formatting string, because the default is used here,
// which is HH:mm[:ss[.nnnnnnnnn]]
if (endTime.isAfter(startTime)) {
System.out.println("If");
}
else {
System.out.println("Else");
}
But even if you used an explicit DateTimeFormatter with the pattern string hh:mm, then a DateTimeException would have been thrown because the value to be parsed were ambiguous. 11:00 and 12:00 in a twelve-hour clock could mean two things: either AM or PM. The parser by default doesn't like ambiguous values, so instead of just choosing one and moving on, causing confusion to everyone, the authors decided to immediately stop the parsing process and throw an exception. The following code shows this:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("hh:mm");
String startTimeStr = "11:00";
LocalTime startTime = LocalTime.parse(startTimeStr, formatter);
Date class of java set 12:00 to 00:00 of the day.therefore new date with 12:00 convert to Jan 01 11:00:00 1970.To avoid this effect you can use "HH:mm" format string.

validation to check date formatting is not working as expected

I have following code which checks for the valid format date
private void validateDate(String date){
try {
String validDate = "MM/dd/yyyy";
SimpleDateFormat format = new SimpleDateFormat(validDate);
format.setLenient(false);
Date theDate = new Date();
theDate = format.parse(date);
}
catch (Exception e) {
}
}
I am passing the date value as 06/25/20014. In this year format is wrong and I was expecting that it will throw exception and will go inside catch, but it never happens and it successfully passes the code format.parse(date); due to which my application is not throwing error.
I also debugged the line format.parse(date); and it returns "Fri Jul 31 00:00:00 MST 20015". I am not sure why that line is not throwing any exception.
Thanks for your help!!
In the standard date formats for SimpleDateFormat, the number 'y' 's doesn't necessarily correspond to the number of digits (it isn't a regex). One or two y's is an indicator for a 2 digit year (15, 98, etc.) and 3 or more y's is an indicator for the full year.
If this line did throw an exception, then your program would stop working after year 9999, which is not usually what you want. Sure, you do not expect your program to last this long, but people did not expect to last up to y2k either; so Java's choice not to block at any date seems reasonable.
If you want to check the year is between 1 and 9999, you can just write a if: (see related question I want to get Year, Month, Day, etc from Java Date to compare with Gregorian Calendar date in Java. Is this possible?)
Calendar cal = Calendar.getInstance();
cal.setTime(date);
if (cal.get(Calendar.YEAR) > 9999)
throw new RuntimeException("Blah");
This is actually documented behaviour (at least for the Gregorian calendar, which I assume you will be using unless you explicitely set it to a different calendar):
Year: If the formatter's Calendar is the Gregorian calendar, the
following rules are applied.
For formatting, if the number of pattern
letters is 2, the year is truncated to 2 digits; otherwise it is
interpreted as a number. For parsing, if the number of pattern letters
is more than 2, the year is interpreted literally, regardless of the
number of digits.
And yes, 20015 will probably be a valid year some day ;) If you want to check for exactly 4 digits, you might want to consider using a regular expression matching before parsing.
I can see that the provided date is valid (although 18k years ahead)
public static void validateDate(String date){
try {
String validDate = "MM/dd/yyyy";
SimpleDateFormat format = new SimpleDateFormat(validDate);
format.setLenient(false);
Date theDate = format.parse(date);
Calendar c = new GregorianCalendar();
c.setTime(theDate);
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH);
int day = c.get(Calendar.DAY_OF_MONTH);
int pos = c.get(Calendar.DAY_OF_WEEK);
if (Calendar.WEDNESDAY == pos)
System.out.print("day is Wednesday on " + year + "/" + (month+1) + "/" + day);
}
catch (Exception e) {
System.out.print("Inside exception block " + e);
}
}
prints: day is Wednesday on 20014/6/25
If you need some year validation you can add additional check
if (year > MAX_YEAR) {
// add error here
}
Here is DEMO

How to format the current date with Suffix to Superscript?

I am using the SimpleDateFormatter
public static final DateFormat DATE_FORMAT_FULL_FULL_SPACES =
new SimpleDateFormat("dd MMMM yyyy", Locale.getDefault());
and Current Date is passed at that time, It should display as
1st JULY 2014 where st should be superscript.
How can I go further ?
Create these methods
private String getFormatedDate(){
String dayNumberSuffix = getDayNumberSuffix(Calendar.getInstance().get(Calendar.DAY_OF_MONTH));
SimpleDateFormat dateFormat = new SimpleDateFormat(" d'" + dayNumberSuffix + "' MMMM yyyy");
return dateFormat.format(Calendar.getInstance().getTime());
}
private String getDayNumberSuffix(int day) {
if (day >= 11 && day <= 13) {
return "<sup>th</sup>";
}
switch (day % 10) {
case 1:
return "<sup>st</sup>";
case 2:
return "<sup>nd</sup>";
case 3:
return "<sup>rd</sup>";
default:
return "<sup>th</sup>";
}
}
How to call?
String str = getFormatedDate();
txtDate.setText(Html.fromHtml(str));
OutPut :
The superscript part isn't the first tricky part here - although it's not clear how you'd want that to be represented anyway (HTML with <sup> tags? something else?)
The first tricky part is knowing how to get the ordinal (st, nd, rd, th) and doing that appropriately for different cultures (which can have very different rules). This isn't something that SimpleDateFormat supports, as far as I'm aware. You should also be aware that different cultures might not use dd MMMM yyyy as their normal full date format - it could look very odd to some people.
I would think very carefully about:
Which locales you need to support
Whether you really need the ordinal part
How you want the superscript to be represented in a string
If you only need to handle English, then the ordinal part isn't too hard (you can probably find examples of a String getOrdinal(int value) method online, or write your own in 5 minutes). If you're also happy to always use a "day first" format, then you'd probably only need to format the month and year in SimpleDateFormat, e.g.
public String formatWithOrdinal(Calendar calendar) {
DateFormat formatter = new SimpleDateFormat(" MMMM yyyy", Locale.getDefault());
formatter.setTimeZone(calendar.getTimeZone());
int day = calendar.get(Calendar.DATE);
return day + toSuperscript(getOrdinal(day)) + formatter.format(calendar.getTime());
}
Where toSuperscript would use HTML or whatever you need to superscript the value.
In short, you have a lot of separable concerns here - I strongly suggest you separate them, work out your exact requirements, and then implement them as simply as you can.

Having trouble format a string into a date object

I have a string that looks like this
Aug 16, 2013,11:30:10
The comma can be replaced by a different separator and the date & time position can be switched.
I am trying to use this format for my SimpleDateFormat(dtString is the String above):
Date d = null;
try {
d = new SimpleDateFormat("MMMM dd, yyyy,hh:mm:ss", Locale.ENGLISH).parse(dtString);
} catch (ParseException ex) {
Logger.getLogger(MonKaiClientImpl.class.getName()).log(Level.SEVERE, null, ex);
}
return d;
but when I run d.getYear() the result is 113.
All of the other Date methods return the correct result except .getYear(). Am I missing something? Is my SimpleDateFormatter wrong?
You should not use Date#getYear. It's deprecated.
As for the result you get, it's as specified in the Javadoc:
Returns a value that is the result of subtracting 1900 from the year that contains or begins with the instant in time represented by this Date object, as interpreted in the local time zone.
Use Calendar API instead. Or even better, if you can use 3rd party library, then I would really suggest you to try Joda Time. Or wait for Java 8 to come next year, that has a new Date Time API.
Simple way to check the result of SimpleDateFormat parsing is this
System.out.println(d);
and it shows correct result
Fri Aug 16 11:30:10 EEST 2013
the problems is that Date methods interpreting year, month, day, hour, minute, and second are deprecated. See Date API

Comparing hours in java

First of all forgive my English :-(
I have a problem with hours on java. Let's see it by an example:
DateFormat datos = new SimpleDateFormat ("hh:mm:ss");
Date ac, lim;
String actual,limit;
actual="18:01:23";
limit="00:16:23";
ac=datos.parse(actual);
lim=datos.parse(limit);
if(ac.compareTo(lim)==-1){.......
I need to solve this case in which limit is past midnight and actual hour is before midnight. My program says that actual has reached limit and it isn't correct because at the example, it has still 6 hours to finish.
I tried to solve it with DateFormat class but it doesnt see this case. I tried it with Time class too but its methods are deprecated.
How can I solve this?
Use HH instead of hh in your SimpleDateFormat:
DateFormat datos = new SimpleDateFormat("HH:mm:ss");
hh is the 12-hour clock (hours go from 1 to 12).
HH is the 24-hour clock (hours go from 0 to 23).
But besides that, there are other things wrong with this. Class Date is not very well suited to contain only a time. If you do this, it will be parsed as 01-01-1970 with the specified time. So 18:01:23 becomes 01-01-1970, 18:01:23 and 00:16:23 becomes 01-01-1970, 00:16:23. You probably wanted to compare 18:01:23 to 00:16:23 the next day.
Try something like this:
String actual = "18:01:23";
String limit = "00:16:23";
String[] parts = actual.split(":");
Calendar cal1 = Calendar.getInstance();
cal1.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parts[0]));
cal1.set(Calendar.MINUTE, Integer.parseInt(parts[1]));
cal1.set(Calendar.SECOND, Integer.parseInt(parts[2]));
parts = limit.split(":");
Calendar cal2 = Calendar.getInstance();
cal2.set(Calendar.HOUR_OF_DAY, Integer.parseInt(parts[0]));
cal2.set(Calendar.MINUTE, Integer.parseInt(parts[1]));
cal2.set(Calendar.SECOND, Integer.parseInt(parts[2]));
// Add 1 day because you mean 00:16:23 the next day
cal2.add(Calendar.DATE, 1);
if (cal1.before(cal2)) {
System.out.println("Not yet at the limit");
}
The library Joda Time is a popular Java date and time library that is much better designed than the standard Java date and calendar API; consider using it if you have to work with dates and times in Java.
With Joda Time you could do this:
String actual = "18:01:23";
String limit = "00:16:23";
DateTimeFormatter df = DateTimeFormat.forPattern("HH:mm:ss");
DateTime ac = df.parseLocalTime(actual).toDateTimeToday();
DateTime lim = df.parseLocalTime(limit).toDateTimeToday().plusDays(1);
if (ac.isBefore(lim)) {
System.out.println("Not yet at the limit");
}
As a quick and dirty solution:
final DateFormat datos = new SimpleDateFormat("HH:mm:ss");
Date ac;
final Date lim = new Date();
String actual, limit;
actual = "18:01:23";
limit = "00:16:23";
try {
ac = datos.parse(actual);
lim.setTime(ac.getTime() + TimeUnit.MINUTES.toMillis(16) + TimeUnit.SECONDS.toMillis(23));
if ( ac.before(lim) ) {
// TODO
}
} catch ( final ParseException e ) {
e.printStackTrace();
}

Categories

Resources