ANDROID - How to display datetime that already passed? - java

I want to display the time that already passed with specific time and date.
Example :
time1 = 2017-06-18 07:00:00 //set time
curtime = 2017-06-19 07:00:01 //get the current time
TextView will just display 0 Years 0 Month 1 Days 00 Hours 00 Minutes 01 Seconds already passed_
If someone have the best keyword for me to finding my self, I appreciate it.
Ref: link1 but not enough to face my issue.

To get the difference between 2 dates, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
First I parsed the strings to a LocalDateTime object, then I've got the difference between those dates. The API has created 2 different concepts of "time-difference/amount of time": a Period, a date-based amount of time (in terms of years, months and days), and a Duration, a time-based amount (in terms of seconds).
import org.threeten.bp.Duration;
import org.threeten.bp.LocalDate;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.LocalTime;
import org.threeten.bp.Period;
import org.threeten.bp.format.DateTimeFormatter;
String time1 = "2017-06-18 07:00:00"; // set time
String curtime = "2017-06-19 07:00:01"; // get the current time
// parse the strings to a date object
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime t1 = LocalDateTime.parse(time1, fmt);
LocalDateTime cur = LocalDateTime.parse(curtime, fmt);
// get the period between the dates
LocalDate startDate = t1.toLocalDate();
LocalDate endDate = cur.toLocalDate();
Period period = Period.ZERO;
if (startDate != null && endDate != null) {
period = Period.between(startDate, endDate);
}
// get the duration between the dates
LocalTime startTime = t1.toLocalTime();
LocalTime endTime = cur.toLocalTime();
startTime = startTime != null ? startTime : LocalTime.MIDNIGHT;
endTime = endTime != null ? endTime : LocalTime.MIDNIGHT;
Duration duration = Duration.between(startTime, endTime);
StringBuilder sb = new StringBuilder();
append(sb, period.getYears(), "year");
append(sb, period.getMonths(), "month");
append(sb, period.getDays(), "day");
long seconds = duration.getSeconds();
long hours = seconds / 3600;
append(sb, hours, "hour");
seconds -= (hours * 3600);
long minutes = seconds / 60;
append(sb, minutes, "minute");
seconds -= (minutes * 60);
append(sb, seconds, "second");
System.out.println(sb.toString()); // 1 day 1 second
// auxiliary method
public void append(StringBuilder sb, long value, String text) {
if (value > 0) {
if (sb.length() > 0) {
sb.append(" ");
}
sb.append(value).append(" ");
sb.append(text);
if (value > 1) {
sb.append("s"); // append "s" for plural
}
}
}
The output is:
1 day 1 second
Note that the Period class already keeps the fields (years, months and days) separated, while the Duration class keeps only the seconds (so some calculations are needed to get the correct results) - it actually has methods like toHours(), but it only converts the seconds to hours, and it doesn't separate all the fields like we want.
You can customize the append() method to the exact format you want. I just took the simple approach of printing value + text, but you can change it according to your needs.
Java new Date/Time API
For Java >= 8, there's the new java.time API. You can use this new API and the ThreeTen Extra project, which has the PeriodDuration class (a combination of both Period and Duration).
The code is basically the same as above, the only difference is the packages names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
import org.threeten.extra.PeriodDuration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
String time1 = "2017-06-18 07:00:00"; // set time
String curtime = "2017-06-19 07:00:01"; // get the current time
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime t1 = LocalDateTime.parse(time1, fmt);
LocalDateTime cur = LocalDateTime.parse(curtime, fmt);
PeriodDuration pd = PeriodDuration.between(t1, cur);
StringBuilder sb = new StringBuilder();
append(sb, pd.getPeriod().getYears(), "year");
append(sb, pd.getPeriod().getMonths(), "month");
append(sb, pd.getPeriod().getDays(), "day");
long seconds = pd.getDuration().getSeconds();
long hours = seconds / 3600;
append(sb, hours, "hour");
seconds -= (hours * 3600);
long minutes = seconds / 60;
append(sb, minutes, "minute");
seconds -= (minutes * 60);
append(sb, seconds, "second");
System.out.println(sb.toString()); // 1 day 1 second
Of course you can also create a Period and a Duration using the same code of org.threeten.bp's version.

Check DateUtils:
https://developer.android.com/reference/android/text/format/DateUtils.html#getRelativeTimeSpanString(long,long,long)
Should give you what you are looking for.

You need to create Date objects of Calendar objects and compare them to know how much time has passed.
Or you can use the Joda date time library to find it.
Check out

You can use java.time.Duration and java.time.Period which were introduced with Java-8 as part of JSR-310 implementation to model ISO_8601#Durations. With Java-9, some more convenience method were added.
Demo:
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.Period;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("u-M-d H:m:s", Locale.ENGLISH);
LocalDateTime startDateTime = LocalDateTime.parse("2017-06-18 07:00:00", dtf);
// Use the following line for the curren date-time
// LocalDateTime endDateTime = LocalDateTime.now();
// Use the following line for a given end date-time string
LocalDateTime endDateTime = LocalDateTime.parse("2017-06-19 07:00:01", dtf);
Period period = startDateTime.toLocalDate().until(endDateTime.toLocalDate());
Duration duration = Duration.between(startDateTime, endDateTime);
// ############################ Java-8 ############################
String periodDuration = String.format("%d Years %d Months %d Days %02d Hours %02d Minutes %02d Seconds",
period.getYears(), period.getMonths(), period.getDays(), duration.toHours() % 24,
duration.toMinutes() % 60, duration.toSeconds() % 60);
System.out.println(periodDuration);
// ############################ Java-8 ############################
// ############################ Java-9 ############################
periodDuration = String.format("%d Years %d Months %d Days %02d Hours %02d Minutes %02d Seconds",
period.getYears(), period.getMonths(), period.getDays(), duration.toHoursPart(),
duration.toMinutesPart(), duration.toSecondsPart());
System.out.println(periodDuration);
// ############################ Java-8 ############################
}
}
Output:
0 Years 0 Months 1 Days 00 Hours 00 Minutes 01 Seconds
0 Years 0 Months 1 Days 00 Hours 00 Minutes 01 Seconds
Learn about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Related

Unable to parse correct total hours from Wednesday to Thursday in java

I am having an issue while parsing day and time to get the total hours and minutes in java.
If I calculate total hours starting from 'Mon 22:00' to 'Tue 22:00' then I am getting correct total hours 24. But If I calculate total hours starting from 'Wed 22:00' to current day and time like 'Thu 12:45' then I am getting 'Hours : -153 Min : -15'.
This is the case only for Wednesday and Thursday. For rest of the days it is working fine.
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Test {
private static DateFormat dateFormat = new SimpleDateFormat("EEE HH:mm");
private static DateFormat dayFormat = new SimpleDateFormat("E");
private static Calendar calendar = Calendar.getInstance();
public static void main(String[] args) {
try {
Date date1 = dateFormat.parse("Wed 22:00");
Date date2 = dateFormat.parse(dayFormat.format(calendar.getTime()) + " " + calendar.getTime().getHours() + ":"
+ calendar.getTime().getMinutes());
long hours2 = getDurationInHours(date1, date2);
long min = getDurationInMin(date1, date2);
System.out.println("Hours : " + hours2 + " Min : " + min);
} catch (Exception e) {
e.printStackTrace();
}
}
public static long getDurationInHours(Date returnTime, Date leaveTime) {
long durationInMillis = leaveTime.getTime() - returnTime.getTime();
long hours = TimeUnit.MILLISECONDS.toHours(durationInMillis);
return hours;
}
public static long getDurationInMin(Date returnTime, Date leaveTime) {
long durationInMillis = leaveTime.getTime() - returnTime.getTime();
long min = TimeUnit.MILLISECONDS.toMinutes(durationInMillis) % 60;
return min;
}
}
That's because when you define your date as Wed 22:00 it's not the Wednesday the current week. It is actually 7th of January 1970 ;)
As you probably know the dates in java work as long number since 01.01.1970. So when you say Wednesday and not an actual date it gets the first Wednesday after 1970 which is the 7th. When you say Mon 22:00 it works properly because it uses 5th of January 1970 and the difference is 2 days.
When you use "Thu 22:00" in the same logic it uses 1st of January 1970 (which is a Thursday) and that's why you get negative numbers. Because it's actually 6 days ahead
java.time
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE H:mm", Locale.ENGLISH);
ZonedDateTime now = ZonedDateTime.now(ZoneId.of("America/Dominica"));
TemporalAccessor fromTa = formatter.parse("Wed 22:00");
ZonedDateTime from = now
.with(TemporalAdjusters.previous(DayOfWeek.from(fromTa)))
.with(LocalTime.from(fromTa));
Duration dur = Duration.between(from, now);
System.out.println(dur);
Running this code just now gave the following output:
PT11H41M25.284611S
This means a duration of 11 hours 41 minutes 25.284611 seconds. If you need to use this duration further in your program, you will probably want to keep the Duration object. For printing to the user it’s not so nice, so do that this way:
long hours = dur.toHours();
int min = dur.toMinutesPart();
System.out.println("" + hours + " hours " + min + " min");
11 hours 41 min
Java doesn’t have a concept of “Wednesday at 22:00”. So we need to pick a specific Wednesday and a specific Thursday. SimpleDateFormat was trying to be helpful to you and picked for you, but didn’t pick the Wednesday and the Thursday you had expected, so didn’t do you any favour. java.time, the modern Java date and time API, forces us to pick ourselves. I much prefer this. It makes it much clearer exactly what happens in the code, which in turn will also make it easier to spot and fix any errors.
My use of TemporalAdjusters.previous ensures that I get last Wednesday (not next Wednesday). And my use of ZonedDateTime ensures that the hours and minutes are correct. Even across transitions to and from summer time (daylight saving time) and other such time transitions. You should of course fill in your own time zone if it didn’t happen to be America/Dominica.
Link: Oracle tutorial: Date Time explaining how to use java.time.
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
You can do it in an intuitive way with java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.
Note that a weekday and time e.g. Mon 22:00 is not sufficient to create a date-time object directly. A weekday e.g. Monday comes in every week and therefore we will have to create a date-time object defaulting to a particular date e.g. today. From this date as a reference, you can find the first occurrence (LocalDate) of the given weekday (e.g. Monday) and from that object, you can obtain a date-time object with the given time.
Duration#between gives you the Duration object between the two date-time objects. Using the Duration object, you can create a string formatted as per your requirement, by getting days, hours, minutes, seconds from it.
Demo:
import java.time.DayOfWeek;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.time.temporal.TemporalAdjusters;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
displayDuration(getDuration("Mon 22:00", "Tue 22:00"));
displayDuration(getDuration("Wed 22:00", "Thu 12:45"));
}
static Duration getDuration(String strStartDayTime, String strEndDayTime) {
LocalDate today = LocalDate.now();
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("EEE HH:mm", Locale.ENGLISH);
TemporalAccessor taStart = dtf.parse(strStartDayTime);
TemporalAccessor taEnd = dtf.parse(strEndDayTime);
LocalDateTime ldtStartDateTime = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.from(taStart)))
.atTime(LocalTime.from(taStart));
LocalDateTime ldtEndDateTime = today.with(TemporalAdjusters.nextOrSame(DayOfWeek.from(taEnd)))
.atTime(LocalTime.from(taEnd));
return Duration.between(ldtStartDateTime, ldtEndDateTime);
}
static String formatDurationJava8(Duration duration) {
return String.format("Days: %d, Hours: %02d, Minutes: %02d, Seconds: %02d", duration.toDays(),
duration.toHours() % 24, duration.toMinutes() % 60, duration.toSeconds() % 60);
}
static String formatDurationJava9(Duration duration) {
return String.format("Days: %d, Hours: %02d, Minutes: %02d, Seconds: %02d", duration.toDaysPart(),
duration.toHoursPart(), duration.toMinutesPart(), duration.toSecondsPart());
}
static void displayDuration(Duration duration) {
// Default format
System.out.println(duration);
// Custom format
System.out.println(formatDurationJava8(duration));
System.out.println(formatDurationJava9(duration));
}
}
Output:
PT24H
Days: 1, Hours: 00, Minutes: 00, Seconds: 00
Days: 1, Hours: 00, Minutes: 00, Seconds: 00
PT14H45M
Days: 0, Hours: 14, Minutes: 45, Seconds: 00
Days: 0, Hours: 14, Minutes: 45, Seconds: 00
Learn about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Format of time is incorrect

String realTimeStr = "5.2345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
long realTimeLng = (long) (realTimeDbl*1000);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSS", Locale.getDefault());
log("Duration: " + sdf.format(new Date(realTimeLng - TimeZone.getDefault().getRawOffset())));
Current output:
Duration: 00:00:05.0234
Desired output:
Duration: 00:00:05.2345
I also tried another method, still no good:
String realTimeStr = "1.4345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("HH:mm:ss.SSSS").withZone(ZoneId.of("UTC"));
Instant instant = Instant.ofEpochMilli((long)(realTimeDbl*1000));
String t = formatter.format(instant);
System.out.println("Duration: " + t);
Current output:
Duration: 00:00:01.4340
Desired output:
Duration: 00:00:01.4345
I have googled for some time. Any ideas what is causing this?
First of all, you're mistaking 2 different concepts:
A time of the day, such as 10 AM or 15:30:45
A duration, which is an amount of time, such as 1 year, 2 months and 10 days or 10 hours, 25 minutes and 30 seconds
Although both might use the same words (such as "hours" and "minutes"), they're not the same thing. A duration is not attached to a chronology (10 hours and 25 minutes relative to what?), it's just the amount of time, by itself.
SimpleDateFormat and DateTimeFormatter are designed to format dates and times of the day, but not durations. Although converting a duration to a time and "pretending" it's a time of the day to format it might work, it's not the right way.
Unfortunately, there are no built-in formatters for a duration. So you'll have to format it manually.
Another detail is that you are multiplying 1.4345 by 1000 (resulting in 1434.5), and then casting to a long(so the value is rounded to 1434) - the last digit is lost.
One way to do it is to parse the string to a double and then multiply by 1 billion to get the value as nanoseconds (I don't know if you'll work with more than 4 digits, so I'm considering nanosecond precision):
// convert the string value to a total of nanoseconds
int nanosPerSecond = 1_000_000_000;
long nanos = (long) (Double.parseDouble(realTimeStr) * nanosPerSecond);
Now we must format it manually. First I've extracted the number of hours, minutes, seconds and nanoseconds from the total nanos value:
long hours = nanos / nanosPerSecond / 3600;
nanos -= hours * 3600 * nanosPerSecond;
long minutes = nanos / nanosPerSecond / 60;
nanos -= minutes * 60 * nanosPerSecond;
long seconds = nanos / nanosPerSecond;
nanos -= seconds * nanosPerSecond;
Then I created an auxiliary method to build the output:
// auxiliary method
public void addValue(long value, StringBuilder sb) {
if (value < 10) {
sb.append("0");
}
sb.append(value);
}
And used it to join the pieces:
StringBuilder sb = new StringBuilder();
addValue(hours, sb);
sb.append(":");
addValue(minutes, sb);
sb.append(":");
addValue(seconds, sb);
sb.append(".");
addValue(nanos, sb);
// remove the extra zeroes in the end
String output = sb.toString().replaceAll("0*$", "");
System.out.println(output);
The output is:
00:00:01.4345
You can use java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenience methods were introduced.
Demo:
import java.time.Duration;
public class Main {
public static void main(String[] args) {
String realTimeStr = "5.2345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
long nanos = (long) (realTimeDbl * 1000_000_000);
Duration duration = Duration.ofNanos(nanos);
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedDuration = String.format("%02d:%02d:%02d.%d", duration.toHours() % 24,
duration.toMinutes() % 60, duration.toSeconds() % 60, (duration.toNanos() % 1000_000_000) / 100000);
System.out.println(formattedDuration);
// ##############################################################################
// ####################################Java-9####################################
formattedDuration = String.format("%02d:%02d:%02d.%d", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart(), duration.toNanosPart() / 100000);
System.out.println(formattedDuration);
// ##############################################################################
}
}
Output:
PT5.2345S
00:00:05.2345
00:00:05.2345
Learn about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
The problem resides in the format, as noticed by Joe C, probably meaning at this line:
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSS", Locale.getDefault());
try changing it removing one "S"
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS", Locale.getDefault());
notify us if it's correct =)
package com.stackoverflow.examples;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.TimeZone;
public class TimeStamp {
public static void main(String[] args) {
String realTimeStr = "5.2345";
Double realTimeDbl = Double.parseDouble(realTimeStr);
long realTimeLng = (long) (realTimeDbl * 1000);
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSSs", Locale.getDefault());
System.out.println("Duration: " + sdf.format(new Date(realTimeLng - TimeZone.getDefault().getRawOffset())));
}
}
I tried SSSs instead of SSSS

Calculate duration between two hours in Java

I want to calculate the time difference (duration) between two hours (HH:mm:ss) in Java. Here, I've read several topics on this subject, but my problem is a little bit different.
I'm not able to use Joda-Time, as well.
Example:
input values: 12:03:00
00:00:00
expected output: 11:57:00
Сode:
public static void main(String[] args) throws ParseException {
Scanner sc = new Scanner(System.in);
String startTime = sc.next();
String endTime = sc.next();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Date d1 = sdf.parse(startTime);
Date d2 = sdf.parse(endTime);
long elapsed = d2.getTime() - d1.getTime();
String hms = String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(elapsed),
TimeUnit.MILLISECONDS.toMinutes(elapsed) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(elapsed)),
TimeUnit.MILLISECONDS.toSeconds(elapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsed)));
if (elapsed > 0) {
System.out.println(hms);
} else {
elapsed = elapsed * (-1); //otherwise, print hours with '-'
String hms1 = String.format("%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(elapsed),
TimeUnit.MILLISECONDS.toMinutes(elapsed) - TimeUnit.HOURS.toMinutes(TimeUnit.MILLISECONDS.toHours(elapsed)),
TimeUnit.MILLISECONDS.toSeconds(elapsed) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(elapsed)));
System.out.println(hms1);
}
}
Result:
expected output: 11:57:00
actual output: 12:03:00 //that's the problem
tl;dr
Duration.between(
LocalTime.parse( "12:03:00" ) ,
LocalTime.parse( "23:59:59.999999999" )
).plusNanos( 1 ).withNanos( 0 )
PT11H57M
Use a nanosecond
The modern approach uses the java.time classes.
The catch is that for time-of-day only, there is no midnight. So your 00:00 which you apparently intended for end-of-day is actually interpreted as start-of-day.
There is only the last nanosecond before the day ends. The LocalTime has a constant defined for that last nanosecond: LocalTime.MAX = 23:59:59.999999999
Since you care only about whole seconds, we can take advantage of that fractional second. If your ending time happens to be 00:00:00, substitute LocalTime.MAX. Then calculate a Duration object. You can add a single nanosecond and then truncate the resulting fractional second by setting the fractional second (the nanoseconds) to zero.
For ending times other than 00:00:00, the math still works. Adding a nanosecond gets you ….000000001 fraction of second, and Duration::withNanos will truncate that unwanted fraction.
// This code assumes the inputs are *always* in whole seconds, without any fraction-of-second.
LocalTime start = LocalTime.parse( "12:03:00" );
LocalTime stop = LocalTime.parse( "00:00:00" );
if( stop.equals( LocalTime.MIN ) ) {
stop = LocalTime.MAX ; // `23:59:59.999999999`
}
Duration d = Duration.between( start , stop );
d = d.plusNanos( 1 ).withNanos( 0 ) ;
System.out.println( "start/stop: " + start + "/" + stop );
System.out.println( "d: " + d );
See this code run live at IdeOne.com.
PT11H57M
Formatting
The output from toString is standard ISO 8601 format. The Duration class can parse such strings as well as generate them.
I strongly recommend not representing a span of time in time-of-day style, HH:MM:SS. This is ambiguous and often creates confusion when read by humans.
But if you insist on that format you must build the string yourself. The Duration class lacks a format method seen in other java.time class. Oddly, this class originally lacked methods to extract the parts, a number of days, of hours, of minutes, of seconds, and a fractional second. See this Question for discussion. Java 9 brings such methods, named to…Part.
While using Java 8, I suggest doing string manipulation of the ISO 8601 formatted output. Replace the PT with empty string. If there is an M, replace H with a colon. If there is an S, replace the M with a colon and replace the S with empty string. If no S, replace M with empty string. I believe you can find this code posted on Stack Overflow.
The basic flaw here is that you want the NEAREST distance between two times. When you are constructing your date objects, even though you only format for Hour:Minute:Second it still stores the day/month/year etc... For the dates 12:03:00 and 00:00:00 it defaults them to the same day, so the difference from (Midnight to Noon) is what your getting not (Noon to Midnight) of the next day. The solution for you would be to check if the times are less than 12 (military time) and if so add 1 to the day.
Here's How you do it:
String t1 = "12:03:00";
String t2 = "00:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
Date d1 = sdf.parse(t1);
Date d2 = sdf.parse(t2);
Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
c1.setTime(d1);
c2.setTime(d2);
if(c2.get(Calendar.HOUR_OF_DAY) < 12) {
c2.set(Calendar.DAY_OF_YEAR, c2.get(Calendar.DAY_OF_YEAR) + 1);
}
long elapsed = c2.getTimeInMillis() - c1.getTimeInMillis();
Is this what you want to do:
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
public class HourTest {
public static void main(String[] args) throws Exception {
LocalDateTime ldt1 = LocalDateTime.parse("2015-05-04T12:07:00");
LocalDateTime ldt2 = LocalDateTime.parse("2015-05-04T00:00:00");
long seconds = Math.abs(ChronoUnit.SECONDS.between(ldt1, ldt2));
String hms = String.format("%02d:%02d:%02d", seconds / 3600, (seconds / 60) % 60, seconds % 60);
// Prints 12:07:00. I tried it.
System.out.println(hms);
}
}
You can use java.time.Duration which is modelled on ISO-8601 standards and was introduced with Java-8 as part of JSR-310 implementation. With Java-9 some more convenient methods were introduced.
Demo:
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Main {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalTime startTime = LocalTime.parse("12:03:00");
LocalTime endTime = LocalTime.parse("00:00:00");
LocalDateTime startDateTime = today.atTime(startTime);
LocalDateTime endDateTime = today.atTime(endTime);
if (startDateTime.isAfter(endDateTime)) {
endDateTime = endDateTime.with(LocalTime.MIN).plusDays(1).with(endTime);
}
Duration duration = Duration.between(startDateTime, endDateTime);
// Default format
System.out.println(duration);
// Custom format
// ####################################Java-8####################################
String formattedDuration = String.format("%02d:%02d:%02d", duration.toHours(), duration.toMinutes() % 60,
duration.toSeconds() % 60);
System.out.println(formattedDuration);
// ##############################################################################
// ####################################Java-9####################################
formattedDuration = String.format("%02d:%02d:%02d", duration.toHoursPart(), duration.toMinutesPart(),
duration.toSecondsPart());
System.out.println(formattedDuration);
// ##############################################################################
}
}
Output:
PT11H57M
11:57:00
11:57:00
Learn about the modern date-time API from Trail: Date Time.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

Java Date is giving incorrect time difference, jumps 1 hour ahead

My time difference is showing an incorrect output, I'm trying to calculate the time difference between startTime and endTime.
Date time1, time2;
long difference;
SimpleDateFormat df = new SimpleDateFormat("HH:mm");
public Time(String startTime, String endTime)
{
this.startTime = startTime;
this.endTime = endTime;
time1 = new Time("16:30", "18:00"); //example
try
{
time1 = df.parse(startTime);
time2 = df.parse(endTime);
}
catch(Exception e) {
System.out.println("invalid time");
}
}
public String getDifference()
{
difference = (time2.getTime() - time1.getTime());
return df.format(difference); //output = 02:30, should be 01:30
}
I know that Joda-Time could make this easier, but I'm supposed not to use any other library.
It calculates the difference correctly as 5400000 milliseconds (1.5 hours), but formats it as 02:30, due to, I think, the time zone.
Add this line in your constructor to set the date format to the UTC time zone, and it should output 01:30 as you expect:
df.setTimeZone(java.util.TimeZone.getTimeZone("UTC"));
Time is the number of milliseconds since a moment called epoch. In your code, you calculate the difference between to moments, and then interpret the result as a timestamp, but it isn't.
The calculated result is the difference between two timestamps in milliseconds. If you want that printed in hours and minutes, do something like:
public String getDifference() {
difference = (time2.getTime() - time1.getTime()) / 1000L;
long hours = difference/3600;
difference %= 3600;
long minutes = difference/60;
difference %= 60;
long seconds = difference;
return String.format("%d:%02d:%02d", hours, minutes, seconds);
}
The date-time API of java.util and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.
For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7.
If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.
Demo:
import java.time.Duration;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("H:m", Locale.ENGLISH);
LocalTime begin = LocalTime.parse("16:30", dtf);
LocalTime end = LocalTime.parse("18:00", dtf);
Duration duration = Duration.between(begin, end);
System.out.println(duration);
// Custom format
// ##########################################Java-8##########################################
System.out.println(String.format("%d:%d", duration.toHours(), duration.toMinutes() % 60));
// ##########################################################################################
// ##########################################Java-9##########################################
System.out.println(String.format("%d:%d", duration.toHoursPart(), duration.toMinutesPart()));
// ##########################################################################################
}
}
Output:
PT1H30M
1:30
1:30
Learn about the modern date-time API from Trail: Date Time.

Find total hours between two Dates

I have two Date objects and I need to get the time difference so I can determine the total hours between them. They happen to be from the same day. The result I would like would have the hours and minutes.
When I use .toString() on my Date object I get this: Fri Dec 18 08:08:10 CST 2009
I've tried the following:
long diff = (this.endDate.getTime() - this.startDate.getTime()) / (60 * 60 * 1000);
But this only gives me hours, not the minutes.
I know this is a simple problem, but I can't figure it out atm.
Edits:
Final solution for those interested. Thanks to Michael Brewer-Davis
Period p = new Period(this.startDate, this.endDate);
long hours = p.getHours();
long minutes = p.getMinutes();
String format = String.format("%%0%dd", 2);
return Long.toString(hours) + ":" + String.format(format, minutes);
This should work.
long secs = (this.endDate.getTime() - this.startDate.getTime()) / 1000;
int hours = secs / 3600;
secs = secs % 3600;
int mins = secs / 60;
secs = secs % 60;
Here's how it works with Joda time:
DateTime startTime, endTime;
Period p = new Period(startTime, endTime);
int hours = p.getHours();
int minutes = p.getMinutes();
You could format with Joda's formatters, e.g., PeriodFormat, but I'd suggest using Java's. See this question for more details.
EDIT: be careful using this method to check hours between. This function don't respect days between. It get just hours between two times. 2022-07-20 11.00 and 2022-07-21 12.00 will return 1 hour, not 25 hours.
Here's simple way:
private static int hoursDifference(Date date1, Date date2) {
final int MILLI_TO_HOUR = 1000 * 60 * 60;
return (int) (date1.getTime() - date2.getTime()) / MILLI_TO_HOUR;
}
java.time.Duration
I should like to contribute the modern (java 8+) answer. The solutions using Joda-Time are fine. The Joda-Time project is in maintenance mode, so for new code we should not use it. I follow the official recommendation from the Joda-Time project and use java.time, the modern Java date and time API:
Duration dur = Duration.between(startDate, endDate);
String result = String.format("%d:%02d", dur.toHours(), dur.toMinutesPart());
System.out.println(result);
This works if startDate and endDate both have type Instant or OffsetDateTime or ZonedDateTime or LocalDateTime or LocalTime. All of the mentioned types are from java.time package. If starting with LocalDate, call either of the atStartOfDay methods.
The toMinutesPart methof was introduced in Java 9. If you are using Java 8 (ot ThreeTen Backport), search for java format duration or similar to learn how to format the duration into hours and minutes.
Two quotes from the Joda-Time home page:
Users are now asked to migrate to java.time (JSR-310).
Note that Joda-Time is considered to be a largely “finished” project.
No major enhancements are planned. If using Java SE 8, please migrate
to java.time (JSR-310).
Links
Oracle tutorial: Date Time explaining how to use java.time.
Joda-Time home page
Please follow Somaiah's suggestion in a comment, use Hours instead:
Hours hours = Hours.hoursBetween(startTime, endTime);
The call to getHours() will only return the hour section of the time difference and ignore all year, month differences so it would not be correct in some cases.
If you use Period.toStandardHours() to try to convert the time difference into hours the calculation will throw an exception if the time difference between the two dates includes difference in either year or month, since the length of month is unknown.
So the getTime() method, I presume, returns an integer.
In which case, the left set of parentheses has type int, right?
and
(60*60*1000)
is also an int.
Which means you get long diff = ((int)/(int)) so the integer division is done BEFORE you cast stuff to long. And hence you lose your minutes.
Try casting them BEFORE you divide.
for kotlin, you can use below function and get hours between two date
private val dateFormat: String = "yyyy-MM-dd # hh:mm a"
val startDate = SimpleDateFormat(dateFormat).parse("2018-10-01 # 12:33 PM")
val endDate = SimpleDateFormat(dateFormat).parse("2018-10-01 # 02:46 PM")
private fun hoursDifference(date1: Date, date2: Date): Int {
val milliToHour : Long = 1000 * 60 * 60
return ((date1.time - date2.time) / milliToHour).toInt()
}
println(hoursDifference(endDate,startDate).toString())
Output:
2
Even though there's already an accepted answer, this is what worked for me using the Joda time library.
/**
*
* #param date1
* #param date2
* #return hours between two dates rounded down
*/
public static int hoursBetween(DateTime date1, DateTime date2) {
if(date1 == null || date2 == null) return NOT_FOUND;
return Math.abs(Hours.hoursBetween(date1.toLocalDateTime(), date2.toLocalDateTime()).getHours());
}
private void getHours(Date d1, Date d2){
long diff = d2.getTime() - d1.getTime();
long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffDays = diff / (24 * 60 * 60 * 1000);
long diffHours = diff / (60 * 60 * 1000) % 24;
System.out.print(diffDays + " days, ");
System.out.print(diffHours + " hours, ");
System.out.print(diffMinutes + " minutes, ");
System.out.print(diffSeconds + " seconds.\n");
}`
//Displays:
/* 1 days, 1 hours, 1 minutes, 50 seconds. */
Here's a pure Java 8+ solution that does not involve Joda or mathematical operations
import java.time.*;
import java.time.temporal.*;
// given two java.util.Dates
Date startDate ...
Date endDate ...
// convert them to ZonedDateTime instances
ZonedDateTime start = ZonedDateTime.ofInstant(startDate.toInstant(), ZoneId.systemDefault());
ZonedDateTime end = ZonedDateTime.ofInstant(endDate.toInstant(), ZoneId.systemDefault());
// get the total duration of minutes between them
Duration total = Duration.ofMinutes(ChronoUnit.MINUTES.between(start, end));
// use the duration to determine the hours and minutes values
long hours = total.toHours();
long minutes = total.minusHours(hours).toMinutes();
Here is the simple method :-
Check your Date format,if your date not in this format then change it and pass to this method it will give you a String which is your result. Modify the method as per the requirement.
private String getDateAsTime(String datePrev) {
String daysAsTime = "";
long day = 0, diff = 0;
String outputPattern = "yyyy:MM:dd HH:mm:ss";
SimpleDateFormat outputFormat = new SimpleDateFormat(outputPattern);
Calendar c = Calendar.getInstance();
String dateCurrent = outputFormat.format(c.getTime());
try {
Date date1 = outputFormat.parse(datePrev);
Date date2 = outputFormat.parse(dateCurrent);
diff = date2.getTime() - date1.getTime();
day = TimeUnit.DAYS.convert(diff, TimeUnit.MILLISECONDS);
} catch (ParseException e) {
e.printStackTrace();
}
if (day == 0) {
long hour = TimeUnit.HOURS.convert(diff, TimeUnit.MILLISECONDS);
if (hour == 0)
daysAsTime = String.valueOf(TimeUnit.MINUTES.convert(diff, TimeUnit.MILLISECONDS)).concat(" minutes ago");
else
daysAsTime = String.valueOf(hour).concat(" hours ago");
} else {
daysAsTime = String.valueOf(day).concat(" days ago");
}
return daysAsTime;
}
Hope this will help,

Categories

Resources