Sorry, but I come to you with a problem that should have been answered already. Alas, my google-foo is weak and I humbly come to ask for your guidance.
WHY DOES AN EXTRA 59 minutes appear??
Ok, so I got a "Clock In" thing going and my calculations go wrong when the persons out minutes are the same as the in minutes. I remember hearing about this problem before, but with no solution. Just a "Well, that's how it is. Good luck, brah." I've tried adding and subtracting minutes during calculation, but that just pushes the problem +/- the time added/subtracted. I've also tried calculating to the second (not shown below), but that also didn't help.
Obligatory, here's my code:
//calculateTotalHours()
public static String calculateTotalHours(Cell inTime, Cell outTime, Cell breakStart, Cell breakEnd)
{
System.out.println(LOG + "calculateTotalHours");
SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm");
Date in, out, start, end;
if(null != inTime && null != outTime && null != breakStart && null != breakEnd)
{
try
{
in = timeFormat.parse(inTime.getStringCellValue());
out = timeFormat.parse(outTime.getStringCellValue());
start = timeFormat.parse(breakStart.getStringCellValue());
end = timeFormat.parse(breakEnd.getStringCellValue());
long lunchTotal = end.getTime() - start.getTime();
long totalWork = out.getTime() - in.getTime();
long totalTime = totalWork - lunchTotal;
long diffHours = totalTime/HOURS % 24;
totalTime -= diffHours;
long diffMinutes = totalTime/MINUTES % 60;
totalTime -= diffMinutes;
return String.format("%02d:%02d", diffHours, diffMinutes);
}
catch (ParseException e) {e.printStackTrace();}
}
else
{
try
{
if(null == breakStart || null == breakEnd) {
in = timeFormat.parse(inTime.getStringCellValue());
out = timeFormat.parse(outTime.getStringCellValue());
long totalTime = out.getTime() - in.getTime();
long diffHours = totalTime/HOURS % 24;
totalTime -= diffHours;
long diffMinutes = totalTime/MINUTES % 60;
totalTime -= diffMinutes;
return String.format("%02d:%02d", diffHours, diffMinutes);
}
else if(null == inTime.getStringCellValue())
{
System.out.println(LOG + "inTime is blank");
return "-1";
}
}
catch (ParseException e) {e.printStackTrace();}
}
return "-1";
}
My sincere apologies for the mess I call my code. And let me know if calculating by the second or millisecond is the way to go. I may have overlooked something when trying it that way.
2020 UPDATE:
I wanted to update my code and what I should have done. First, I should have separated the cells, strings, and time more. Second, I should have broken it down to more methods for clarity.
I'll just show getTotalHours(startTimeString, endTimeString):
DateTimeFormatter format = DateTimeFormatter.ofPattern("HH:mm");
LocalTime end = LocalTime.parse(endTimeString.trim(), format);
LocalTime start = LocalTime.parse(startTimeString.trim(), format);
return Duration.between(start, end).toHoursPart()%24
+ ":"
+ Duration.between(start, end).toMinutes()%60;
private static final String defaultHours = "-1";
public static String calculateTotalHours(Cell inTime, Cell outTime, Cell breakStart, Cell breakEnd)
{
try {
LocalTime inLocalTime = LocalTime.parse(inTime.getStringCellValue());
LocalTime outLocalTime = LocalTime.parse(outTime.getStringCellValue());
LocalTime breakStartTime = LocalTime.parse(breakStart.getStringCellValue());
LocalTime breakEndTime = LocalTime.parse(breakEnd.getStringCellValue());
Duration lunch = Duration.between(breakStartTime, breakEndTime);
Duration present = Duration.between(inLocalTime, outLocalTime);
Duration worked = present.minus(lunch);
return String.format("%02d:%02d", worked.toHours(), worked.toMinutesPart());
} catch (DateTimeParseException dtpe) {
System.out.println(dtpe);
return defaultHours;
}
}
The above code uses the toMinutesPart
method that was introduced in Duration
in Java 9. Assuming you are using ThreeTenABP (details below) or an earlier Java version, it’s:
long hours = worked.toHours();
long minutes = worked.minusHours(hours).toMinutes();
return String.format("%02d:%02d", hours, minutes);
For clarity I have omitted the null checks, I am sure you can handle those.
As said in the comments, leave time math to well-tested library methods. It’s not only less error-prone, it also gives clearer code. I am using java.time
, the modern Java date and time API. It also saves us from specifying an explicit formatter since LocalTime.parse()
parses your format of HH:mm
as its default (it’s ISO 8601 format).
As kshetline in the other answer I believe that totalTime
is in milliseconds and diffHours
is hours. So when you do totalTime -= diffHours;
, you subtract hours from milliseconds and you’re bound to get an incorrect result (same with totalTime -= diffMinutes;
, by the way, but you’re not using the result of the latter subtraction, so this error doesn’t show).
Yes, java.time
works nicely on older and newer Android devices. It just requires at least Java 6.
org.threeten.bp
with subpackages.java.time
.java.time
was first described.java.time
to Java 6 and 7 (ThreeTen for JSR-310).