By externalizing the scheduled date (to a database), the typical scheduling practices (i.e. cron based, or fixed scheduling) no longer apply.  Given a target Date, you can schedule the task accurately as follows: 
Date now = new Date();
Date next = ... get next date from external source ...
long delay = next.getTime() - now.getTime();
scheduler.schedule(Runnable task, delay, TimeUnit.MILLISECONDS);
What remains is to create an efficient approach to dispatching each new task.
The following has a TaskDispatcher thread, which schedules each Task based on the next java.util.Date (which you read from a database).  There is no need to check daily; this approach is flexible enough to work with any scheduling scenario stored in the database.
To follow is working code to illustrate the approach.
The example Task used; in this case just sleeps for a fixed time.  When the task is complete, the TaskDispatcher is signaled through a CountDownLatch.
public class Task implements Runnable {
    private final CountDownLatch completion;
    public Task(CountDownLatch completion) {
        this.completion = completion;
    }
    @Override
    public void run() {
        System.out.println("Doing task");
        try {
            Thread.sleep(60*1000);  // Simulate the job taking 60 seconds
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        completion.countDown();     // Signal that the job is complete
    }
}
The dispatcher is responsible for reading the database for the next scheduled Date, launching a ScheduledFuture runnable, and waiting for the task to complete.
public class TaskDispatcher implements Runnable {
    private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
    private boolean isInterrupted = false;
    @Override
    public void run() {
        while (!isInterrupted) {
            Date now = new Date();
            System.out.println("Reading database for next date");
            Date next = ... read next data from database ...
            //Date next = new Date();   // Used as test
            //next.setTime(now.getTime()+10*1000); // Used as test
            long delay = next.getTime() - now.getTime();
            System.out.println("Scheduling next task with delay="+delay);
            CountDownLatch latch = new CountDownLatch(1);
            ScheduledFuture<?> countdown = scheduler.schedule(new Task(latch), delay, TimeUnit.MILLISECONDS);
            try {
                System.out.println("Blocking until the current job has completed");
                latch.await();
            } catch (InterruptedException e) {
                System.out.println("Thread has been requested to stop");
                isInterrupted = true;
            }
            if (!isInterrupted)
                System.out.println("Job has completed normally");
        }
        scheduler.shutdown();
    }
}
The TaskDispatcher was started as follows (using Spring Boot) - start the thread as you normally do with Spring:
@Bean
public TaskExecutor taskExecutor() {
    return new SimpleAsyncTaskExecutor(); // Or use another one of your liking
}
@Bean
public CommandLineRunner schedulingRunner(TaskExecutor executor) {
    return new CommandLineRunner() {
        public void run(String... args) throws Exception {
            executor.execute(new TaskDispatcher());
        }
    };
}
Let me know if this approach will work for your use case.