This question already has answers here:
integer giving negative values in java in multiplication using positive numbers [duplicate]
(4 answers)
Closed 3 years ago.
I know this has been asked on here many times previously, but I'm haven't been able to find anything specific to my case. I'm trying to find the difference between the current datetime and a previous datetime, each with the format yyyy-MM-dd HH:mm:ss.s. Based on the answer given here, I've come up with the following code:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.s");
String earliestRunTime = "2017-12-16 01:30:08.0";
Date currentDate = new Date();
log.info("Current Date: {}", format.format(currentDate));
try {
Date earliestDate = format.parse(earliestRunTime);
long diff = currentDate.getTime() - earliestDate.getTime();
long diffSeconds = diff / 1000 % 60;
long diffMinutes = diff / (60 * 1000) % 60;
long diffHours = diff / (60 * 60 * 1000) % 24;
long diffDays = diff / (24 * 60 * 60 * 1000) % 30;
long diffMonths = diff / (30 * 24 * 60 * 60 * 1000) % 12;
long diffYears = diff / (12 * 30 * 24 * 60 * 60 * 1000);
return String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",
diffYears, diffMonths, diffDays, diffHours, diffMinutes, diffSeconds);
}
catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
When I run the code, the JSON returns the following result:
lifetime: "41 years, -1 months, 14 days, 9 hours, 42 minutes, 37 seconds"
I have two questions here:
Where am I going wrong in my calculations 41 years and a negative number?
Is there a better way for me to do this? My current setup does not consider leap years or a 365 day year, and I need to take these into account.
Where am I going wrong in my calculations 41 years and a negative number?
Because the denominator will overflow. You need to use Long:
long diffMonths = diff / (30 * 24 * 60 * 60 * 1000L) % 12; //Notice the L at the end
long diffYears = diff / (12 * 30 * 24 * 60 * 60 * 1000L); //Notice the L at the end
Also note that 12 * 30 is a really bad approximation of the number of days in a year.
Is there a better way for me to do this?
Yes. Use Duration api from Java 8. https://www.mkyong.com/java8/java-8-period-and-duration-examples/
It's hard to give precise answer, because the question is a bit vague. For example - If one of the year was a leap year and you were comparing dates 2020/03/28 and 2021/03/28, what should be the result? 1 year or 1 years, 1 days? (2020 is a leap year so after 03/28, there's also 03/29)
Where am I going wrong in my calculations 41 years and a negative number?
Apart from using the notoriously troublesome and long outdated SimpleDateFormat class and the just as outdated Date there are the following bugs in your code:
You are parsing 08.0 as 8 seconds 0 seconds. On my JDK-11 SimpleDateFormat opts for the 0 seconds and discards the 8 seconds that I think are correct. SimpleDateFormat cannot parse one decimal on the seconds (only exactly three decimals), so the solution to this bug is discarding SimpleDateFormat altogether.
As others have said you have an int overflow in your multiplications. For example, 30 * 24 * 60 * 60 * 1000 should give 2 592 000 000, but since an int cannot hold this number, you get -1 702 967 296 instead. Since this is a negative number, the following division gives you a negative number of months.
As Solomon Slow pointed out in a comment, a month may be 28, 29, 30 or 31 days. When setting all months to 30 days you risk incorrect numbers of days and months and in the end also years. When I ran your code today, the correct answer would have been 1 year, 4 months, 13 days, but I got 19 days instead, 6 days too much.
You are not taking summer time (DST) and other time anomalies into account. These may cause a day to be for example 23 or 25 hours, giving an error.
Or to sum up: Your error was that you tried to do the calculation “by hand”. Date and time math is too complex and error-prone to do this. You should always leave it to well-proven library classes instead.
Is there a better way for me to do this? My current setup does not consider leap years or a 365 day year, and I need to take these into
account.
Yes, there is a much better way. The best way may be to use the PeriodDuration class from the ThreeTen Extra project, see the link below. I am not going to install that library in my computer right now, so I will just show the good and modern solution using built-in classes:
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S");
LocalDateTime currentDateTime = LocalDateTime.now(ZoneId.of("Australia/Sydney"));
String earliestRunTime = "2017-12-16 01:30:08.0";
LocalDateTime earliestDateTime = LocalDateTime.parse(earliestRunTime, dtf);
// We want to find a period (years, months, days) and a duration (hours, minutes, seconds).
// To do that we cut at the greatest possible whole number of days
// and then measure the period before the cut and the duration after it.
LocalDateTime cut = earliestDateTime.plusDays(
ChronoUnit.DAYS.between(earliestDateTime, currentDateTime));
Period p = Period.between(earliestDateTime.toLocalDate(), cut.toLocalDate());
Duration d = Duration.between(cut, currentDateTime);
String result = String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",
p.getYears(), p.getMonths(), p.getDays(),
d.toHours(), d.toMinutesPart(), d.toSecondsPart());
System.out.println(result);
When I ran the code just now I got:
1 years, 4 months, 13 days, 19 hours, 26 minutes, 7 seconds
In java.time, the modern Java date and time API, a Period is an amount of years, months and days, and a Duration is an amount of hours, minutes, seconds and fraction of second (down to nanoseconds). Since you wanted both, I am using both classes.
The toXxxPart methods of Duration I am using were introduced in Java 9. If you are using Java 8 (or the ThreeTen Backport) printing the minutes and seconds is a little bit more complicated. Search for java format duration or similar to learn how.
I am still not taking summer time into account. To do that we would need to know the time zone of the earliest run time string and then use ZonedDateTime instead of LocalDateTime. The code would otherwise be very similar.
Links
ThreeTen Extra
Documentation of PeriodDuration
Oracle Tutorial: Date Time explaining how to use java.time
Using the same approach you did, you need to explicitly identify the denominator as long values. Currently, it assumes them to be integers, which causes a numeric overflow - meaning the value computed is too large for a integer. This would explain why you get negative/arbitrary values. Fix is simple:
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.s");
String earliestRunTime = "2017-12-16 01:30:08.0";
Date currentDate = new Date();
log.info("Current Date: {}" + format.format(currentDate));
try {
Date earliestDate = format.parse(earliestRunTime);
long diff = currentDate.getTime() - earliestDate.getTime();
long diffSeconds = diff / 1000L % 60L;
long diffMinutes = diff / (60L * 1000L) % 60L;
long diffHours = diff / (60L * 60L * 1000L) % 24L;
long diffDays = diff / (24L * 60L * 60L * 1000L) % 30L;
long diffMonths = diff / (30L * 24L * 60L * 60L * 1000L) % 12L;
long diffYears = diff / (12L * 30L * 24L * 60L * 60L * 1000L);
return String.format("%s years, %s months, %s days, %s hours, %s minutes, %s seconds",
diffYears, diffMonths, diffDays, diffHours, diffMinutes, diffSeconds);
}
catch (Exception e) {
e.printStackTrace();
return e.getMessage();
}
This question already has answers here:
How do I calculate someone's age in Java?
(28 answers)
Closed 6 years ago.
birthDate's type is java.util.Date .
What is the best way to calculate the current age?
I want a java.util.Date variable storing TODAY - birthDate.
That depends on what do you mean by current age.
If you mean the precise astronomical meaning, use
DateTime startDate = new DateTime(2000, 1, 19, 5, 14, 0, 0);
DateTime endDate = new DateTime();
Days d = Days.daysBetween(startDate, endDate);
If you need the common sense difference, based on both dates given in whole days:
long thisDay = (new Date()).getTime() / (1000 * 60 * 60 * 24);
DateFormat formatter = new SimpleDateFormat("dd-MMM-yy");
Date birthDate = formatter.parse("11-June-07");
long birthdayInDays = birthDate.getTime() / (1000 * 60 * 60 * 24);
long dayDiff = thisDay - birthdayInDays;
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I am newbie to java and android. One of my android news app i am displaying the time as "7 August 2014, 8:20 am"
But I need to display it like:
5 mins ago
1 hour ago
2 days ago
Found many libraries such us pretty time, joda. But i dont know how to add it to my android app.
Even this link https://stackoverflow.com/a/13018647/2020685 show me.
But how to pass my date and time into it.
Any simple code to do it.
Thanks
What you want to display is called as the Relative time display. Android provides methods
to display time relative to your current time. You don't have to use any third party library just for this purpose.
You can use
DateUtils.getRelativeTimeSpanString(long time, long now, long minResolution)
Refer docs Here
eg.
DateUtils.getRelativeTimeSpanString(your_time_in_milliseconds, current_ time_in_millisecinds,DateUtils.MINUTE_IN_MILLIS);
UPDATE1:
You can try following to pass your date and get the milliseconds for it.
public static long getDateInMillis(String srcDate) {
SimpleDateFormat desiredFormat = new SimpleDateFormat(
"d MMMM yyyy, hh:mm aa");
long dateInMillis = 0;
try {
Date date = desiredFormat.parse(srcDate);
dateInMillis = date.getTime();
return dateInMillis;
} catch (ParseException e) {
Log.d("Exception while parsing date. " + e.getMessage());
e.printStackTrace();
}
return 0;
}
Hope it helps you.
Create the below logic:
Convert your time to seconds, get the diff ( delta ) from current file :
% it by 3600*365
if the result > 0 then display year(s) ago
else % it by 3600 * 30
if the result > 0 then display month(s) ago
else % it by 3600 * 7
if the result > 0 then display week(s) ago
else % it by 3600
if the result > 0 then display day(s) ago
else % it by 3600 / 24
if the result > 0 then display hour(s) ago
else % it by 60,
if the result > 0 then display minute(s) ago
NOTE: % means mod (modulus operation)
Date nowDate=new Date();
Date yourPassDate=//you have a date here.
long now=nowDate.getTime();
long time=yourPassDate.getTime();
final long diff = now - time; //now you have a date interval representing with mileseconds.
//you can use this diff to do something like:
if (diff <1000*60)//less than one minute
//...
else if (diff <1000*60*60) //less than 1 hour
//...
else if (diff < 1000*60*60*24)//less than one day
//...
This is what java doc of Date.getTime() said:
* Returns the number of milliseconds since January 1, 1970, 00:00:00 GMT
* represented by this <tt>Date</tt> object.
This question already has answers here:
How do I increment a java.sql.Timestamp by 14 days?
(5 answers)
Closed 8 years ago.
How to add 3 hours to the time that store in java.sql.Timestamp by not using the deprecated API?
I use the below code, but it doesn't work.
Timestamp later = new Timestamp(old + (1000 * 60 * 60 * 3));
Assuming old is a Timestamp; your code is close. You just need to convert the old timestamp to a millisecond value first. Do:
Timestamp later = new Timestamp(old.getTime() + (1000 * 60 * 60 * 3));
Neither getTime() nor the Timestamp(long) constructor are deprecated.
Note that all of this information is readily available in the Timestamp documentation.
You can use Calendar for date manipulation:
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
calendar.add(Calendar.HOUR, 3);
Timestamp timestamp = new Timestamp(calendar.getTimeInMillis());
This question already has answers here:
How to subtract X days from a date using Java calendar?
(11 answers)
Closed 9 years ago.
long epoch = System.currentTimeMillis() / 1000;
String dateStr = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'.0Z'").format(new java.util.Date(epoch * 1000));
System.out.println(dateStr);
Can anyone please tell me how to get the time stamp of 4 weeks from the current one? I'm working on payroll testing.
Subtract the number of milliseconds in 4 weeks from the current time.
long now = System.currentTimeMillis();
long fourWeeksAgo = now - 1000 * 60 * 60 * 24 * 28;
java.util.Calendar provides a means of manipulating dates so that code is readable:
Calendar calendar = Calendar.getInstance();
calendar.add(Calendar.WEEK_OF_YEAR, -4);
long fourWeeksAgo = calendar.getTime().getTime();
java.util.Calendar c = java.util.Calendar.getInstance();
c.add(java.util.Calendar.WEEK_OF_MONTH, -4);