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.
Related
So i'm trying to implement a sort of day-night cycle in my game, and I'm using System.nanotime() to get the approximate time passed between frames, the problem is that it sometimes jumps huge amounts of time
Using lwjgl, and calling Timer.update() before swapBuffers with vsync enabled should be around 16.6ms increase to the current time each loop shouldnt it? Yet it can be much much higher than that with no actual slowdown for rendering
Here's the code : Time class
public class Time
{
public static final long SECOND = 1000000000L;
private static long lastTime;
public static long getTime()
{
return System.nanoTime();
}
public static double getDelta()
{
return (double)(getTime() - lastTime) / SECOND;
}
public static void update()
{
Time.lastTime = Time.getTime();
}
}
Update method
while ( !glfwWindowShouldClose(window) )
{
input();
update();
render();
}
public void update()
{
//System.out.println("Time since last update " + Time.getDelta());
Time.update();
}
And where i'm using the delta time :
if ((timeOfDay + Time.getDelta()) < timeDayTotal)
timeOfDay += Time.getDelta();
else
timeOfDay += Time.getDelta() - timeDayTotal;
System.out.println("Time of day " + timeOfDay);
Ignoring the fact that the precision seems to be waaaay off for now, here's some sample output
Time of day 0.0077873133
Time of day 0.0077988105
Time of day 0.0078120963
Time of day 0.007860638
Time of day 0.015185255
Time of day 0.01879608
Time of day 0.01880809
Time of day 0.018820863
Time of day 0.018835938
Time of day 0.018851267
It seems to mostly increment the correct amount (by a factor of 10^-4, but close enough, thats not the problem), but then it has these massive jumps up that I can't explain
So finally, a) whats the problem with system.nanoTime and b) is there a fix or viable replacement?
Edit : Switched to currentTimeMillis(), the precision is gone which is no big deal, but the jumps are still there
Time of day 0.03
Time of day 0.03
Time of day 0.03
Time of day 0.03
Time of day 0.06
Time of day 0.06
Time of day 0.06
Time of day 0.06
In general, do not use System.nanoTime() in any program which you don’t plan to strongly control how it is run, and the environment it is run in.
..
The problem lies in the RDTSC instruction which retrieves the number of CPU ticks since the CPU started. On multi-core systems, each core will have its own tick count, and they will not match, so every time your process switches CPUs, you get a different measurement. The issue is compounded by the fact that some power management systems actually alter the CPU’s frequency to save power, which breaks the functionality even on single core, single CPU systems.
From here
From the code you posted, it looks like you update() the Time on each frame before rendering, so then when you use getDelta() you only measure the time it took to get there, rather than the whole frame time?
I think it should look more like this:
public class Time
{
public static final long SECOND = 1000000000L;
public static final double timeDayTotal = 100.0; // ?
private static final long start = System.nanoTime();
private static double timeOfDay;
public static void update() {
long now = System.nanoTime();
timeOfDay = (now - start) / (double)SECOND % timeDayTotal;
}
public static double getTimeOfDay()
{
return timeOfDay;
}
}
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 am timing an event like this:
seconds = System.currentTimeMillis() / 1000;
// Something happens here
time = System.currentTimeMillis() / 1000 - seconds;
and then I have attempted to format it:
String Time = String.format("%d min, %d sec",
TimeUnit.MILLISECONDS.toMinutes(time),
TimeUnit.MILLISECONDS.toSeconds(time) -
TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(time)));
and the results don't make any sense, the minutes are thousands but the seconds seem to be normal numbers. What is the proper way to format the time?
long milliseconds = System.currentTimeMillis()%1000;
long seconds = (System.currentTimeMillis()/1000)%60;
long minutes = (System.currentTimeMillis()/(60*1000))%60;
long hours = (System.currentTimeMillis()/(60*60*1000));
Leave out whatever parts you don't want and remove the modulus from the highest one you do.
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);
I'm wanting to have my JLabel display values in the format of HH:mm:ss without making use of any external libraries. (the label will update every second)
So for example, the following input in seconds and the desired output are below:
Seconds: Output:
--------------------------------------------------
long seconds = 0 00:00:00
long seconds = 5 00:00:05
long seconds = 500 00:08:20
long seconds = 5000 01:23:20
Note: the seconds value is of type long
I'm aware that typically one would just do the following conversions to get the desired numbers:
long s = 5000; //total seconds
long hrs = (s / 3600) //hours
long mins = ((s%3600)/60) //minutes
long secs = (s%60) //seconds
However, this leaves decimals on the values. Perhaps there is some sort of formatting that will allow me to toss the un-needed decimals.
Options I have come across were String.format(), SimpleDateFormat(), or concatenating a string myself.
The thing is, I will be updating this JLabel every second and sometimes it can count to the equivalent of 5-6 days if not longer.
So I'm looking for someone who has more experience in the area than I, and knows the most efficient way to tackle this issue.
I would use SimpleDateFormat if I were you.
If SDF is too slow for you, profile all your options and pick the fastest one, then refactor the rest of your code until it's fast enough.
Remember that premature optimization is the root of all evil, and that you should only really do any optimizing after you've profiled your code and missed your target execution time.
SimpleDateFormat() is really quite appropriate for your needs.
Use the TimeUnit class, as shown here in combination with the javax.swing.Timer class set to execute at 1 second intervals.
If you don't mind values wrapping then use SimpleDateFormat as follows. Remember x1000 to convert to milliseconds and to manually override the timezone.
long value = 5 * 24 * 3600 + 5000;
// wrapping solution
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
// ensure no daylight saving +1 hour
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
System.out.println(sdf.format(value * 1000));
Output
01:23:20
If you want the hours to go past 23.59.59 then this is the simplest I could come up with. I used DecimalFormat to force at least 2 digits for the hours.
long value = 5 * 24 * 3600 + 5000;
long hours = value / 3600; // whole hours
long mins = value / 60 - hours * 60;
long secs = value % 60;
System.out.println(String.format("%s:%2d:%2d",
new DecimalFormat("00").format(hours), mins, secs));
Output
121:23:20
I've found this to be extremely fast. Try it out. Seconds go from 0 - 59, minutes go from 0 - 59, hours go from 0 - 2,562,047,788,015. Afterwards the hours become negative and begin going towards that maximum.
performing the "+" operator on Strings is very slow. A StringBuilder performs grouping strings together the fastest from what I've seen. You should also be using "chars" not "String/Byte" Bytes are very slow as well. I'd prefer doing only multiplication however dividing by 36 and 6 give decimals that are to large for holding.
StringBuilder sb = new StringBuilder(8);
long hours = time / 3600000;
long minutes = (time - hours * 3600000) / 60000;
long seconds = (time - hours * 3600000 - minutes * 60000) / 1000;
if (hours < 10)
sb.append('0');
sb.append(hours);
sb.append(':');
if (minutes < 10)
sb.append('0');
sb.append(minutes);
sb.append(':');
if (seconds < 10)
sb.append('0');
sb.append(seconds);
String formattedTime = sb.toString();
.....
If you don't want to use a formatter class, you can get your work done by using basic operations like conversion among wrapper classes and String operations. Take a look at this code:
long h, m, s; // Initialize them after calculation.
String h1, m1, s1;
h1 = Long.toString( h );
m1 = Long.toString( m );
s1 = Long.toString( s );
if ( s1.length() < 2 )
s1 = "0" + s1;
if ( m1.length() < 2 )
m1 = "0" + m1;
if ( h1.length() < 2 )
h1 = "0" + h1;
String output = h1+":"+m1+":"+s1;
Supposing you have correctly calculated values of seconds, minutes and hours, you can gather String versions of these variables, then format them with a simple length check and finally concatenate these time unit parts.
i think you want to do the math you indicated, but take the floor of each value. then concatenate..
public class Test{
public static void main(String args[]){
double d = -100.675;
float f = -90;
System.out.println(Math.floor(d));
System.out.println(Math.floor(f));
System.out.println(Math.ceil(d));
System.out.println(Math.ceil(f));
}
}