Generate random time within a range of two times with condition - java

I'm trying to generate 10 random times within a range of two times, and there is a condition that the times generated cannot have less than 30 minutes between them. So, if i Start at 10:00am and end at 05:00pm, the times between these must be a least 30 minutes between them.
I already can get the random times, but don't know how to put the condition there, any ideas?
public LocalTime between(LocalTime startTime, LocalTime endTime) {
int startSeconds = startTime.toSecondOfDay();
int endSeconds = endTime.toSecondOfDay();
int randomTime = ThreadLocalRandom
.current()
.nextInt(startSeconds, endSeconds);
return LocalTime.ofSecondOfDay(randomTime);
}
i put this in a for loop to get 10 of them

For a good random distribution: Out of the 7 hours between your start of 10:00 and your end of 17:00 (on a 24 hour clock, “military hours”), 4 hours 30 minutes are already reserved for your minimal gaps (9 gaps # 30 minutes minimum). So subtract 4:30 from 7, this gives 2 hours 30 minutes of freedom.
Generate 10 random times within 2 hours 30 minutes, for example the way you already do.
Sort them chronologically.
Add 0 minutes to the first time, 30 minutes to the next, 1 hour to the third, etc. So you will be adding 4 hours 30 minutes to the last time. This will make sure that the gaps become at least 30 minutes each and that the last time is still within the 17:00 end time.

You can use isBefore in LocalTime, so check startTime+30 Min is before result and result is before endTime-30 Min
LocalTime result = LocalTime.ofSecondOfDay(randomTime);
if (startTime.plusMinutes(30).isBefore(result) && result.isBefore(endTime.minusMinutes(30))) {
return result;
}
Probably you can use while loop to loop until it get the valid result
while(true) {
LocalTime result = LocalTime.ofSecondOfDay(ThreadLocalRandom. current().nextInt(startSeconds, endSeconds));
if (startTime.plusMinutes(30).isBefore(result) && result.isBefore(endTime.minusMinutes(30))) {
return result;
}
}

You can not generate truly random numbers with computers, you always have to have some strategy. And if your numbers are truly random then, they can not be aware of each other. So, you can not generate truly random time 30 minutes apart separately. You have to generate them all together. You have to find a minimum distance. And start time and end time must have enough distance to generate the number of random times you want.
You can generate any number of random times by the following method in any given range if they have enough distance -
public List<LocalTime> generateRandomTimes(LocalTime startTime, LocalTime endTime, int n) {
if (n < 0) {
throw new RuntimeException("Must be greater than zero");
}
List<LocalTime> localTimeList = new ArrayList<>();
int startSeconds = startTime.toSecondOfDay();
int endSeconds = endTime.toSecondOfDay();
int minimumDistance = LocalTime.of(0, 30).toSecondOfDay();
int standardDistance = (endSeconds - startSeconds) / n;
if (standardDistance <= minimumDistance) {
throw new RuntimeException("Not enough time distance to generate the required number of random times");
}
int randomRange = (endSeconds - (n * minimumDistance)) / n;
for (int i = 1; i <= 10; i++) {
int nextInt = ThreadLocalRandom
.current()
.nextInt(startSeconds, startSeconds + randomRange);
LocalTime time = LocalTime.ofSecondOfDay(nextInt);
localTimeList.add(time);
startSeconds = nextInt + minimumDistance;
}
return localTimeList;
}

Related

How can I turn an int (minutes) into a Duration in java?

I'm trying to compare a duration to an integer representing minutes (so another duration) in order to find out if it's a longer or shorter time. I'm trying to use compareTo(Duration duration) method but I can't use an int as parameter. How would I transform that int (minutes) into Duration?
You can create a duration in minutes with the ofMinutes static method. So, as a silly example
int compareDurations(Duration d) {
int myMinutes = 5;
Duration durationInMinutes = Duration.ofMinutes(myMinutes);
return d.compareTo(durationMinutes);
}
I always find code involving compareTo() hard to read. Therefore for most purposes I would prefer to do it the other way around: convert your Duration to minutes and compare using plain < or >.
int minutes = 7;
Duration dur = Duration.ofMinutes(7).plusSeconds(30);
if (minutes > dur.toMinutes()) {
System.out.println("The minutes are longer");
} else {
System.out.println("The minutes are shorter or the same");
}
Output:
The minutes are shorter or the same
If you need to know whether the minutes are strictly shorter, the code will be a bit longer, of course (no joke intended). One way does involve converting the minutes to a Duration in some cases:
if (minutes > dur.toMinutes()) {
System.out.println("The minutes are longer");
} else if (Duration.ofMinutes(minutes).equals(dur)) {
System.out.println("The minutes are the same");
} else {
System.out.println("The minutes are shorter");
}
The minutes are shorter
I really wish the Duration class had had methods isLonger() and isShorter() (even though the names just suggested may not be quite clear when it comes to negative durations). Then I would have recommended converting the minutes to a Duration too as in the accepted answer.
One way, with Duration:
Duration duration = Duration.of(10, ChronoUnit.SECONDS);
int seconds = 5;
System.out.println(duration.getSeconds() - seconds);
Note, that ChronoUnit has a lot of useful constant members, like MINUTES, DAYS, WEEKS, CENTURIES, etc.
Another way, with LocalTime:
LocalTime localTime = LocalTime.of(0, 0, 15); //hh-mm-ss
int seconds = 5;
System.out.println(localTime.getSecond() - seconds);

Time Difference separating the times

Complete timeDifference that takes two different times and returns a
string with the difference in hours and minutes, separated by ":".
The int argument 0 represents midnight, 700 is 7:00 a.m., 1314 is 14
minutes past 1:00pm, and 2200 is 10 pm.
Leading zeros required
I know the problem requires you to convert both times to minutes, however I don't know how to separate the integers that are four characters long so I can differ between hours and minutes.
Sice your question is on the separation part only, this will do the trick:
int timeDifference(int a, int b)
{
int minsA = a % 100); //remainder
int hrsA = (a / 100);
.....
}
Edit: if you want to get the full time just in minutes you can do:
int fullMinsA = minsA + hrsA*60;

Loss of precision - Java

Problem Statement:
Write a method whatTime, which takes an int, seconds, representing the number of seconds since midnight on some day, and returns a String formatted as "::". Here, represents the number of complete hours since midnight, represents the number of complete minutes since the last complete hour ended, and represents the number of seconds since the last complete minute ended. Each of , , and should be an integer, with no extra leading 0's. Thus, if seconds is 0, you should return "0:0:0", while if seconds is 3661, you should return "1:1:1"
My Algorithm:
Here is how my algorithm is supposed to work for the input 3661:
3661/3600 = 1.016944 -> This means the number of hours is 1
Subtract the total number of hours elapsed i.e. 1.016944-1=0.016944
Multiply this with 60 i.e. 0.016944*60=1.016666 -> The number of minutes elapsed is equal to 1
Subtract the total number of minutes elapsed i.e. 1.01666-1=0.01666. Multiply this with 60. This would yield the number of seconds elapsed.
The output produced however is 1:1:0. I tried to use a print statement and it appears that the value of 'answer3' variable is 0.999 and that is why prints the integer part (0). I tried to use the Math.ceil() function to round up the value and it produces a correct output. However I can only score about 60/250 points when I submit my code (TopCoder SRM 144 Div2) . Any insight for improving the algorithm will be helpful.
public class Time
{
public String whatTime(int seconds)
{
double answer1,answer2,answer3; int H;
answer1=(double)seconds/3600;
H=(int)answer1;
answer2=(double)((answer1-H)*60);
int M=(int)answer2;
answer3=answer2-M;
answer3=(double)answer3*60;
int S=(int)answer3;
String answer=Integer.toString(H);
answer=Integer.toString(H)+":"+Integer.toString(M)+":"+Integer.toString(S);
return answer;
}
}
public String whatTime(int seconds) {
int secondVal = seconds % 60;
int minutes = seconds / 60;
int minuteVal = minutes % 60;
int hours = minutes / 60;
int hourVal = hours % 24;
int daysVal = hours / 24;
String answer = "" + daysVal + ":" + hourVal + ":" + minuteVal + ":" + secondVal;
return answer;
}
Could do the formatting more elegantly, but that's the basic idea.
Avoid floating point values, and work entirely with ints or longs.
You could solve this by working with ints :
3661/3600 = 1.016944 -> This means the number of hours is 1
Subtract the number of hours * 3600 - i.e. 3661-(1*3600) = 61
61/60 = 1.0166666 -> The number of minutes elapsed is equal to 1
Subtract the number of minutes * 60 i.e. 61-(1*60)=1. This yields the number of seconds elapsed.

Set the start of the task according to freqency and start of server

I have a frequency and a time range with which the frequency has to be executed.
For eg, if the current time is 2AM and frequency is 360 mins, it has to assume that
since it just passed midnight , the task should execute at 360 mins after 12 means 6 AM
the current time is server start time from midnight.
so if server starts at 5AM and frequncy is 360 the task should be run at 6AM
but if the task is 5am and frequency is 240, since it has already passed 240 mins from midnight
the next run should be at 8AM
If the server starts at 10AM and frequency is 300 then starting from midnight one run is elapsed at 5AM ans next as calculated at 10AM so will start immediately at 10AM
The time ranges are divded into 4 quarters, 12AM to 6AM to 12PM ,12PM to 6PM and 6PM to 12AM next day
This is the code below which is working fine for 240 and 360 frequency but going wrong when its 60 frequency.
Some values which are provided below:
stNow----serverTime
sElapsed ---time elapsed from midnight
currFreq ----frequecy
protected int _getInitWorkerTime()
{
int vRun=0;
STime stNow= new STime(PWMSystem.newDate());
int currFreq = _findAlertFrequency()/60;
int sElapsed =Constants.MINUTES_PER_DAY-stNow.elapsedMinutes(STime.midnight);
_log.error("now time as 24------"+stNow.getHourNo24());
_log.error("now currFreq------"+currFreq);
_log.error("now sElapsed-----"+sElapsed);
if(sElapsed == 1440)
sElapsed=0;
if(stNow.getHourNo24()>=0 && stNow.getHourNo24()<=6)
{
_log.error("now time as 24-inside cond-1-----"+stNow.getHourNo24());
if(currFreq>sElapsed)
vRun= currFreq-sElapsed;
else
vRun= -(currFreq-sElapsed);
}
if(stNow.getHourNo24()>6 && stNow.getHourNo24()<=12)
{
_log.error("now time as 24-inside cond-2-----"+stNow.getHourNo24());
if(currFreq>sElapsed)
vRun=360-(currFreq-sElapsed);
else
vRun=360-(-(currFreq-sElapsed));
}
if(stNow.getHourNo24()>12 && stNow.getHourNo24()<=18)
{
_log.error("now time as 24-inside cond-3-----"+stNow.getHourNo24());
if(currFreq>sElapsed)
vRun=720-(currFreq-sElapsed);
else
vRun=720-(-(currFreq-sElapsed));
}
if(stNow.getHourNo24()>18 && (stNow.getHourNo24()<=24 ||stNow.getHourNo24()<=0))
{
_log.error("now time as 24-inside cond-4-----"+stNow.getHourNo24());
if(currFreq>sElapsed)
vRun=1080-(currFreq-sElapsed);
else
vRun=1080-(-(currFreq-sElapsed));
}
// vRun=_MAX_FREQUENCY_DELAY_IN_SEC+ sElapsed*60+_findAlertFrequency()+_BOOT_DELAY_SECONDS_START;*/
//vRun=stNow.elapsedMinutes(STime.midnight)*60+_findAlertFrequency()+_BOOT_DELAY_SECONDS_START;
return (vRun*60 + _BOOT_DELAY_SECONDS_START);
}
Isn't it just a case of saying:
int nextTime = ((timeSinceMidnight / (period-1)) + 1) * period;
(Where the division is done with integer arithmetic. The "period-1" bit is to catch the situation where it's exactly on time, such as the third test case below.)
Sample situations:
Period Minutes since midnight Result
360 120 (2am) 360 (6am)
240 300 (5am) 480 (8am)
300 600 (10am) 600 (10am)
All looks correct to me. You mention dividing time ranges into quarters, but I don't see how that's desirable or relevant... aren't you really just talking about "minutes since midnight" in every case? Note that the way I've expressed it, you could change it to "seconds since midnight" or "milliseconds since midnight" - or even "minutes since the start of the month"; so long as you have a consistent origin and time unit, it should work out fine.
(Note that I've referred to period rather than frequency - normally a higher frequency means something happens more often, not less.)
I found out to be..
protected int _getInitWorkerTime()
{
int vRun = 0;
STime stNow = new STime(PWMSystem.newDate());
int currFreq = _findAlertFrequency() / Constants.SECONDS_PER_MINUTE;
int sElapsed = Constants.MINUTES_PER_DAY- stNow.elapsedMinutes(STime.midnight);
int runsCompleted = sElapsed / currFreq;
int remainLeft = (runsCompleted + 1) * currFreq;
if (remainLeft > sElapsed)
vRun = remainLeft - sElapsed;
else
vRun = sElapsed - remainLeft;
return (vRun * 60 + _BOOT_DELAY_SECONDS_START);

JodaTime Calculate total hours worked in a week

Currently I have a function which can take the start time and end time of one day, and calculate the difference between the two, giving me the hours worked in a day. What I would like to do is be able to get the hours worked for 7 days, and return a grand total, while remaining with the display format (HH:mm).
My function for a single day's total:
Period p = new Period(this.startTime[dayIndex], this.endTime[dayIndex]);
long hours = p.getHours();
long minutes = p.getMinutes();
String format = String.format("%%0%dd", 2);//Ensures that the minutes will always display as two digits.
return Long.toString(hours)+":"+String.format(format, minutes);
this.startTime[] & this.endTime[] are both arrays of DateTime objects.
Any suggestions?
You'll need something to hold a week's worth of days, and call your function once for each day.
But that means you'll want to refactor so that your calculator method doesn't format as a string, but instead returns a numeric value, so you can easily add them together.
Another simple solution:
Here is a method that receives separate the hours and minutes.The parameters are:
Start Hour
Start Minutes
End Hour
End Minutes
first, calculate the difference between hours and minutes separate:
int hours = pEndHour - pStartHour;
int minutes = ((60 - pStartMinutes) + pEndMinutes) - 60;
then, validates if the value of "minutes" variable is negative:
// If so, the "negative" value of minutes is our remnant to the next hour
if (minutes < 0) {
hours--;
minutes = 60 + minutes ;
}
Finally you can print the period of time in the hour format:
String format = String.format("%%0%dd", 2);
System.out.println( "*** " + hours + " : " + minutes);
That's all.
Solution I ended with for those interested
Period[] p=new Period[7];
long hours = 0;
long minutes =0;
for(int x=0; x<=this.daysEntered;x++)
{
p[x] = new Period(this.startTime[x], this.endTime[x]);
hours += p[x].getHours();
minutes += p[x].getMinutes();
}
hours += minutes/60;
minutes=minutes%60;
String format = String.format("%%0%dd", 2);
return Long.toString(hours)+":"+String.format(format, minutes);

Categories

Resources