I want to pass around a time number and the TimeUnit it is in.
long number = some number;
TimeUnit timeUnit = some arbitrary time unit
What can hold both the time and timeUnit in one Object from the Java libraries?
There is no Java library object that encapsulates a number and an arbitrary TimeUnit. However, there is one in Java 8 that converts itself into whatever time unit is required:
java.time.Duration
Duration stores the provided quantity and then provides comparison and conversion to all other time units. For example:
// Create duration from nano time
Duration systemTime = Duration.ofNanos(System.nanoTime());
// Create duration from millis time
Duration systemTime = Duration.ofMillis(System.currentTimeMillis());
Of course, if doing addition and subtraction or other math operations, the precision is only as good as the precision of the current operation and the supplied Duration.
/**
* Example that tells if something has reached the required age
* TRUE IF THE current system time is older or equal to the required system time
*/
// TRUE IF THE FILE HAS NOT WAITED ENOUGH TIME AFTER LAST CREATE/MODIFY
private boolean isMature() {
// it is not known whether required age is nanos or millis
Duration requiredAge = systemTimeWhenMature();
// so create a duration in whatever time unit you have
// more precise = possibly better here
Duration actualAge = Duration.ofNanos(System.nanoTime());
// if ON or OLDER THAN REQUIRED AGE
// actualAge - requiredAge = balance
// 20 - 21 = -1 (NOT MATURE)
// 21 - 21 = 0 (OK)
// 22 - 21 = 1 (OK)
Duration balance = actualAge.minus(requiredAge);
if (balance.isNegative()) {
logger.info("Something not yet expired. Expires in {} millis.", balance.negated());
return false;
} else {
return true;
}
}
And there are many more methods in Duration that are useful for converting and processing the stored quantity in various unit.
It is important to understand how the precision will affect calculations. This shows the
general precision contract by example:
// PICK A NUMBER THAT IS NOT THE SAME WHEN CONVERTED TO A LESSER PRECISION
long timeNanos = 1234567891011121314L;
long timeMillis = TimeUnit.MILLISECONDS.convert(timeNanos, TimeUnit.NANOSECONDS);
// create from milliseconds
Duration millisAccurate = Duration.ofMillis(timeMillis);
Duration nanosAccurate = Duration.ofNanos(timeNanos);
// false because of precision difference
assertFalse(timeMillis == timeNanos);
assertFalse(millisAccurate.equals(nanosAccurate));
// true because same logical precision conversion takes place
assertTrue(timeMillis - timeNanos <= 0);
assertTrue(millisAccurate.minus(nanosAccurate).isNegative());
// timeNanos has greater precision and therefore is > timeMillie
assertTrue(timeNanos - timeMillis > 0);
assertTrue(nanosAccurate.minus(millisAccurate).negated().isNegative());
In a nutshell .. I cannot believe it took me this long to find Duration!
:)
TimeUnit is just enum holding some time unit types like Second, Milliseconds, ...
TimeUnit is NOT for holding time BUT you can convert a time in a unit to another unit using TimeUnit API.
I think you have to create your object to hold time and its unit.
If you use Java 8. You can work with some new Date API
http://download.java.net/jdk8/docs/api/java/time/package-summary.html
In Joda-Time there is an Interval, but you'll need to create a Java Bean (perhaps calling it Interval) if you want to use only JRE inclusive Object types.
Related
I have many time stamps showing at which time a user entered the room. I want to calculate an average time. The problem occurs when some action happens at night.
I tried to calculate it with milis, but it is wrong.
ArrayList<String> times = new ArrayList<String>();
times.add("00:20:01");
times.add("00:00:01");
times.add("23:40:01");
times.add("23:20:01");
times.add("23:20:01");
times.add("00:20:01");
times.add("23:40:01");
times.add("23:40:01");
times.add("00:00:01");
long commonMillis=0;
for (String date:times){
LocalTime time = new LocalTime(date);
long dayMilis = time.getMillisOfDay();
commonMillis = commonMillis + dayMilis;
}
LocalTime average = new LocalTime(commonMillis/times.size());
This code, for example, returns the value 14:08:54.333. Because the hours 00:00 and 23:00 -- calculated in millis -- are too far from each other.
Please help me to find right way to calculate the average time?
Three things:
You have to define an offset time:
If you want an average of times of different days without knowing the day, you have to define an offset time by yourself. This time is used to decide whether a time is belonging to the next day or not.
This offset time may be derived depending on the values you get.
Without an offset time, you implicitely use 0 o'clock.
Avoid overflows:
If your times list gets longer, you may run into an overflow if a long field is not sufficient to store the accumulated value. You can use a data structure which is overflow resistant like BigInteger or use the (culmulative) moving average approach.
Wrong result constructor:
The constructor LocalTime(long instant) implicitely uses your local DateTimeZone to calculate a local time from an Instant. This causes different times when using the same code between different time zones.
The method you want to use is LocalTime#fromMillisOfDay.
Here is an approach considering the above points:
long movingAverage = 0;
// 1. define offset
LocalTime offset = new LocalTime("12:00:00");
long offsetMillis = offset.getMillisOfDay();
for (String date : times) {
long sampleMillis = new LocalTime(date).getMillisOfDay();
// align to offset
if (sampleMillis < offsetMillis)
sampleMillis += DateTimeConstants.MILLIS_PER_DAY;
long diff = sampleMillis - offsetMillis;
// 2. use moving average
movingAverage = movingAverage + diff / times.size();
}
// 3. avoid LocalTime(long) constructor
LocalTime result = offset.plusMillis((int) movingAverage);
System.out.println(result); // 23:48:54.329
A naive approach would be to gather the long millisecond values in all the dates, add them up and divide them by the number of dates, transforming them back into a LocalDate. You probably need a BigInteger to hold the sum, though.
I have code which checks if the given "A" time (in milliseconds) is in the given "b" time period.
private static boolean isInTimeInterval(long time, int timePeriod) {
long curTime = Calendar.getInstance().getTimeInMillis();
// time period is in hours, 1 hour is 3600000 ms;
long startTime = curTime - timePeriod * 3600000;
if (time >= startTime && time < curTime){
return true;
}
return false;
}
I take the time from a file and parse it into a long like this:
(Long.parseLong(array[2]))
But it doesn't work correctly, what is wrong ?
To simplify things, I would suggest that you first subtract the start time from the end time, check to see if that is positive and then decide if the remaining milliseconds is smaller than the requested time period.
long difference = Calendar.getInstance().getTimeInMillis() - time;
long timeRange = timePeriod * 3600000;
return (0 <= difference && differance <= timeRange);
It makes the code slightly smaller in lines, but more importantly, it simplifies the math to where you know the code isn't the problem.
As far as the errors you are likely encountering, I'd look to your
Long.parseLong(array[2])
As that is likely grabbing the input in a manner you aren't expecting. For starters, I'd put in some logging or at least one-time println debugging statements to verify the input times are what I thought they were.
How to generate a random value bigger than value of System.currentTimeInMillis(). I use Random object.how can I obtain a value that have min range as System.currentTimeInMillis()?
Doesn't
long value = System.currentTimeMillis() + (long)random.nextInt(range);
work?
If you want to enforce a value that is strictly larger than System.currentTimeMillis() add an additional 1 to it. Set the range accordingly to prevent overflow (see assylias's comment).
Edited according to comments.
This is an approach if you want to be able to get numbers distributed across the entire range System.currentTimeMillis()..Long.MAX_VALUE:
long millis = System.currentTimeMillis();
long l = Math.min(Long.MAX_VALUE - millis, Math.abs(random.nextLong())) + millis;
Long.MAX_VALUE will be much more common than other results here though, in case that matters.
For a uniform distribution of times between currentTimeMillis and Long.MAX_VALUE, without overflow, you can use:
long time = System.currentTimeMillis();
long randomFutureTime = Math.abs(random.nextLong()) % (Long.MAX_VALUE - time) + time;
This may is useful to have real time of object creation, and two objects cannot have the same timestamp, so you can order them.
I use as UUID for my objects :
Const.DECAL_BIT = 20;
Const.DECAL_BIT_MASQUE = (Long.size() -1) - next 20;
private final Long timeCreate = (System.currentTimeMillis() << Const.DECAL_BIT)
+ (System.nanoTime() & Const.DECAL_BIT_MASQUE);
So you can have valid dates for 100 years : you multiply by 1M the internal datetime and had one second elapse time in nanosecond precision.
To read the date : Date d = Date((Long) timeCreate>> Const.DECAL_BIT);
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.
This question already has answers here:
How do I time a method's execution in Java?
(42 answers)
Closed 4 years ago.
What's a simple/easy way to access the system clock using Java, so that I can calculate the elapsed time of an event?
I would avoid using System.currentTimeMillis() for measuring elapsed time. currentTimeMillis() returns the 'wall-clock' time, which may change (eg: daylight savings, admin user changing the clock) and skew your interval measurements.
System.nanoTime(), on the other hand, returns the number of nanoseconds since 'some reference point' (eg, JVM start up), and would therefore not be susceptible to system clock changes.
This is some sample code.
long startTime = System.currentTimeMillis();
// Run some code;
long stopTime = System.currentTimeMillis();
System.out.println("Elapsed time was " + (stopTime - startTime) + " miliseconds.");
Apache Commons-Lang also has the StopWatch class suited just for your purpose. It uses System.currentTimeMillis(), so you'll still have resolution problems, but you can pause and do lap times and such. I use it as standard now for event stats.
http://commons.apache.org/lang/api-release/org/apache/commons/lang/time/StopWatch.html
The Answer by Leigh is correct.
java.time
Java 8 and later has the java.time framework built in.
An Instant is a moment on the timeline in UTC with nanosecond resolution (up to 9 digits of a decimal fraction of a second). The now method grabs the current date-time moment.
Instant now = Instant.now();
2016-03-12T04:29:39.123Z
You can calculate the elapsed time between a pair of Instant objects as a Duration. The duration uses nanosecond resolution with a maximum value of the seconds that can be held in a long. This is greater than the current estimated age of the universe.
Duration duration = Duration.between( startInstant , stopInstant );
The default output of Duration::toString is in standard ISO 8601 format. You can also ask for a total count of nanoseconds (toNanos) or milliseconds (toMillis), as well as other amounts.
Java 8
In Java 8, fetching the current moment resolves only to millisecond resolution (up to 3 digits of a decimal fraction of a second). So while the java.time classes can store nanoseconds they can only determine the current moment with milliseconds. This limitation is due to a legacy issue (the default Clock implementation uses System.currentTimeMillis()).
Java 9
In Java 9 and later, the default Clock implementation can determine the current moment in up to nanosecond resolution. Actually doing so depends on the fineness of your computer’s clock hardware.
See this OpenJDK issue page for more info: Increase the precision of the implementation of java.time.Clock.systemUTC()
Micro Benchmark
If your purpose is benchmarking, be sure to look at other Questions such as:
How do I write a correct micro-benchmark in Java?
Create quick/reliable benchmark with java?
Frameworks are available to assist with short-duration benchmarking.
java.lang.System.currentTimeMillis() or java.lang.System.nanoTime() ought to work to measure elapsed time.
Here is a small StopWatch class I wrote using the System.nanoTime() as suggested in the answer from Leigh:
public class StopWatch {
// Constructor
public StopWatch() {
}
// Public API
public void start() {
if (!_isRunning) {
_startTime = System.nanoTime();
_isRunning = true;
}
}
public void stop() {
if (_isRunning) {
_elapsedTime += System.nanoTime() - _startTime;
_isRunning = false;
}
}
public void reset() {
_elapsedTime = 0;
if (_isRunning) {
_startTime = System.nanoTime();
}
}
public boolean isRunning() {
return _isRunning;
}
public long getElapsedTimeNanos() {
if (_isRunning) {
return System.nanoTime() - _startTime;
}
return _elapsedTime;
}
public long getElapsedTimeMillis() {
return getElapsedTimeNanos() / 1000000L;
}
// Private Members
private boolean _isRunning = false;
private long _startTime = 0;
private long _elapsedTime = 0;
}