Calculate time difference in java - java

I want to calculate time difference in java. I am calculating successfully only in between 1 hour. When I enter the time above 1 hour calculation is getting Wrong.
String start= "12:00:00";
String end= "12:50:00";
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
Date date1 = format.parse(start);
Date date2 = format.parse(end);
long difference = date2.getTime() - date1.getTime();
System.out.println(difference/1000);
double time = difference/1000;
double tot = time/60;
JOptionPane.showMessageDialog(this, tot);
result displayed 50mins successfully from above code
I modified the same code and it looks like this:
String start = "12:00:00";
String end = "01:50:00";
SimpleDateFormat format = new SimpleDateFormat("HH:mm:ss");
Date date1 = format.parse(start);
Date date2 = format.parse(end);
long difference = date2.getTime() - date1.getTime();
System.out.println(difference/1000);
double time = difference/1000;
double tot = time/60;
JOptionPane.showMessageDialog(this, tot);
here result displayed
-610.0 I don't know why I need to display the output of 1.50

Because you input the time in the AM|PM form, but your code is supposed to work with the 24-hour time format.
Change the time from
String end = "01:50:00";
to
String end = "13:50:00";
and it will work like a charm :)
(Or you can change the code to work with AM-PM time model, but it will be more difficult.

Actually, I would use the new OffsetTime classes to solve this problem.
Here is some example code:
public static void distance(String strTime1, String strTime2) {
OffsetTime time1 = OffsetTime.parse(strTime1);
OffsetTime time2 = OffsetTime.parse(strTime2);
int time1Seconds = time1.get(ChronoField.MINUTE_OF_DAY);
int time2Seconds = time2.get(ChronoField.MINUTE_OF_DAY);
System.out.println("Time 1 in seconds: " + time1Seconds);
System.out.println("Time 1 in seconds: " + time2Seconds);
System.out.println("Distance: " + Math.abs(time1Seconds - time2Seconds));
}
What you are doing is to parse a String simliar to yours. As a difference, I would recommend you to always add timezone information. Since it probably doesn't matter much in your case, I'd just add +00:00.
Please not Maths.abs(). As long as you are interested in the distance between both times and not in which direction the distance is, you can use this to get rid of minus or plus prefixes and use the absolute value.
That way you can create OffsetTime by parsing this string. After that you can read the minute of the day.
Please try it with:
public static void main(String[] args) {
distance("10:00:00+00:00", "12:00:00+00:00");
distance("12:30:00+00:00", "12:31:00+00:00");
distance("12:31:00+00:00", "12:30:00+00:00");
}
The results would be:
Time 1 in seconds: 600
Time 1 in seconds: 720
Distance: 120
Time 1 in seconds: 750
Time 1 in seconds: 751
Distance: 1
Time 1 in seconds: 751
Time 1 in seconds: 750
Distance: 1
You mentioned that you need fractions of minutes, like 1.5. Fractions are always complicated and not precise. That's why people invented BigDecimal. However, in your case BigDecimal doesn't help. I would recommend you to use a smaller unit, like seconds.
Just change your code to:
int time1Seconds = time1.get(ChronoField.SECOND_OF_DAY);
int time2Seconds = time2.get(ChronoField.SECOND_OF_DAY);
Here is some Javadocs:
https://docs.oracle.com/javase/8/docs/api/index.html?java/time/LocalDateTime.html
And a tutorial to the new classes (JDK8):
https://docs.oracle.com/javase/tutorial/datetime/iso/timezones.html

From SimpleDateFormat
Letter | Date or Time Component
H | Hour in day (0-23) .
h | Hour in am/pm (1-12)
So in your case you have "HH:mm:ss" which stands for 24Hr time format.
and its start from 00:00 till 23:59
So you can change this to like below for above pattern:
String start = "12:00:00";
String end = "13:50:00";
Or you can change your pattern like below:
SimpleDateFormat format = new SimpleDateFormat("hh:mm:ss");
String start = "12:00:00";
String end = "01:50:00";
See result: code output

Related

Countdown adds one hour between April and October

I'm working on simple countdown app to tell me how long until certain GMT time.
example:
input: 01-05-2021-02-00-00
output: (if entered time is local) 72 days, 15 hours, 21 mins, 49 secs
output(if entered time is gmt): 72 days, 17 hours, 21 mins, 33 secs
...there should be 16 not 17 hours i believe.
Everything's working fine untill input is between 1. April and 31 October. I give it GMT time and it transforms it to my local (berlin +1) time. If entered time is from mentioned interval it shows +2 hours differencer between berlin and GMT. since it is like this only for certain period of year (any year) it looks weird I don't know what went wrong?
my code:
String result = "";
String date = input;
SimpleDateFormat date_format = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
Date target_date = null;
try {
target_date = date_format.parse(date);
} catch (ParseException e) {
result += e.getMessage();
}
Date now = new Date();
long secs = 0;
if(local_time_radio_btn.isSelected()) {
secs = (target_date.getTime() - now.getTime()) / 1000;
}else {
int offset = target_date.getTimezoneOffset();
long n = 1000 * offset * 60;
long gmt = target_date.getTime() -n;
long now_gmt = now.getTime();
secs = (gmt - now_gmt) / 1000;
}
long days = secs / (60*60*24);
secs = secs % (60*60*24);
long hours = secs / (60*60);
secs = secs % (60*60);
long mins = secs / 60;
secs = secs % 60;
result += days+" days, "+hours+" hours, "+mins+" mins, "+secs +" secs";
java.time
I strongly recommend that you use java.time, the modern Java date and time API, for your date and time work.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-uuuu-HH-mm-ss");
String input = "01-05-2021-02-00-00";
LocalDateTime targetLdt = LocalDateTime.parse(input, formatter);
// German time case
ZoneId zone = ZoneId.of("Europe/Berlin");
ZonedDateTime now = ZonedDateTime.now(zone);
ZonedDateTime target = targetLdt.atZone(zone);
long days = ChronoUnit.DAYS.between(now, target);
ZonedDateTime afterDays = now.plusDays(days);
Duration timeDiff = Duration.between(afterDays, target);
String result = days + " days, " + timeDiff.toHours() + " hours, "
+ timeDiff.toMinutesPart() + " mins, "
+ timeDiff.toSecondsPart() + " secs";
System.out.println(result);
When I ran the code just now (2021-02-18T17:23:35.47 in Berlin), the output was:
71 days, 8 hours, 36 mins, 24 secs
For the UTC (or GMT) case you only need to change one line:
// GMT case
ZoneId zone = ZoneOffset.UTC;
71 days, 9 hours, 36 mins, 24 secs
What went wrong in your code?
First, don’t use SimpleDateFormat and Date as they are poorly designed and long outdated. Even if you insisted on using Date, you should definitely stay away from its getTimezoneOffset method. It has been deprecated since 1997 because it works unreliably across time zones.
Why your code gives an incorrect result in the months you mention is that it counts a day as always 24 hours. On March 28 the EU will transit to summer time (DST), so that day is only 23 hours long, giving rise to an error of exactly 1 hour. On October 31 this year the opposite transisiton may happen (I don’t think it’s been decided yet, but Java thinks that it does), so that day is 25 hours, balancing out for dates after that. Until summer time next year.
Which leads to the next point: don’t do time math yourself. It’s so easy to get wrong. And even when you get it right, it’s hard for the reader to convince oneself that it’s right. You have got a reliable date and time library that is happy to do it for you.
Link
Oracle tutorial: Date Time explaining how to use java.time.
What's weird about your code is that you're first parsing the input string according to a SimpleDateFormat instance that's configured to use local timezone (so, the resulting Date is wrong if the input was meant to be UTC), and then put a lot of effort into re-adjusting the point in time to UTC if that's what the user requested.
Instead, it would be clearer and more robust to have two SimpleDateFormat instances, one with the local timezone, and one with UTC, like:
SimpleDateFormat dateFormatLocal = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
SimpleDateFormat dateFormatUTC = new SimpleDateFormat("dd-MM-yyyy-HH-mm-ss");
dateFormatUTC.setTimeZone(TimeZone.getTimeZone("UTC"));
and select the correct one already when parsing.
By the way, your re-adjusting code uses deprecated features of the Date class, like getTimezoneOffset(), something that should be avoided since Java 1.1.

Checking dates if it is in a range

My Java FX app handles hours worked. I have work start and end time in 2 date fields. I succeeded in calculating the differences between 2 datesTime; but now how could I check if the result is in a night or day range???? The day begin at 6 and ends at 22h. For example someone who worked between 3Am till 11Pm.
Here is below how I did to have the total number of hours worked.
public void CalculNbreJourTravaille() {
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyy HH:mm");
try {
Date ddtt = format.parse(ddt.getText());
Date dftt = format.parse(dft.getText());
long diff = dftt.getTime() - ddtt.getTime();
long diffhours = diff / (60*60*1000)%24;
long diffdays = diff/(24*60*60*1000);
long total = diffhours + (diffdays*24);
result.setText(total + " Hours");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
We have workers who can work beyond 10PM, and the pay would not be the same. If they work after 10pm, they will have a special pay. We pay at the end of the work. They could would work only 10 days or more.
You should use the new DateTimeFormatter class to give you a LocalDateTime object, which you can pull the hour from.
DateTimeFormatter format = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
LocalDateTime localDateTimeFrom = format.parse(dateFrom.getText(), LocalDateTime::from);
LocalDateTime localDateTimeTo = format.parse(dateTo.getText(), LocalDateTime::from);
int hoursFrom = localDateTimeFrom.getHour();
int hoursTo = localDateTimeTo.getHour();
boolean workedNight = hoursFrom < 6 || hoursTo > 22;
Here’s my attempt to cover all of your requirements. I wrote the code before reading that you don’t require that summer time (DST) is taken into account, so I am using ZonedDateTime to get correct hours also across summer time transitions. For the same reason I need to iterate over each day. For each date I calculate the hours worked at night time and the hours worked at day time.
If you want to make sure that summer time is not taken into account, use LocalDateTime instead of ZonedDateTime. In this case there may also be a possible performance gain in calculating the whole work days in one lump rather than one day at a time.
The code below uses 28/03/2018 03:00 and 29/03/2018 23:30 as example start and end time. Expected total hours worked are 44.5 since one day is 24 hours and there are 20.5 hours from 03:00 to 23:30. The expected day time hours are 32 since there are 16 daytime hours each of the two days. This leaves 12.5 hours as night time. And indeed the code prints
Day 32.0 hours; night 12.5 hours
The program follows. Please fill in the correct time zone where I put America/Monterey.
static ZoneId zone = ZoneId.of("America/Monterrey");
static LocalTime dayStart = LocalTime.of(6, 0);
static LocalTime dayEnd = LocalTime.of(22, 0);
static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("d/M/uuuu H:mm");
public static void main(String[] args) {
String workStartString = "28/03/2018 03:00";
String workEndString = "29/03/2018 23:30";
calculateWorkingHours(workStartString, workEndString);
}
public static void calculateWorkingHours(String workStartString, String workEndString) {
ZonedDateTime workStart
= LocalDateTime.parse(workStartString, formatter).atZone(zone);
ZonedDateTime workEnd
= LocalDateTime.parse(workEndString, formatter).atZone(zone);
if (workEnd.isBefore(workStart)) {
throw new IllegalArgumentException("Work end must not be before work start");
}
LocalDate workStartDate = workStart.toLocalDate();
LocalDate workEndDate = workEnd.toLocalDate();
Duration workedDaytime = Duration.ZERO;
// first calculate work at nighttime before the start date, that is, work before 06:00
Duration workedNighttime
= calculateNightTime(workStartDate.minusDays(1), workStart, workEnd);
for (LocalDate d = workStartDate; ! d.isAfter(workEndDate); d = d.plusDays(1)) {
workedDaytime = workedDaytime.plus(calculateDayTime(d, workStart, workEnd));
workedNighttime = workedNighttime.plus(calculateNightTime(d, workStart, workEnd));
}
double dayHours = workedDaytime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);
double nightHours = workedNighttime.toMinutes() / (double) TimeUnit.HOURS.toMinutes(1);
System.out.println("Day " + dayHours + " hours; night " + nightHours + " hours");
}
/**
* Calculates amount of work in daytime on d,
* that is between 06:00 and 22:00 on d.
* Only time that falls with in workStart to workAnd
* and also falls within 06:00 to 22:00 on d is included.
*
* #param d The date for which to calculate day work
* #param workStart
* #param workEnd
* #return Amount of daytime work on the said day
*/
private static Duration calculateDayTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
ZonedDateTime dayStartToday = d.atTime(dayStart).atZone(zone);
ZonedDateTime dayEndToday = d.atTime(dayEnd).atZone(zone);
if (workStart.isAfter(dayEndToday) || workEnd.isBefore(dayStartToday)) {
return Duration.ZERO;
}
// restrict calculation to daytime on d
if (workStart.isBefore(dayStartToday)) {
workStart = dayStartToday;
}
if (workEnd.isAfter(dayEndToday)) {
workEnd = dayEndToday;
}
return Duration.between(workStart, workEnd);
}
/**
* Calculates amount of night work in the night after d,
* that is from 22:00 on d until 06:00 the next morning.
*
* #param d The date for which to calculate night work
* #param workStart
* #param workEnd
* #return Amount of nighttime work in said night
*/
private static Duration calculateNightTime(LocalDate d, ZonedDateTime workStart, ZonedDateTime workEnd) {
assert ! workEnd.isBefore(workStart);
ZonedDateTime nightStart = d.atTime(dayEnd).atZone(zone);
ZonedDateTime nightEnd = d.plusDays(1).atTime(dayStart).atZone(zone);
if (workEnd.isBefore(nightStart) || workStart.isAfter(nightEnd)) {
return Duration.ZERO;
}
// restrict calculation to the night after d
if (workStart.isBefore(nightStart)) {
workStart = nightStart;
}
if (workEnd.isAfter(nightEnd)) {
workEnd = nightEnd;
}
return Duration.between(workStart, workEnd);
}
You can check the LocalTime part of a LocalDateTime to have a simple check using isAfter and isBefore.
I will use those values for this example.
LocalDateTime start = LocalDateTime.of(2018, Month.APRIL, 30, 23, 0);
LocalDateTime end = LocalDateTime.of(2018, Month.MAY, 1, 5, 0);
Then define the limit for the night.
LocalTime startNight = LocalTime.of(22, 0);
LocalTime endNight = LocalTime.of(6, 0);
And simply use get the LocalTime of both date and check if they are in the range. You can get the value using toLocalTime.
if(start.toLocalTime().isAfter(startNight) &&
end.toLocalTime().isBefore(endNight)){
System.out.println("NIGHT TIME");
} else {
System.out.println("DAY TIME");
}
NIGHT TIME
The output is valid since we start at 23:00 and end at 05:00.
Using this allow a simpler solution if you need to define a time like LocalTime.of(5,45) for 5:45
This is an example, this might need some adaptation if it is allowed to start part 22 but keep working after 6. This is just an example on how to use those methods.
This is easier, if you use the java.time API. You simply need to check, if the dates differ or if the starting time not in the range from 6:00 to 22:00:
private static final LocalTime START_TIME = LocalTime.of(6, 0); // 06:00
private static final LocalTime END_TIME = LocalTime.of(22, 0); // 22:00
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm");
// parse from input strings
LocalDateTime start = LocalDateTime.parse(startText, FORMATTER);
LocalDateTime end = LocalDateTime.parse(endText, FORMATTER);
boolean nightTime =
!start.toLocalDate().equals(end.toLocalDate())
|| start.toLocalTime().isBefore(START_TIME)
|| end.toLocalTime().isAfter(END_TIME);
// todo: change output to gui
System.out.println("night time: " + nightTime);
System.out.println("duration : " + Duration.between(start, end).toHours());
Define two formatters. One Fromatter to get date with time from edittext. And other On to get 12AM of that day. Now we need Date Objects corresponding to 6AM and 11PM of the same day. We can get those by adding that much milliseconds to the 12AM Object. These added dates can be used for comparison.
SimpleDateFormat df_zero_hours = new SimpleDateFormat("dd/MM/yyy");
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm");
Date ddtt = format.parse(ddt.getText()); //Work Start Time
Date dftt = format.parse(dft.getText()); //Work End Time
Date dateStart = df_zero_hours.parse(ddt.getText()); //12AM of the day job started
Date dayStart = new Date();
dayStart.setTime(dateStart.getTime()+6*60*60*1000); // Get 6AM of that day
Date dayEnd = new Date();
dayEnd.setTime(dateStart.getTime()+22*60*60*1000); //Get 10PM of that day
// Now check the worked hours. in Whatever way you need
boolean isBefore6AM = (dayStart.getTime()-ddtt.getTime())>0;
boolean isAfter10PM = (dftt.getTime()-dayEnd.getTime())>0;

Get difference between two Joda dates in seconds

I am trying to use joda API in my app for playing with Date object.
In some activity i am storing joda datetime in sharedpreference using following code
prefsEdit.putLong(context.getString(R.string.last_status_change_time_key) , DateTime.now().getMillis());
Now in some other activity, i m fetching this stored preference and calculating the difference between dates using following code
long lastStatusChangeTime = objSharedPref.GetAppLongPrefByKey(R.string.last_status_change_time_key);
DateTime now = DateTime.now();
DateTime dateTime = new DateTime(lastStatusChangeTime);
Seconds seconds = Seconds.secondsBetween(now, dateTime);
int n = seconds.getSeconds();
The code always return me values in minus eg -31 , -12 etc..
It is not calculating the difference correctly .
What is missing ??
The declaration of secondsBetween() is:
secondsBetween(ReadableInstant start, ReadableInstant end)
In order to have positive result the start date should be a date before the end date.
It is because secondsBetween() doesn't return an absolute value.
In your example dateTime is obviously before now, so in order to get positive values the invocation should be:
Seconds seconds = Seconds.secondsBetween(dateTime, now);
instead of:
Seconds seconds = Seconds.secondsBetween(now, dateTime); // <- wrong order as `startDate` parameter is a date after `endDate` parameter
and your code could be:
long lastStatusChangeTime = objSharedPref.GetAppLongPrefByKey(R.string.last_status_change_time_key);
DateTime now = DateTime.now();
DateTime dateTime = new DateTime(lastStatusChangeTime);
Seconds seconds = Seconds.secondsBetween(dateTime, now); // <-- Here is the difference
int n = seconds.getSeconds();
Just use native Java code.
long oldTime = Calendar.getInstance().getTime().getTime();
Thread.sleep(10*1000);
long newTime = Calendar.getInstance().getTime().getTime();
long diffInMillisecods = newTime - oldTime;
long diffInSeconds = diffInMillisecods / 1000;

Java calculating time with timestamps [duplicate]

This question already has answers here:
Calculating the difference between two Java date instances
(45 answers)
Closed 7 years ago.
Im trying to calculate the time difference between 2 Timestamps, this is the code:
Calendar calendar = Calendar.getInstance();
java.util.Date now = calendar.getTime();
Timestamp currentTimestamp = new Timestamp(now.getTime());
System.out.println("Current\n"+currentTimestamp);
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
Date date = dateFormat.parse("28/02/2015");
Timestamp timestampBefore = new Timestamp(date.getTime());
System.out.println("Before\n"+timestampBefore);
Timestamp calculated = new Timestamp(currentTimestamp.getTime() - timestampBefore.getTime());
System.out.println("Calculated\n"+calculated);
Output:
Current
2015-02-28 12:12:40.975
Before
2015-02-28 00:00:00.0
Calculated
1970-01-01 13:12:40.975
I can understand why it returns 1970-01-01 but why does it return 13:12:40.975 ,1 hour more?
How to calculate the difference between 2 dates so the output is like this (based on this example):
Years:0, Months:0, Days:0, Hours:12, Minutes:12, Seconds:40 ?
Update: for java below 1.8 check out http://www.joda.org/joda-time/index.html
and for java 1.8 see answer.
Similar solution here: Java 8: Calculate difference between two LocalDateTime
(1) A timestamp is a point in time. If you calculate the difference between two timestamps, the result is not a timestamp (point in time), but a duration. So it is nonsense to convert the difference to a timestamp, hence it is useless to discuss the reason why the result is strange.
(2) You should probably use the new Java 8 time API (if you are able to use Java 8):
LocalTime now = LocalTime.now();
LocalTime previous = LocalTime.of(0, 0, 0, 0);
Duration duration = Duration.between(previous, now);
System.out.println(now);
System.out.println(previous);
System.out.println(duration);
Note that this just calculates the duration between two times of a day (hour-minute-second). If your want to include date information, use LocalDateTime instead:
LocalDateTime nextFirework = LocalDate.now()
.with(TemporalAdjusters.firstDayOfNextYear())
.atTime(LocalTime.MIDNIGHT);
LocalDateTime now = LocalDateTime.now();
// duration (in seconds and nanos)
Duration duration = Duration.between(now, nextFirework);
// duration in total hours
long hours = now.until(nextFirework, ChronoUnit.HOURS);
// equals to: duration.toHours();
If you want to have 'normalized' duration in years/months/days/hours/seconds, there is suprisingly no direct support. You could convert the duration to days, hours, minutes and seconds by yourself:
long d = duration.toDays();
long h = duration.toHours() - 24 * d;
long m = duration.toMinutes() - 60 * duration.toHours();
long s = duration.getSeconds() - 60 * duration.toMinutes();
System.out.println(d + "d " + h + "h " + m + "m " + s + "s ");
But note that you will have difficulties converting the days into months and years, as there is no unique number of days per month and a year can be a leap year with 366 days. For that, you can use Period, as in opposite to Duration, this class is associated with a timeline. Unfortunately, Period does only support dates, but no times:
// period in years/months/days (ignoring time information)
Period p = Period.between(now.toLocalDate(), nextFirework.toLocalDate());
System.out.println(p); // or use p.getYears(), p.getMonths(), p.getDays()
So probably you could combine both approaches - first, compute the Period from the dates and then the Duration using the times. Note that the duration can be negative, so you'll have to take care of that in case of:
Duration dur = Duration.between(start.toLocalTime(), end.toLocalTime());
LocalDate e = end.toLocalDate();
if (dur.isNegative()) {
dur = dur.plusDays(1);
e = e.minusDays(1);
}
Period per = Period.between(start.toLocalDate(), e);
System.out.println(per.toString() + ", " + dur.toString());

How to parse time durations from Strings and add them?

I need to parse two Strings in HH:MM format in Java:
String time1="10:45";
String time2="02:30";
Stupid but simple:
String time1 = "10:45";
String time2 = "02:30";
String[] split1 = time1.split(":");
String[] split2 = time2.split(":");
int total = 60 * Integer.parseInt(split1[0]) +
Integer.parseInt(split1[1]) +
60 * Integer.parseInt(split2[0]) +
Integer.parseInt(split2[1]);
int hours = total / 60;
int minutes = total - hours * 60;
System.out.println(hours + ":" + minutes);
Do you want to get the difference? have a look at the SimpleDateFormat, perhaps you use that to create a Date and then calculate on that.
Use SimpleDateFormat to get teh dates
DateFormat formatter = new SimpleDateFormat("HH:mm");
Date date = (Date)formatter.parse("10:20");
Then you can add the dates together.
You may have to do some logic to cope with times where the dateas go over different days. I would recommend using JodaTime for any date manipulation.
Not sure if this is relevant as not sure what the actual question is....

Categories