Related
This question already has answers here:
How do I time a method's execution in Java?
(42 answers)
How do I calculate the elapsed time of an event in Java? [duplicate]
(6 answers)
Closed 4 years ago.
I want to have something like this:
public class Stream
{
public startTime;
public endTime;
public getDuration()
{
return startTime - endTime;
}
}
Also it is important that for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.
Which types to use in order to accomplish this in Java?
Unfortunately, none of the ten answers posted so far are quite right.
If you are measuring elapsed time, and you want it to be correct, you must use System.nanoTime(). You cannot use System.currentTimeMillis(), unless you don't mind your result being wrong.
The purpose of nanoTime is to measure elapsed time, and the purpose of currentTimeMillis is to measure wall-clock time. You can't use the one for the other purpose. The reason is that no computer's clock is perfect; it always drifts and occasionally needs to be corrected. This correction might either happen manually, or in the case of most machines, there's a process that runs and continually issues small corrections to the system clock ("wall clock"). These tend to happen often. Another such correction happens whenever there is a leap second.
Since nanoTime's purpose is to measure elapsed time, it is unaffected by any of these small corrections. It is what you want to use. Any timings currently underway with currentTimeMillis will be off -- possibly even negative.
You may say, "this doesn't sound like it would ever really matter that much," to which I say, maybe not, but overall, isn't correct code just better than incorrect code? Besides, nanoTime is shorter to type anyway.
Previously posted disclaimers about nanoTime usually having only microsecond precision are valid. Also it can take more than a whole microsecond to invoke, depending on circumstances (as can the other one), so don't expect to time very very small intervals correctly.
Which types to use in order to accomplish this in Java?
The short answer is a long. Now, more on how to measure...
System.currentTimeMillis()
The "traditional" way to do this is indeed to use System.currentTimeMillis():
long startTime = System.currentTimeMillis();
// ... do something ...
long estimatedTime = System.currentTimeMillis() - startTime;
o.a.c.l.t.StopWatch
Note that Commons Lang has a StopWatch class that can be used to measure execution time in milliseconds. It has methods methods like split(), suspend(), resume(), etc that allow to take measure at different points of the execution and that you may find convenient. Have a look at it.
System.nanoTime()
You may prefer to use System.nanoTime() if you are looking for extremely precise measurements of elapsed time. From its javadoc:
long startTime = System.nanoTime();
// ... the code being measured ...
long estimatedTime = System.nanoTime() - startTime;
Jamon
Another option would be to use JAMon, a tool that gathers statistics (execution time, number of hit, average execution time, min, max, etc) for any code that comes between start() and stop() methods. Below, a very simple example:
import com.jamonapi.*;
...
Monitor mon=MonitorFactory.start("myFirstMonitor");
...Code Being Timed...
mon.stop();
Check out this article on www.javaperformancetunning.com for a nice introduction.
Using AOP
Finally, if you don't want to clutter your code with these measurement (or if you can't change existing code), then AOP would be a perfect weapon. I'm not going to discuss this very deeply but I wanted at least to mention it.
Below, a very simple aspect using AspectJ and JAMon (here, the short name of the pointcut will be used for the JAMon monitor, hence the call to thisJoinPoint.toShortString()):
public aspect MonitorAspect {
pointcut monitor() : execution(* *.ClassToMonitor.methodToMonitor(..));
Object arround() : monitor() {
Monitor monitor = MonitorFactory.start(thisJoinPoint.toShortString());
Object returnedObject = proceed();
monitor.stop();
return returnedObject;
}
}
The pointcut definition could be easily adapted to monitor any method based on the class name, the package name, the method name, or any combination of these. Measurement is really a perfect use case for AOP.
Your new class:
public class TimeWatch {
long starts;
public static TimeWatch start() {
return new TimeWatch();
}
private TimeWatch() {
reset();
}
public TimeWatch reset() {
starts = System.currentTimeMillis();
return this;
}
public long time() {
long ends = System.currentTimeMillis();
return ends - starts;
}
public long time(TimeUnit unit) {
return unit.convert(time(), TimeUnit.MILLISECONDS);
}
}
Usage:
TimeWatch watch = TimeWatch.start();
// do something
long passedTimeInMs = watch.time();
long passedTimeInSeconds = watch.time(TimeUnit.SECONDS);
Afterwards, the time passed can be converted to whatever format you like, with a calender for example
Greetz,
GHad
If the purpose is to simply print coarse timing information to your program logs, then the easy solution for Java projects is not to write your own stopwatch or timer classes, but just use the org.apache.commons.lang.time.StopWatch class that is part of Apache Commons Lang.
final StopWatch stopwatch = new StopWatch();
stopwatch.start();
LOGGER.debug("Starting long calculations: {}", stopwatch);
...
LOGGER.debug("Time after key part of calcuation: {}", stopwatch);
...
LOGGER.debug("Finished calculating {}", stopwatch);
tl;dr
for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.
Not possible. If you have only time-of-day, the clock stops at midnight. Without the context of dates, how do we know if you mean 1 AM on the next day, next week, or next decade?
So going from 11 PM to 1 AM means moving backwards in time 22 hours, running the hands of the clock counterclockwise. See the result below, a negative twenty-two hours.
Duration.between( // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
LocalTime.of( 23 , 0 ) , // A time-of-day without a date and without a time zone.
LocalTime.of( 1 , 0 ) // A time-of-day clock stops at midnight. So getting to 1 AM from 11 PM means going backwards 22 hours.
) // Return a `Duration` object.
.toString() // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS
PT-22H
Crossing midnight requires the larger context of date in addition to time-of-day (see below).
How do I measure time elapsed in Java?
Capture the current moment in UTC, with Instant.now().
Capture another such moment later.
Pass both to Duration.between.
(a) From the resulting Duration object, extract a number of 24-hour days, hours, minutes, seconds, and fractional second in nanoseconds by calling the various to…Part methods.(b) Or, call toString to generate a String in standard ISO 8601 format of PnYnMnDTnHnMnS.
Example code, using pair of Instant objects.
Duration.between( // Represent a span of time a total number of seconds plus a fractional second in nanoseconds.
then , // Some other `Instant` object, captured earlier with `Instant.now()`.
Instant.now() // Capture the current moment in UTC with a resolution as fine as nanoseconds, depending on the limits of your host computer hardware clock and operating system. Generally you will get current moment in microseconds (six decimal digits of fractional second) in Java 9, 10, and 11, but only milliseconds in Java 8.
) // Return a `Duration` object.
.toString() // Generate a `String` representing this span of time using standard ISO 8601 format: PnYnMnDTnHnMnS
PT3M27.602197S
New Technology In Java 8+
We have new technology for this now built into Java 8 and later, the java.time framework.
java.time
The java.time framework is defined by JSR 310, inspired by the highly successful Joda-Time project, extended by the ThreeTen-Extra project, and described in the Oracle Tutorial.
The old date-time classes such as java.util.Date/.Calendar bundled with the earliest versions of Java have proven to be poorly designed, confusing, and troublesome. They are supplanted by the java.time classes.
Resolution
Other answers discuss resolution.
The java.time classes have nanosecond resolution, up to nine digits of a decimal fraction of a second. For example, 2016-03-12T04:29:39.123456789Z.
Both the old java.util.Date/.Calendar classes and the Joda-Time classes have millisecond resolution (3 digits of fraction). For example, 2016-03-12T04:29:39.123Z.
In Java 8, the current moment is fetched with up to only millisecond resolution because of a legacy issue. In Java 9 and later, the current time can be determined up to nanosecond resolution provided your computer’s hardware clock runs so finely.
Time-Of-Day
If you truly want to work with only the time-of-day lacking any date or time zone, use the LocalTime class.
LocalTime sooner = LocalTime.of ( 17, 00 );
LocalTime later = LocalTime.of ( 19, 00 );
A Duration represents a span of time it terms of a count of seconds plus nanoseconds.
Duration duration = Duration.between ( sooner, later );
Dump to console.
System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );
sooner: 17:00 | later: 19:00 | duration: PT2H
ISO 8601
Notice the default output of Duration::toString is in standard ISO 8601 format. In this format, the P marks the beginning (as in 'Period'), and the T separates any years-months-days portion from the hours-minutes-seconds portion.
Crossing Midnight
Unfortunately, working with time-of-day only gets tricky when you wrap around the clock crossing midnight. The LocalTime class handles this by assuming you want to go backwards to an earlier point in the day.
Using the same code as above but going from 23:00 to 01:00 results in a negative twenty-two hours (PT-22H).
LocalTime sooner = LocalTime.of ( 23, 0 );
LocalTime later = LocalTime.of ( 1, 0 );
sooner: 23:00 | later: 01:00 | duration: PT-22H
Date-Time
If you intend to cross midnight, it probably makes sense for you to be working with date-time values rather than time-of-day-only values.
Time Zone
Time zone is crucial to dates. So we specify three items: (1) the desired date, (2) desired time-of-day, and (3) the time zone as a context by which to interpret that date and time. Here we arbitrarily choose the time zone of the Montréal area.
If you define the date by only an offset-from-UTC, use a ZoneOffset with a OffsetDateTime. If you have a full time zone (offset plus rules for handling anomalies such as Daylight Saving Time), use a ZoneId with a ZonedDateTime.
LocalDate localDate = LocalDate.of ( 2016, 1, 23 );
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
ZonedDateTime sooner = ZonedDateTime.of ( localDate, LocalTime.of ( 23, 0 ), zoneId );
We specify the later time as next day at 1:00 AM.
ZonedDateTime later = ZonedDateTime.of ( localDate.plusDays ( 1 ), LocalTime.of ( 1, 0 ), zoneId );
We calculate the Duration in the same manner as seen above. Now we get the two hours expected by this Question.
Duration duration = Duration.between ( sooner, later );
Dump to console.
System.out.println ( "sooner: " + sooner + " | later: " + later + " | duration: " + duration );
sooner: 2016-01-23T23:00-05:00[America/Montreal] | later: 2016-01-24T01:00-05:00[America/Montreal] | duration: PT2H
Daylight Saving Time
If the date-times at hand had involved Daylight Saving Time (DST) or other such anomaly, the java.time classes would adjust as needed. Read class doc for details.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android bundle implementations of the java.time classes.
For earlier Android (<26), the ThreeTenABP project adapts ThreeTen-Backport (mentioned above). See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
It is worth noting that
System.currentTimeMillis() has only millisecond accuracy at best. At worth its can be 16 ms on some windows systems. It has a lower cost that alternatives < 200 ns.
System.nanoTime() is only micro-second accurate on most systems and can jump on windows systems by 100 microseconds (i.e sometimes it not as accurate as it appears)
Calendar is a very expensive way to calculate time. (i can think of apart from XMLGregorianCalendar) Sometimes its the most appropriate solution but be aware you should only time long intervals.
Which types to use in order to accomplish this in Java?
Answer: long
public class Stream {
public long startTime;
public long endTime;
public long getDuration() {
return endTime - startTime;
}
// I would add
public void start() {
startTime = System.currentTimeMillis();
}
public void stop() {
endTime = System.currentTimeMillis();
}
}
Usage:
Stream s = ....
s.start();
// do something for a while
s.stop();
s.getDuration(); // gives the elapsed time in milliseconds.
That's my direct answer for your first question.
For the last "note" I would suggest you to use Joda Time. It contains an interval class suitable for what you need.
Java provides the static method System.currentTimeMillis(). And that's returning a long value, so it's a good reference. A lot of other classes accept a 'timeInMillis' parameter which is long as well.
And a lot of people find it easier to use the Joda Time library to do calculations on dates and times.
If you prefer using Java's Calendar API you can try this,
Date startingTime = Calendar.getInstance().getTime();
//later on
Date now = Calendar.getInstance().getTime();
long timeElapsed = now.getTime() - startingTime.getTime();
If you are writing an application that must deal with durations of time, then please take a look at Joda-Time which has class specifically for handling Durations, Intervals, and Periods. Your getDuration() method looks like it could return a Joda-Time Interval:
DateTime start = new DateTime(2004, 12, 25, 0, 0, 0, 0);
DateTime end = new DateTime(2005, 1, 1, 0, 0, 0, 0);
public Interval getInterval() {
Interval interval = new Interval(start, end);
}
Byte Stream Reader Elapsed Time for 23.7 MB is 96 secs
import java.io.*;
import java.io.IOException;
import java.util.Scanner;
class ElaspedTimetoCopyAFileUsingByteStream
{
private long startTime = 0;
private long stopTime = 0;
private boolean running = false;
public void start()
{
this.startTime = System.currentTimeMillis();
this.running = true;
}
public void stop()
{
this.stopTime = System.currentTimeMillis();
this.running = false;
}
public long getElapsedTime()
{
long elapsed;
if (running) {
elapsed = (System.currentTimeMillis() - startTime);
}
else {
elapsed = (stopTime - startTime);
}
return elapsed;
}
public long getElapsedTimeSecs()
{
long elapsed;
if (running)
{
elapsed = ((System.currentTimeMillis() - startTime) / 1000);
}
else
{
elapsed = ((stopTime - startTime) / 1000);
}
return elapsed;
}
public static void main(String[] args) throws IOException
{
ElaspedTimetoCopyAFileUsingByteStream s = new ElaspedTimetoCopyAFileUsingByteStream();
s.start();
FileInputStream in = null;
FileOutputStream out = null;
try {
in = new FileInputStream("vowels.txt"); // 23.7 MB File
out = new FileOutputStream("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
}finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
s.stop();
System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
}
}
[Elapsed Time for Byte Stream Reader][1]
**Character Stream Reader Elapsed Time for 23.7 MB is 3 secs**
import java.io.*;
import java.io.IOException;
import java.util.Scanner;
class ElaspedTimetoCopyAFileUsingCharacterStream
{
private long startTime = 0;
private long stopTime = 0;
private boolean running = false;
public void start()
{
this.startTime = System.currentTimeMillis();
this.running = true;
}
public void stop()
{
this.stopTime = System.currentTimeMillis();
this.running = false;
}
public long getElapsedTime()
{
long elapsed;
if (running) {
elapsed = (System.currentTimeMillis() - startTime);
}
else {
elapsed = (stopTime - startTime);
}
return elapsed;
}
public long getElapsedTimeSecs()
{
long elapsed;
if (running)
{
elapsed = ((System.currentTimeMillis() - startTime) / 1000);
}
else
{
elapsed = ((stopTime - startTime) / 1000);
}
return elapsed;
}
public static void main(String[] args) throws IOException
{
ElaspedTimetoCopyAFileUsingCharacterStream s = new ElaspedTimetoCopyAFileUsingCharacterStream();
s.start();
FileReader in = null; // CharacterStream Reader
FileWriter out = null;
try {
in = new FileReader("vowels.txt"); // 23.7 MB
out = new FileWriter("output.txt");
int c;
while ((c = in.read()) != -1) {
out.write(c);
}
}finally {
if (in != null) {
in.close();
}
if (out != null) {
out.close();
}
}
s.stop();
System.out.println("elapsed time in seconds: " + s.getElapsedTimeSecs());
}
}
[Elapsed Time for Character Stream Reader][2]
[1]: https://i.stack.imgur.com/hYo8y.png
[2]: https://i.stack.imgur.com/xPjCK.png
If you're getting your timestamps from System.currentTimeMillis(), then your time variables should be longs.
i found this code to be useful when timing things:
public class Et {
public Et() {
reset();
}
public void reset() {
t0=System.nanoTime();
}
public long t0() {
return t0;
}
public long dt() {
return System.nanoTime()-t0();
}
public double etms() {
return etms(dt());
}
#Override public String toString() {
return etms()+" ms.";
}
public static double etms(long dt) {
return dt/1000000.; // 1_000_000. breaks cobertura
}
private Long t0;
}
Use this:
SimpleDateFormat format = new SimpleDateFormat("HH:mm");
Date d1 = format.parse(strStartTime);
Date d2 = format.parse(strEndTime);
long diff = d2.getTime() - d1.getTime();
long diffSeconds,diffMinutes,diffHours;
if (diff > 0) {
diffSeconds = diff / 1000 % 60;
diffMinutes = diff / (60 * 1000) % 60;
diffHours = diff / (60 * 60 * 1000);
}
else{
long diffpos = (24*((60 * 60 * 1000))) + diff;
diffSeconds = diffpos / 1000 % 60;
diffMinutes = diffpos / (60 * 1000) % 60;
diffHours = (diffpos / (60 * 60 * 1000));
}
(Also it is important that for example if the startTime it's 23:00 and endTime 1:00 to get a duration of 2:00.)
the "else" part can get it correct
I built a formatting function based on stuff I stole off SO. I needed a way of "profiling" stuff in log messages, so I needed a fixed length duration message.
public static String GetElapsed(long aInitialTime, long aEndTime, boolean aIncludeMillis)
{
StringBuffer elapsed = new StringBuffer();
Map<String, Long> units = new HashMap<String, Long>();
long milliseconds = aEndTime - aInitialTime;
long seconds = milliseconds / 1000;
long minutes = milliseconds / (60 * 1000);
long hours = milliseconds / (60 * 60 * 1000);
long days = milliseconds / (24 * 60 * 60 * 1000);
units.put("milliseconds", milliseconds);
units.put("seconds", seconds);
units.put("minutes", minutes);
units.put("hours", hours);
units.put("days", days);
if (days > 0)
{
long leftoverHours = hours % 24;
units.put("hours", leftoverHours);
}
if (hours > 0)
{
long leftoeverMinutes = minutes % 60;
units.put("minutes", leftoeverMinutes);
}
if (minutes > 0)
{
long leftoverSeconds = seconds % 60;
units.put("seconds", leftoverSeconds);
}
if (seconds > 0)
{
long leftoverMilliseconds = milliseconds % 1000;
units.put("milliseconds", leftoverMilliseconds);
}
elapsed.append(PrependZeroIfNeeded(units.get("days")) + " days ")
.append(PrependZeroIfNeeded(units.get("hours")) + " hours ")
.append(PrependZeroIfNeeded(units.get("minutes")) + " minutes ")
.append(PrependZeroIfNeeded(units.get("seconds")) + " seconds ")
.append(PrependZeroIfNeeded(units.get("milliseconds")) + " ms");
return elapsed.toString();
}
private static String PrependZeroIfNeeded(long aValue)
{
return aValue < 10 ? "0" + aValue : Long.toString(aValue);
}
And a test class:
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import junit.framework.TestCase;
public class TimeUtilsTest extends TestCase
{
public void testGetElapsed()
{
long start = System.currentTimeMillis();
GregorianCalendar calendar = (GregorianCalendar) Calendar.getInstance();
calendar.setTime(new Date(start));
calendar.add(Calendar.MILLISECOND, 610);
calendar.add(Calendar.SECOND, 35);
calendar.add(Calendar.MINUTE, 5);
calendar.add(Calendar.DAY_OF_YEAR, 5);
long end = calendar.getTimeInMillis();
assertEquals("05 days 00 hours 05 minutes 35 seconds 610 ms", TimeUtils.GetElapsed(start, end, true));
}
}
I'm using Joda-Time Duration to get the duration between two DateTime:
DateTime startTimeDate = new DateTime(startTimeDateInLong, DateTimeZone.UTC);
DateTime endTimeDate = new DateTime(endTimeDateInLong, DateTimeZone.UTC);
Duration duration = new Duration(startTimeDate, endTimeDate);
I want to convert per following rules:
0-60 seconds --> 1 minute ..
1.5 - 1 hour --> 1 hour
1.6 hour - 2 hour --> 2 hour
I am using duration.toStandardHours(), but for 96 minutes it gives 1 hour instead I want 2 hours.
The Duration class doesn't round the values the way you want. Even if you get a duration of 1 hour, 59 minutes, 59 seconds and 999 milliseconds, toStandardHours() will return 1.
To get the results you want, you must get the total in seconds, and then manipulate this value accordingly. You can use the java.math.BigDecimal class, with a java.math.RoundingMode to control how the values are rounded:
// 96-minutes duration
Duration duration = new Duration(96 * 60 * 1000);
long secs = duration.toStandardSeconds().getSeconds();
if (secs >= 3600) { // more than 1 hour
BigDecimal secondsPerHour = new BigDecimal(3600);
int hours = new BigDecimal(secs).divide(secondsPerHour, RoundingMode.HALF_DOWN).intValue();
System.out.println(hours + " hour" + (hours > 1 ? "s" : "")); // 2 hours
} else {
int mins;
if (secs == 0) { // round zero seconds to 1 minute
mins = 1;
} else {
// always round up (1-59 seconds = 1 minute)
BigDecimal secondsPerMin = new BigDecimal(60);
mins = new BigDecimal(secs).divide(secondsPerMin, RoundingMode.UP).intValue();
}
System.out.println(mins + " minute" + (mins > 1 ? "s" : ""));
}
This will print 2 hours for a 96-minutes duration, 1 minute for durations between 0 and 60 seconds, and so on.
To get the difference in seconds, you can also use the org.joda.time.Seconds class:
long secs = Seconds.secondsBetween(startTimeDate, endTimeDate).getSeconds();
Java new Date/Time API
Joda-Time is in maintainance mode and is being replaced by the new APIs, so I don't recommend start a new project with it. Even in joda's website it says: "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).".
If you can't (or don't want to) migrate from Joda-Time to the new API, you can ignore this section.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java 6 or 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package 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.
First, to get the corresponding instant from an epoch milliseconds value, you can use the Instant class (no need to set timezone to UTC, as Instant represents an UTC instant). Then, to calculate the difference, you can use a Duration:
long startTimeDateInLong = // long millis value
long endTimeDateInLong = // long millis value
// get the corresponding Instant
Instant start = Instant.ofEpochMilli(startTimeDateInLong);
Instant end = Instant.ofEpochMilli(endTimeDateInLong);
// get the difference in seconds
Duration duration = Duration.between(start, end);
long secs = duration.getSeconds();
// perform the same calculations as above (with BigDecimal)
You can also use a ChronoUnit to get the difference in seconds:
long secs = ChronoUnit.SECONDS.between(start, end);
The only way I could find was to get the time in smaller unit first then convert to unit of desire and round it. So, for example, for the use case mentioned, the way to get rounded minutes would be something like this:
public Minutes getRoundedMinutes(DateTime dateTime1, DateTime dateTime2) {
return Minutes.minutes(
(int) round((double) secondsBetween(dateTime1, dateTime2).getSeconds() / Minutes.ONE.toStandardSeconds().getSeconds()));
}
#Test
public void should_round_minutes() throws Exception {
DateTime dateTime1 = new DateTime(2018, 1, 1, 1, 0, 0);
DateTime dateTime2 = new DateTime(2018, 1, 1, 1, 0, 29);
DateTime dateTime3 = new DateTime(2018, 1, 1, 1, 0, 30);
DateTime dateTime4 = new DateTime(2018, 1, 1, 1, 1, 1);
DateTime dateTime5 = new DateTime(2018, 1, 1, 1, 1, 31);
assertThat(getRoundedMinutes(dateTime1, dateTime2).getMinutes()).isEqualTo(0);
assertThat(getRoundedMinutes(dateTime1, dateTime3).getMinutes()).isEqualTo(1);
assertThat(getRoundedMinutes(dateTime1, dateTime4).getMinutes()).isEqualTo(1);
assertThat(getRoundedMinutes(dateTime1, dateTime5).getMinutes()).isEqualTo(2);
}
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.
Are there any Java libraries around for dealing with the win32 FILETIME/ time intervals ?
It's basically a 64 bit timestamp in 100ns intervals since January 1, 1601.
(For my particular needs, converting to/from java.util.Date or an appropriate joda time equivalent would do, although I'll need access to at least microsecond resolution - which neither seems to provide.)
If you are fine with millisecond resolution, this would work:
/** Difference between Filetime epoch and Unix epoch (in ms). */
private static final long FILETIME_EPOCH_DIFF = 11644473600000L;
/** One millisecond expressed in units of 100s of nanoseconds. */
private static final long FILETIME_ONE_MILLISECOND = 10 * 1000;
public static long filetimeToMillis(final long filetime) {
return (filetime / FILETIME_ONE_MILLISECOND) - FILETIME_EPOCH_DIFF;
}
public static long millisToFiletime(final long millis) {
return (millis + FILETIME_EPOCH_DIFF) * FILETIME_ONE_MILLISECOND;
}
At this point, converting from ms to a Date object is quite straightforward.
Here's a Java 8+ java.time based solution that keeps 100-nanosecond precision:
public static final Instant ZERO = Instant.parse("1601-01-01T00:00:00Z");
public static long fromInstant(Instant instant) {
Duration duration = Duration.between(ZERO, instant);
return duration.getSeconds() * 10_000_000 + duration.getNano() / 100;
}
public static Instant toInstant(long fileTime) {
Duration duration = Duration.of(fileTime / 10, ChronoUnit.MICROS).plus(fileTime % 10 * 100, ChronoUnit.NANOS);
return ZERO.plus(duration);
}
Last time I solved this using JNI... (Although not on Windows, this was unix)
That is, a piece of C++ code that called the native OS functions, and then called that code using Java Native Interface.
A bit clunky, but it was the only way I could find (Also needed the i-node).
EDIT: Assuming the values are already obtained from some other source, Date4J can handle seconds with 9 decimals, but it is not as feature rich as Joda.
I have...
Date start = new Date()
...
...
...
Date stop = new Date()
I'd like to get the years, months, days, hours, minutes and seconds ellapsed between these two dates.
--
I'll refine the question.
I just want to get the elapsed time, as an absolute measure, that is without taking into account leap years, the days of each month, etc.
Thus I think it's impossible to get the years and months elapsed, all I can get is days, hours, minutes and seconds.
More specifically I want to tell that a certain task lasted for e.g.
20 sec
13 min, 4 sec
2 h, 10 min, 2 sec
4 d, 4 h, 2 min, 2 sec
So please forgive my lack of precision.
I've just discovered this quick Groovy-sourced solution:
import groovy.time.TimeCategory
import groovy.time.TimeDuration
Date start = new Date()
// do something here
Date stop = new Date()
TimeDuration td = TimeCategory.minus( stop, start )
println td
You can do all of this with division and mod.
long l1 = start.getTime();
long l2 = stop.getTime();
long diff = l2 - l1;
long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;
long elapsedDays = diff / dayInMillis;
diff = diff % dayInMillis;
long elapsedHours = diff / hourInMillis;
diff = diff % hourInMillis;
long elapsedMinutes = diff / minuteInMillis;
diff = diff % minuteInMillis;
long elapsedSeconds = diff / secondInMillis;
That should give you all of the information you requested.
EDIT: Since people seem to be confused, no, this does not take things like leap years or daylight savings time switches into account. It is pure elapsed time, which is what opensas asked for.
Not so easy with the standard Date API.
You might want to look at Joda Time, or JSR-310 instead.
I'm not an expert in Joda, but I think the code would be:
Interval interval = new Interval(d1.getTime(), d2.getTime());
Period period = interval.toPeriod();
System.out.printf(
"%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n",
period.getYears(), period.getMonths(), period.getDays(),
period.getHours(), period.getMinutes(), period.getSeconds());
Regarding JodaTime I just got it going; thanks to the responder who suggested it. Here's a more condensed version of the Joda code suggested:
Period period = new Period(d1.getTime(), d2.getTime());
System.out.printf(
"%d years, %d months, %d days, %d hours, %d minutes, %d seconds%n",
period.getYears(), period.getMonths(), period.getDays(),
period.getHours(), period.getMinutes(), period.getSeconds());
(not sure if this is helping the original question but certainly searchers).
tl;dr
Duration.between( then , Instant.now() )
Using java.time
The modern way uses the java.time classes that supplant the troublesome old date-time classes.
Instead of Date, use Instant. The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant then = Instant.now();
…
Instant now = Instant.now();
Use the Duration class for a span of time unattached to the timeline, with resolution of day-hours-minutes-seconds-nanos.
Duration d = Duration.between( then , now );
For a span of time with resolution of years-months-days, use the Period class.
Generate a string is standard ISO 8601 format for durations: PnYnMnDTnHnMnS. The P marks the beginning. The T separates any years-months-days from hours-minutes-seconds. So two and a half hours is PT2H30M.
String output = d.toString();
In Java 9 and later, you can access the individual parts with methods toDaysPart, toHoursPart, and so on.
Also in Java 9 and later is an improvement to Instant.now where it captures the current moment in microseconds rather than the milliseconds seen in Java 8. Of course in all versions of Java the Instant class can hold a value in nanoseconds.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8 and SE 9 and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
Well since Java 1.5 you should use TimeUnit.
Here is a simple & plain example for this. I think in groovy it might get shorter(as always).
/**
* Formats a given {#link Date} to display a since-then timespan.
* #param created
* #return String with a format like "3 minutes ago"
*/
public static String getElapsedTime(Date created) {
long duration = System.currentTimeMillis() - created.getTime();
long seconds = TimeUnit.MILLISECONDS.toSeconds(duration);
long days = TimeUnit.MILLISECONDS.toDays(duration);
long hours = TimeUnit.MILLISECONDS.toHours(duration);
long minutes = TimeUnit.MILLISECONDS.toMinutes(duration);
if (days > 0) {
return days + " days";
}
if (hours > 0) {
return hours + " hrs";
}
if (minutes > 0) {
return minutes + " minutes";
}
return seconds + " seconds";
}
Oh and avoid multiple returns please ;)
Actually, regarding the above answers about Joda-Time.
There's an easier way to do this with Joda-Time’s Period class:
Period period = new Period(startDate, endDate);
System.out.println(PeriodFormat.getDefault().print(period));
To customize the output, look into the PeriodFormat, PeriodFormatter, and PeriodFormatterBuilder classes.
Hmm, if I get what you're asking, you want to know that if:
start = Jan 1, 2001, 10:00:00.000 am and
stop = Jan 6, 2003, 12:01:00.000 pm
you want an answer of 2 years, 0 months, 5 days, 2 hours, 1 minute
Unfortunately, this is a specious answer. What if the dates were Jan 2, and Jan 31? Would that be 29 days? Ok, but Feb 2 to Mar 2 is 28 (29) days, but would be listed as 1 month?
The length of time in anything other than seconds or possibly days is variable without knowing the context since months and years are of different lengths. The difference between 2 dates should be in static units, which are easily computable from stop.getTime() - start.getTime() (which is the difference in millisecs)
Apart from the aforementioned great JodaTime API which I do recommend, the best standard Java alternative you can have is the java.util.Calendar. It is cumbersome to work with it (this is an understatement .. look at the single-line JodaTime examples here), but you can calculate the elapsed time with it as well. Important key is that you should use the Calendar#add() in a loop to get the elapsed value for years, months and days to take leap days, years and centuries into account. You should not calculate them back from the (milli)seconds.
Here's a basic example:
import java.util.Calendar;
public class Test {
public static void main(String[] args) throws Exception {
Calendar start = Calendar.getInstance();
start.set(1978, 2, 26, 12, 35, 0); // Just an example.
Calendar end = Calendar.getInstance();
Integer[] elapsed = new Integer[6];
Calendar clone = (Calendar) start.clone(); // Otherwise changes are been reflected.
elapsed[0] = elapsed(clone, end, Calendar.YEAR);
clone.add(Calendar.YEAR, elapsed[0]);
elapsed[1] = elapsed(clone, end, Calendar.MONTH);
clone.add(Calendar.MONTH, elapsed[1]);
elapsed[2] = elapsed(clone, end, Calendar.DATE);
clone.add(Calendar.DATE, elapsed[2]);
elapsed[3] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 3600000;
clone.add(Calendar.HOUR, elapsed[3]);
elapsed[4] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 60000;
clone.add(Calendar.MINUTE, elapsed[4]);
elapsed[5] = (int) (end.getTimeInMillis() - clone.getTimeInMillis()) / 1000;
System.out.format("%d years, %d months, %d days, %d hours, %d minutes, %d seconds", elapsed);
}
private static int elapsed(Calendar before, Calendar after, int field) {
Calendar clone = (Calendar) before.clone(); // Otherwise changes are been reflected.
int elapsed = -1;
while (!clone.after(after)) {
clone.add(field, 1);
elapsed++;
}
return elapsed;
}
}
It should print my age as of now =)
Oh, I should add, you can "convert" Date to Calendar using Calendar#setTime().
import groovy.time.TimeCategory
import groovy.time.TimeDuration
time = { closure ->
use(TimeCategory) {
def started = new Date()
def res = closure()
TimeDuration duration = new Date() - started
logger.info("Execution duration: " + duration.toMilliseconds() + "ms")
res
}
}
time {
println 'A realy heavy operation here that you want to measure haha'
}
It's easy; You should set the right timezone
import java.util.TimeZone;
import java.util.logging.Logger;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class ImportData {
private final static Logger log = Logger.getLogger(ImportData.class.getName());
private final static DateTimeFormatter dtf = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss.SSS");
private final static DateTimeFormatter dtfh = DateTimeFormat.forPattern("HH:mm:ss.SSS");
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws Exception {
TimeZone.setDefault(TimeZone.getTimeZone("Europe/Berlin"));
DateTimeZone.setDefault(DateTimeZone.forID("Europe/Berlin"));
// Quotes connection=Quotes.getInstance();
final long start = System.currentTimeMillis();
// do something here ...
// connection.importTickdata();
Thread.currentThread().sleep(2000);
final long end = System.currentTimeMillis();
log.info("[start] " + dtf.print(start));
log.info("[end] " + dtf.print(end));
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
DateTimeZone.setDefault(DateTimeZone.forID("UTC"));
log.info("[duration] " + dtfh.print(end - start));
// connection.logOff();
// System.exit(0);
}
returns:
10.11.2010 00:08:12 ImportData main
INFO: [start] 2010-11-10 00:08:10.306
10.11.2010 00:08:12 ImportData main
INFO: [end] 2010-11-10 00:08:12.318
10.11.2010 00:08:12 ImportData main
INFO: [duration] 00:00:02.012
I do this in general:
def start_time = System.currentTimeMillis()
...
def end_time = System.currentTimeMillis()
println (end_time - start_time) +' ms'
Then you can break that into any time unit that you want using the Duration Groovy class http://docs.groovy-lang.org/latest/html/api/groovy/time/Duration.html.
There is no point creating a Date object as all this does is wrap System.currentTimeMillis(). The getTime() function just unwraps the Date object. I suggest you just use this function to obtain a long.
If you only need second accuracy, this is fine. However if you want sub-millisecond accuracy use System.nanoTime() to get the elapse time.
This is a complete function I implemented based on Sebastian Celis answer. And again, from his post - this does not take things like leap years or daylight savings time switches into account. It is pure elapsed time.
The output is tailored towards my need. This only outputs three significant sections. Instead of returning
4 months, 2 weeks, 3 days, 7 hours, 28 minutes, 43 seconds
It just returns first 3 block (see more sample run at the end of post):
4 months, 2 weeks, 3 days
Here is the complete method source code:
/**
* Format milliseconds to elapsed time format
*
* #param time difference in milliseconds
* #return Human readable string representation - eg. 2 days, 14 hours, 5 minutes
*/
public static String formatTimeElapsedSinceMillisecond(long milisDiff) {
if(milisDiff<1000){ return "0 second";}
String formattedTime = "";
long secondInMillis = 1000;
long minuteInMillis = secondInMillis * 60;
long hourInMillis = minuteInMillis * 60;
long dayInMillis = hourInMillis * 24;
long weekInMillis = dayInMillis * 7;
long monthInMillis = dayInMillis * 30;
int timeElapsed[] = new int[6];
// Define time units - plural cases are handled inside loop
String timeElapsedText[] = {"second", "minute", "hour", "day", "week", "month"};
timeElapsed[5] = (int) (milisDiff / monthInMillis); // months
milisDiff = milisDiff % monthInMillis;
timeElapsed[4] = (int) (milisDiff / weekInMillis); // weeks
milisDiff = milisDiff % weekInMillis;
timeElapsed[3] = (int) (milisDiff / dayInMillis); // days
milisDiff = milisDiff % dayInMillis;
timeElapsed[2] = (int) (milisDiff / hourInMillis); // hours
milisDiff = milisDiff % hourInMillis;
timeElapsed[1] = (int) (milisDiff / minuteInMillis); // minutes
milisDiff = milisDiff % minuteInMillis;
timeElapsed[0] = (int) (milisDiff / secondInMillis); // seconds
// Only adds 3 significant high valued units
for(int i=(timeElapsed.length-1), j=0; i>=0 && j<3; i--){
// loop from high to low time unit
if(timeElapsed[i] > 0){
formattedTime += ((j>0)? ", " :"")
+ timeElapsed[i]
+ " " + timeElapsedText[i]
+ ( (timeElapsed[i]>1)? "s" : "" );
++j;
}
} // end for - build string
return formattedTime;
} // end of formatTimeElapsedSinceMillisecond utility method
Here are some sample test statement:
System.out.println(formatTimeElapsedSinceMillisecond(21432424234L));
// Output: 8 months, 1 week, 1 day
System.out.println(formatTimeElapsedSinceMillisecond(87724294L));
// Output: 1 day, 22 minutes, 4 seconds
System.out.println(formatTimeElapsedSinceMillisecond(123434L));
// Output: 2 minutes, 3 seconds
This is another similar function, It won't show up days, hours, minutes, etc. if its not needed change its literals if needed.
public class ElapsedTime {
public static void main(String args[]) {
long start = System.currentTimeMillis();
start -= (24 * 60 * 60 * 1000 * 2);
start -= (60 * 60 * 1000 * 2);
start -= (60 * 1000 * 3);
start -= (1000 * 55);
start -= 666;
long end = System.currentTimeMillis();
System.out.println(elapsedTime(start, end));
}
public static String elapsedTime(long start, long end) {
String auxRet = "";
long aux = end - start;
long days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0;
// days
if (aux > 24 * 60 * 60 * 1000) {
days = aux / (24 * 60 * 60 * 1000);
}
aux = aux % (24 * 60 * 60 * 1000);
// hours
if (aux > 60 * 60 * 1000) {
hours = aux / (60 * 60 * 1000);
}
aux = aux % (60 * 60 * 1000);
// minutes
if (aux > 60 * 1000) {
minutes = aux / (60 * 1000);
}
aux = aux % (60 * 1000);
// seconds
if (aux > 1000) {
seconds = aux / (1000);
}
milliseconds = aux % 1000;
if (days > 0) {
auxRet = days + " days ";
}
if (days != 0 || hours > 0) {
auxRet += hours + " hours ";
}
if (days != 0 || hours != 0 || minutes > 0) {
auxRet += minutes + " minutes ";
}
if (days != 0 || hours != 0 || minutes != 0 || seconds > 0) {
auxRet += seconds + " seconds ";
}
auxRet += milliseconds + " milliseconds ";
return auxRet;
}
}
This is a problem and an algorithm needs to be made to account for leap years and exact amount of months and days beside years. Interesting how it is simple if only one unit of measure is to be used. For example, total number of days between two days is correct as apposed to reminder number of days after number of months and years is calculate within let's say two decades.
I am currently working on this to provide it from my PML implementation, for example, in the form of:
unemployed <- date.difference[
From = 2009-07-01,
Till = now,
YEARS, MONTHS, DAYS
]: yyyy-MM-dd
$$-> *unemployed -> date.translate[ YEARS, MONTHS, DAYS ] -> print["Unemployed for:", .]
Of course, this would also be useful and required for exact interest rate calculations.