Reputation: 4938
I'm working with an API that has a different time than the program's machine. I can retrieve the time of the server, which will returns milliseconds.
e.g
long serverTime = api.getTime()
Since I know the server time, can I somehow create a date object from this millisecond that would represent certain dates, but with server time?
For example, API is only available from 8:00 to 16:00 UTC (machine time is +1 hour). My use case requires me to send data using this API as soon as possible (the sooner I send data, the sooner they get processed, and the sooner other tasks can start running and so on, unfortunately, every millisecond spared is good). So far I am doing something like this
// create date time when i want to do something with API in my time
LocalDateTime time = LocalDateTime.of(2021, 3, 26, 9, 0, 0);
long targetMillis = time.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
long serverTime = api.getTime()
// calculate diff
long serverTimeDiff = client.getServerTime() - System.currentTimeMillis();
// sleep thread till the time is right. Sleep 1 minute less to start busy waiting to get some extra
// spared millis
Thread.sleep((targetMillis - serverTime) - minutesToMilliseconds(1) );
while( System.currentTimeMillis() + serverTimeDiff < ( targetMillis - 50 ) ){
//busy waiting
}
api.sendData(..);
However, the time diff may not be that accurate (change in few millis), is there some way how to create something like:
long serverTime = api.getTime()
Instant date = Instant.ofEpochMilli(serverTime).setHour(..).setMinute(..).setSecond(..);
So I can calculate the diff more accurately with something like
Thread.sleep((targetMillis - date.toMillis().toEpochMilli) - minutesToMilliseconds(1))
and thus possibly save some milliseconds?
Upvotes: 0
Views: 113
Reputation: 338506
Your Question is quite unclear. But I am guessing that you want to start a task at 08:00 UTC.
If so, use a scheduled executor service to run your Runnable
or Callable
task on a background thread at the appropriate time.
Determine your next target moment, the next 8 AM in UTC. To do this, you will need the current date and current time as seen in UTC. If right now is not before 8 AM, you must add a day to the date. Then combine that date with the specified time of 8 AM to get a moment as seen in UTC (an offset of zero hours-minutes-seconds).
Calculate the amount of elapsed time until that target moment. Use that amount of time as the delay argument to the schedule
method of your ScheduledExecutorService
.
package work.basil;
import java.time.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* By Basil Bourque. http://www.Basil.work/
* https://stackoverflow.com/q/66809336/642706
*/
public class App
{
public static void main ( String[] args )
{
App app = new App();
app.demo();
}
private void demo ( )
{
System.out.println( "INFO - demo method starting. " + Instant.now() );
// Using lambda syntax to define a `Runnable` object as the task to be done at specified moment.
// You could just as well write a conventional class that implements `Runnable` (or `Callable`).
Runnable task = ( ) -> {
System.out.println( "Sending data at: " + Instant.now() );
};
ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
// Calculate time to wait until the next 8 AM.
LocalTime targetTime = LocalTime.of( 8 , 0 );
OffsetDateTime nowUtc = OffsetDateTime.now( ZoneOffset.UTC );
LocalDate targetDate = nowUtc.toLocalDate();
if ( ! nowUtc.toLocalTime().isBefore( targetTime ) )
{
targetDate = targetDate.plusDays( 1 );
}
OffsetDateTime targetUtc = OffsetDateTime.of( targetDate , targetTime , ZoneOffset.UTC );
Duration duration = Duration.between( nowUtc , targetUtc );
System.out.println( "INFO - Your task is waiting = " + duration + " to run at: " + targetUtc + " which is: " + targetUtc.atZoneSameInstant( ZoneId.systemDefault() ) + "." );
long delay = duration.toNanos();
ses.schedule( task , delay , TimeUnit.NANOSECONDS );
// … Eventually shutdown your executor service so its backing pool of threads do not continue indefinitely like a zombie 🧟.
ses.shutdown();
ses.awaitTermination();
System.out.println( "INFO - demo method ending. " + Instant.now() );
}
}
When run.
INFO - demo method starting. 2021-03-26T03:15:03.203895Z
INFO - Your task is waiting = PT4H44M56.786492S to run at: 2021-03-26T08:00Z which is: 2021-03-26T01:00-07:00[America/Los_Angeles].
Upvotes: 1