0

I know this should be simple, but I can't find anything on the internet.

Given some conditions, I want to get the next Date when they will be met. For example, if conditions are minute = 01 and second = 30 and now the time is 15:58:00, the function should return today at 16:01:30. How can I accomplish this in Java?

I need to be able to set conditions of, at least, seconds, minutes and hours, but I would like to have the possibility to set one condition to any value (like the example above, that doesn't specify an hour).

Thanks and sorry for my bad English.

EDIT: I see there's something that might need clarification: I want to get a Date (or whatever) always after the current time that meets conditions. Also, this is for a Minecraft Spigot server, maybe this information can help.

jnts
  • 33
  • 1
  • 6
  • 1
    If by `Date` you meant `java.util.Date`, I recommend you don’t that class. It is poorly designed and long outdated. Instead use `ZonedDateTime`or another appropriate class from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Feb 23 '21 at 16:59
  • 1
    Are you really implementing the functionality of [cron](https://en.wikipedia.org/wiki/Cron) in Java? There are already libraries doing that, so you don’t need to reinvent the wheel. – Ole V.V. Feb 23 '21 at 17:01
  • @OleV.V. I have already heard about the cron4j library, and that's one of the things I was planning to do. But this still doesn't solve another project I had in mind: I want to make a train "departure board" based on a schedule for a video game. The function should return the exact time when a train will depart, even if the schedule only shows "*:10:00" (at any hour ten). Thanks anyway for the suggestion. – jnts Feb 23 '21 at 20:48
  • @OleV.V. Yes, by `Date` i meant `java.util.Date`. Thanks for the information! – jnts Feb 23 '21 at 20:49
  • @jnts - `if conditions are minute = 01 and second = 30 and now the time is 15:58:00, the function should return today at 16:01:30` - Why `16:01:30` and not `15:01:30`? Is it because `15:01:30` is earlier than `15:58:00` and you want a later time with the specified minute and second? – Arvind Kumar Avinash Feb 23 '21 at 21:01
  • 1
    @ArvindKumarAvinash exactly, I want to get the first time when the conditions will be met _after_ the current time. – jnts Feb 23 '21 at 21:07
  • 1
    If you put this check `if (updated.isBefore(today)) { updated = updated.plusHours(1); }` in my second solution, you will get `2021-02-23T16:01:30`. If you think it has brought you one step closer, you should explore the rich *java.time* API further. In my answer, I've already put a link to the brilliant tutorial by Oracle. Feel free to comment in case you need any further clarification. – Arvind Kumar Avinash Feb 23 '21 at 21:15

4 Answers4

5

You could use streams for this:

Optional<LocalDateTime> firstMatch = 
                         Stream.iterate(
                                  LocalDateTime.now(),
                                  ldt -> ldt.plusSeconds(1L))
                               .filter(
                                  // Insert your condition here
                                  ldt -> ldt.getSecond() == 0) 
                               .findFirst();

What this code does is take the current LocalDateTime and use it to generate a stream of LocalDateTime objects (advancing the time by 1 second each time). Once it encounters a LocalDateTime that matches the provided condition, it returns this objects and terminates the stream.

Keep in mind that using this approach will generate a lot of objects if it takes a while for the condition to become true, so it is not very efficient.

If you want to strip the nanoseconds replace LocalDateTime.now() by LocalDateTime.now().withNano(0).

Jeroen Steenbeeke
  • 3,884
  • 5
  • 17
  • 26
  • Thanks for the answer. My limited knowledge of the language makes it a bit difficult for me to understand your code. Is this similar to having a `while` loop that checks the condition and adds one second if it's not met? What's the advantage of using your method? – jnts Feb 24 '21 at 07:15
  • 2
    Imho it is more beautiful than a while-loop, but that's only a personal opinion. To explain the code a bit: Jeroen creates an endless Stream of objects. He starts with a date object for now and creates a new object which is 1 second in the future. The stream takes care of the rest and so you get LocalDateTime objects for every second from now on. In the filter you define the condition to filter the stream, but you get every timestamp that meet this, so you have to use findfirst. Then you get the first object that meets your conditions. As mentioned you generate a lot of objects ... – Norbert Feb 24 '21 at 07:58
3

You can use LocalDateTime#plus... to add duration to get the updated time.

Demo:

import java.time.LocalDateTime;
import java.time.LocalTime;

public class Main {
    public static void main(String[] args) {
        String strTime = "15:58:00";

        LocalTime time = LocalTime.parse(strTime);

        // Today at the specified time
        LocalDateTime today = LocalDateTime.now().with(time);
        System.out.println(today);

        // Today with the added minutes and seconds
        LocalDateTime updated = today.plusMinutes(1).plusSeconds(30);
        System.out.println(updated);
    }
}

Output:

2021-02-23T15:58
2021-02-23T15:59:30

If you want to switch to a different time, you can use LocalDateTime#with...

import java.time.LocalDateTime;
import java.time.LocalTime;

public class Main {
    public static void main(String[] args) {
        String strTime = "15:58:00";

        LocalTime time = LocalTime.parse(strTime);

        // Today at the specified time
        LocalDateTime today = LocalDateTime.now().with(time);
        System.out.println(today);

        // Today with the updated minute and second
        LocalDateTime updated = today.withMinute(1).withSecond(30);
        System.out.println(updated);
    }
}

Output:

2021-02-23T15:58
2021-02-23T15:01:30

Learn more about the modern date-time API from **[Trail: Date Time](https://docs.oracle.com/javase/tutorial/datetime/index.html)**.

Note: The java.util date-time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern date-time API.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • 1
    The author don't want to add 1 minute and 30 seconds, she likes to jump to the next timestamp with 1 Minute and 30 seconds ;) – Norbert Feb 23 '21 at 15:11
  • @Norbert - The question is not very clear. I've provided the OP with both solutions. I'll wait for his/her response and then update the answer if required. – Arvind Kumar Avinash Feb 23 '21 at 15:17
  • @Norbert exactly, that's not what I wanted to do. I want to get a time always _after_ the current time that meets conditions defined in a timetable. Check my comment on the question to understand exactly how I want to apply this. Thanks anyway for the answer. – jnts Feb 23 '21 at 20:53
0

If I got you right, this should solve your problem

public String nextMeet(int minutes, int seconds) {
    LocalDateTime currentDate = LocalDateTime.now();
    if ((currentDate.getMinute()*60) + currentDate.getSecond() > (minutes*60) + seconds) {
        return (currentDate.getHour() + 1) + ":" + minutes + ":" + seconds;
    } else {
        return currentDate.getHour() + ":" + minutes + ":" + seconds;
    }
}
John
  • 13
  • 5
  • I want to get a time that's always _after_ the current time. I've updated the question to include this clarification. – jnts Feb 23 '21 at 21:10
0

I've found another solution myself. This library can parse a cron expression and return the next time when it will run, which solves most of my issues. (taken from this question)

Thanks to @OleV.V. for the idea.

jnts
  • 33
  • 1
  • 6