I have two date strings and I want to know how many seconds difference there is between them.
2014-05-19 16:37:36:690 // formattedDate
2014-05-19 19:38:00:000 // expString
I use the following code:
SimpleDateFormat sdf = new SimpleDateFormat("yyy-MM-dd HH:mm:ss:SSS");
Date d1 = null;
Date d2 = null;
d1 = sdf.parse(expString);
d2 = sdf.parse(formattedDate);
long diff = d1.getTime() - d2.getTime();
long exp = diff / 1000 % 60;
In this particular example exp is 23. What is the problem here?
.getTime() returns the time in milliseconds since January 1, 1970, 00:00:00 GMT. So diff has the time in milliseconds between the two dates.
long diff = d1.getTime() - d2.getTime();
// diff = 10882310
You user integer division to get to seconds, which drops the extra milliseconds.
long temp = diff / 1000;
// temp = 10823
Then you modulus by 60, which gets you seconds and ignores seconds that were attributed to minutes.
long exp = temp % 60;
// exp = 23
If you want the total time in seconds between the two dates, you don't want to do that last operation.
Don't use modulus division! Just use plain division:
long diff = d1.getTime() - d2.getTime();
long exp = diff / 1000;
Better yet, use the TimeUnit enum from the JDK:
long exp = TimeUnit.MILLISECONDS.toSeconds(d1.getTime() - d2.getTime());
Joda-Time offers a Seconds class to just what you want.
The Joda-Time library also has classes to represent spans of time: Duration, Interval, and Period. You don’t strictly need them for this specific question, but they will be handy for related work.
Below is some untested code off the top of my head.
For simplicity, convert your strings to strict ISO 8601 format. Replace the SPACE with a T.
String inputStart = "…".replace( " ", "T" );
// same for stop
Create date-time objects. Explicitly assign a time zone by which to parse those strings. Are that UTC?
DateTime startDateTime = new DateTime( inputStart, DateTimeZone.UTC );
// repeat for stop
long secs = Seconds.secondsBetween( startDateTime, stopDateTime ).getSeconds();
Related
I have two time stamps which is in UTC with format 2021-05-19T03:03:55.095Z and 2021-05-19T05:10:48.177Z . How can i calculate duration between these two in minutes even when there is date change happened. For example date of second time stamp changed to 2021-05-20T05:10:48.177Z.
Below are the few parser which i have done can anyone help me with this.
private String timeParser (String timestamp){
String output = "";
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
try {
Date date1 = df.parse(timestamp);
DateFormat outputFormatter1 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
output = outputFormatter1.format(date1); //
} catch (ParseException e) {
logger.error(e);
}
return output;
}
public void calculateDuration(JsonNode aggEvent, JsonNode newEvent){
Timestamp createdTimestamp = Timestamp.valueOf(timeParser("2021-05-19T03:03:55.095Z"));
Timestamp newTimestamp = Timestamp.valueOf(timeParser("2021-05-20T05:10:48.177Z"));
float timeDifference = newTimestamp.getTime() - createdTimestamp.getTime();
float minutesDifference = (timeDifference / (1000 * 60)) % 60;
System.out.println(Math.round(minutesDifference * 100.0) / 100.0);
}
Can someone correct here if im doing anything wrong?
Your issues
There are the following issues with your code:
You are parsing each string into a Date, formatting it back to a different string and finally parsing it again, this time into a Timestamp. It’s a detour that gives you extra complication and no gain.
You are using the old SimpleDateFormat, Date and Timestamp classes. They are very poorly designed and have long been replaced by java.time, the modern and far superior date and time API. You should prefer to use the latter.
You must never ever hardcode Z as a literal in your format pattern string. Z is an offset of zero from UTC and must be parsed as an offset, or you will get incorrect results since otherwise SimpleDateFormat will assume the default time zone of your JVM. You may think that in this case, where we are calculating the difference between the two times, the errors of wrong time zone will even out. Not so. For example summer time (DST) transitions in your time zone will influence the calculation that you thought you were doing in UTC, leaving you and those maintaining your code baffled.
Lower case hh in the format pattern string is for hour within morning (AM) or afternoon (PM). You need upper case HH for hour of day.
You should not do the time math yourself in your code. Leave it to the Duration class of java.time for code that is clearer to read and less error-prone.
How to do instead
Edit: My shot at a simple and good way to obtain the time difference with days, hours, minutes and seconds:
Instant createdInstant = Instant.parse("2021-05-19T03:03:55.095Z");
Instant newInstant = Instant.parse("2021-05-20T05:10:48.177Z");
Duration timeDifference = Duration.between(createdInstant, newInstant);
System.out.println(timeDifference);
The output this far looks a bit funny if you’re not used to the ISO 8601 format for durations:
PT26H6M53.082S
It’s straightforward to read when you know how, though. Think of the output as a period of time of 26 hours 6 minutes 53.082 seconds. Only the 24 hours were not converted to a full day, which we had wanted, and which a Duration can do too:
System.out.println("Days: " + timeDifference.toDays());
System.out.println("Hours: " + timeDifference.toHoursPart());
Days: 1
Hours: 2
There are similar toMinutesPart, toSecondsPart and toMillisPart methods.
Link: Wikipedia article: ISO 8601
Single line of code need to be updated.
float minutesDifference = (timeDifference / (1000 * 60));
Here doing %60 means you are covering all difference in hour, minute format
like (timeDifference / (1000 * 60)) / 60 = noOfHours
and (timeDifference / (1000 * 60)) % 60 = reminder of above (Minutes)
See output of this code you will understand better.
I have a object which returns DateTime. I need to generate a random time within next hour.
For example
ZonedDateTime date1 = ZonedDateTime.now(); // returns 2020-01-29T15:00:00.934
ZonedDateTime date2 = ZonedDateTime.now(); // returns 2020-01-29T15:45:00.233
ZonedDateTime convertedDate1;
ZonedDateTime convertedDate2;
//Conversion logic
assertEquals("2020-01-29T15:37:56.345", convertedDate1.toString());
assertEquals("2020-01-29T16:22:22.678", convertedDate2.toString());
You can generate random minutes between 0-60 using ThreadLocalRandom and add them to ZonedDateTime
ZonedDateTime result = date.plusMinutes(ThreadLocalRandom.current().nextInt(60));
In the same way you can add randomly generated seconds and nano seconds also
ZonedDateTime result = date.plusMinutes(ThreadLocalRandom.current().nextInt(58))
.plusSeconds(ThreadLocalRandom.current().nextLong(59))
.plusNanos(ThreadLocalRandom.current().nextLong(999));
Note : nextInt(int bound), nextLong(int bound) will generate between 0 (including) and specific bound (excluding)
Returns a pseudorandom int value between zero (inclusive) and the specified bound (exclusive).
You can try the below code
long leftLimit = 1L;
long rightLimit = 3600000L;
long generatedLong = leftLimit + (long) (Math.random() * (rightLimit - leftLimit));
long currentMillis = System.currentTimeMillis();
long randomTime = currentMillis + generatedLong;
Time time = new Time(currentMillis);
I am getting just time but you can get date and time both.
is there any way in java to do that? I want it to compute the times like that. 0950-0900 is 50 mins but 1700-1610 = 50 mins instead of 90, 1900-1710 = 110 instead of 190. thanks :)
Have a look at Duration (part of the new Date & Time API introduced in Java SE 8).
Eg. (untested):
long minutes = Duration.between(toLocalTime(1710), toLocalTime(1900)).toMinutes();
private LocalTime toLocalTime(int time){
return LocalTime.of(time / 100, time % 100);
}
You can use the new Java Date API from Java 8.
LocalTime start = LocalTime.parse("19:00");
LocalTime end = LocalTime.parse("17:10");
Duration elapsed = Duration.between(start, end);
System.out.println(elapsed.toMinutes());
This will output: -110 and 110 if you switch start and end.
If you've just got integers, and you don't care about validation, you can do it all without touching time parts at all:
public int getMinutesBetween(int time1, int time2) {
// Extract hours and minutes from compound values, which are base-100,
// effectively.
int hours1 = time1 / 100;
int hours2 = time2 / 100;
int minutes1 = time1 % 100;
int minutes2 = time2 % 100;
// Now we can perform the arithmetic based on 60-minute hours as normal.
return (hours2 - hours1) * 60 + (minutes2 - minutes1);
}
However, I'd strongly recommend that you use more appropriate representations - these aren't just normal int values... they're effectively "time of day" values, so LocalTime (in either Joda Time or Java 8's java.time) is the most appropriate representation, IMO.
I want to calculate difference between two times which is calculate correctly then i have to half it so i divide it with 2 results are okay. but when i am trying to add the timdedifferencemillis to startTime its not giving me the correct result...
starttime= 05:53
endtime= 17:57
i want results 11:55
but my code giving me 06:55
please help.....
protected String transitTime2(String endtime, String starttime) {
SimpleDateFormat dt = new SimpleDateFormat("hh:mm");
Date startTime = null;
Date endTime;
long timdedifferencemillis = 0;
try {
startTime = dt.parse(starttime);
endTime = dt.parse(endtime);
long diff=startTime.getTime();
timdedifferencemillis = (endTime.getTime() - startTime.getTime())/2;
//timdedifferencemillis
} catch (ParseException e) {
e.printStackTrace();
}
long timdedifferencemillis1=startTime.getTime()+timdedifferencemillis;
int minutes = Math
.abs((int) ((timdedifferencemillis1 / (1000 * 60)) % 60));
int hours = Math
.abs((int) ((timdedifferencemillis1 / (1000 * 60 * 60)) % 24));
String hmp = String.format("%02d %02d ", hours, minutes);
return hmp;
}
The problem is probably time zone; when you parse endtime and starttime initially, by default (in the absence of an explicit time zone indicated in the format string and represented in the input), Java assumes that the times provided are relative to the local time zone of the system. Then, when you call getTime(), it returns
the number of milliseconds since January 1, 1970, 00:00:00 GMT represented by this Date object
One solution is to tell your SimpleDateFormat object to assume that all strings it parses are in GMT, rather than in the local time zone. Try adding this line after you initialize dt, but before calling dt.parse(...):
dt.setTimeZone(TimeZone.getTimeZone("GMT"));
This is quite easy to do with the new java.time API in Java 8 or with the JODA Time library:
import java.time.Duration;
import java.time.LocalTime;
public class TimeDiff {
public static void main(String[] args) {
LocalTime start = LocalTime.parse("05:53");
LocalTime end = LocalTime.parse("17:57");
// find the duration between the start and end times
Duration duration = Duration.between(start, end);
// add half the duration to the start time to find the midpoint
LocalTime midPoint = start.plus(duration.dividedBy(2));
System.out.println(midPoint);
}
}
Output:
11:55
By using LocalTime objects, you avoid any problems with time zones.
I think the problem is the types "long" and "int" in your code ;when we divide with 2 ( long timdedifferencemillis )the result must be "double".
Please help me to write a method that returns number (int) of days from a provided day to the todays date.
So let's say, I am providing into a method an int 110515 (for May 15, 2011). It should return 9 (inclusive or exclusive is not important to me).
If you can use Joda, this is super simple:
Days d = Days.daysBetween(startDate, endDate);
int days = d.getDays();
Of course you could combine these.
int days = Days.daysBetween(startDate, endDate).getDays();
Joda objects can go back and forth between the JDK's date class pretty easily.
For the first part, make a DateFormatter then parse the string based on it, like this:
DateTimeFormatter fmt = DateTimeFormat.forPattern("yyyyMMdd");
DateTime dt = fmt.parseDateTime(strInputDateTime);
(After turning the int into a string of course.)
Should dates in the future include the current day? Meaning if today is May 24th 2011, should 110529 result in 4 or 5?
public static long numberOfDays(final long date) throws ParseException {
final Calendar compare = Calendar.getInstance();
compare.setTime(new SimpleDateFormat("yyMMdd").parse(String.valueOf(date)));
final int dstOffset = compare.get(Calendar.DST_OFFSET);
final long currentTimeMillis = System.currentTimeMillis();
final long compareTimeInMillis = compare.getTimeInMillis();
long difference = 0;
if (currentTimeMillis >= compareTimeInMillis) {
difference = currentTimeMillis - compareTimeInMillis - dstOffset;
} else {
difference = compareTimeInMillis - currentTimeMillis + dstOffset;
}
return difference / (24 * 60 * 60 * 1000);
}
Since this seems like a homework question I will help you out. You will want to use Calendar.getTimeInMillis. Then you will want to create a constant that is NUMBER_OF_MILLIS_IN_DAY . From there you subtract the initialDate from the currentDate (both time in millis) and divide by the constant.