1

My string value;

09:00-10:00,12:00-14:30,16:00-18:00 (this string repeats time intervals n times like this)

and I want to find out that a string is in the correct format using pattern matching;

Pattern.matches("<Pattern Here>", stringValue);

is it possible?

I tried;

Pattern.matches("^[0-9:0-9-0-9:0-9,]+$", value);

But doesn't work properly

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    "*is it possible?*" - Yes. – Turing85 Nov 22 '22 at 21:40
  • 3
    What error are you getting? Be specific. And consider design choices, i.e. splitting the bad data into an array first, then parsing each individually against your pattern. – Michael Cropper Nov 22 '22 at 21:42
  • 1
    Read a tutorial on regular expressions, rather than just guessing. – tgdavies Nov 22 '22 at 21:47
  • 2
    What does "correct" mean? – tgdavies Nov 22 '22 at 21:48
  • 1
    as @tgdavies pointed out, one could make the argument that the question is ill-defined. If we, for example, factor in [leap seconds (`en.wikipedia.org`)](https://en.wikipedia.org/wiki/Leap_second), the problem might not be solvable through regular expressions. – Turing85 Nov 22 '22 at 21:59
  • Also, does the first time of a pair need to be before the second? Does a later pair need to be after an earlier pair? – tgdavies Nov 22 '22 at 23:44

2 Answers2

6

You can check if the string matches the regex, ^(?:(?:\d{2}:\d{2}\-\d{2}:\d{2})(?:,(?!$))?)*$. Note that you do not need to put starts-with (i.e. ^) and ends-with (i.e. $) when using String#matches.

If the string passes this validation, split the string on , and - and then use java.time API to validate the individual time strings.

Demo:

import java.time.LocalTime;
import java.time.format.DateTimeParseException;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(hasCorrectFormat("09:00-10:00,12:00-14:30,16:00-18:00")); // true
        System.out.println(hasCorrectFormat("09:00-10:00,12:00-1:30,16:00-18:00")); // false -> 1:30 is not in desired
                                                                                    // format
        System.out.println(hasCorrectFormat("09:00-10:00")); // true
        System.out.println(hasCorrectFormat("09:00 10:00")); // false
        System.out.println(hasCorrectFormat("09:00-10:00,09:00 10:00")); // false
        System.out.println(hasCorrectFormat("09:00-10:00-12:00-14:30,16:00-18:00")); // false
        System.out.println(hasCorrectFormat("09:00-10:00,12:00-14:30,16:00-18:00,")); // false
    }

    static boolean hasCorrectFormat(String strTimeRanges) {
        if (!strTimeRanges.matches("(?:(?:\\d{2}:\\d{2}\\-\\d{2}:\\d{2})(?:,(?!$))?)*"))
            return false;
        String[] times = strTimeRanges.split("[-,]");
        for (String time : times) {
            try {
                LocalTime.parse(time);
            } catch (DateTimeParseException e) {
                return false;
            }
        }
        return true;
    }
}

Output:

true
false
true
false
false
false
false

Regex demo

Learn more about the modern Date-Time API from Trail: Date Time.


The valuable comment from Ole V.V. has prompted me to extend my original answer to show how one can use java.time API to compare the times in individual time ranges. I hope this gives enough hints for learners to extend the solution further based on the complexity of the requirements.

import java.time.LocalTime;
import java.time.format.DateTimeParseException;

public class Main {
    public static void main(String[] args) {
        // Test
        System.out.println(hasCorrectFormatAndRanges("09:00-10:00,12:00-14:30,16:00-18:00")); // true
        System.out.println(hasCorrectFormatAndRanges("09:00-10:00,12:00-1:30,16:00-18:00")); // false -> 1:30
        System.out.println(hasCorrectFormatAndRanges("10:00-09:00,12:00-14:30,16:00-18:00")); // false -> 10:00-09:00
        System.out.println(hasCorrectFormatAndRanges("09:00-10:00")); // true
        System.out.println(hasCorrectFormatAndRanges("09:00 10:00")); // false
        System.out.println(hasCorrectFormatAndRanges("09:00-10:00,09:00 10:00")); // false
        System.out.println(hasCorrectFormatAndRanges("09:00-10:00-12:00-14:30,16:00-18:00")); // false
        System.out.println(hasCorrectFormatAndRanges("09:00-10:00,12:00-14:30,16:00-18:00,")); // false
    }

    static boolean hasCorrectFormatAndRanges(String strTimeRanges) {
        if (!strTimeRanges.matches("(?:(?:\\d{2}:\\d{2}\\-\\d{2}:\\d{2})(?:,(?!$))?)*"))
            return false;
        String[] timeRanges = strTimeRanges.split(",");
        for (String timeRange : timeRanges) {
            String[] times = timeRange.split("-");
            try {
                if (LocalTime.parse(times[1]).isBefore(LocalTime.parse(times[0])))
                    return false;
            } catch (DateTimeParseException e) {
                return false;
            }
        }
        return true;
    }
}

Output:

true
false
false
true
false
false
false
false
Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110
  • This would not validate that two time values are separated by a `" - "`, and it would not validate that two time values are separate by two other time values with a `", "`. Example: take the 1st (valid) `String` and replace all occurences of `","` with `"-"` or vice-versa. The now invalid format will evaluate to `true`. – Turing85 Nov 22 '22 at 22:24
  • @Turing85 Thanks for taking the time to review this. I have updated the answer to meet this requirement. – Arvind Kumar Avinash Nov 22 '22 at 22:32
  • Still not correct. String `"09:00-10:00-12:00-14:30,16:00-18:00"` (notice the `"-"` between `"10:00"` and `"12:00"`) evaluates to `true`. – Turing85 Nov 22 '22 at 22:36
  • Well... now one could argue whether `"09:00-10:00,12:00-14:30,16:00-18:00,"` should be valid or not. One way or another, I'd suggest to update the explanation. The original explanation does not really fit the code anymore. – Turing85 Nov 22 '22 at 23:33
  • @Turing85 As per the question posted, `"09:00-10:00,12:00-14:30,16:00-18:00,"` is not a valid string. – Arvind Kumar Avinash Nov 22 '22 at 23:40
  • 1
    This allows for further validating that the times come in order if desired. Like. – Ole V.V. Nov 23 '22 at 04:24
4

You can use the following pattern for any given range of 2 times in the form of 24h clock:

private static final String HOURLY_TIME_PATTERN = "([01][0-9]|2[0-3]):([0-5][0-9])";
private static final String TIME_RANGER_PATTERN = HOURLY_TIME_PATTERN + "-" + HOURLY_TIME_PATTERN;
private static final String PATTERN = "^" + TIME_RANGER_PATTERN + "(," + TIME_RANGER_PATTERN + "?)*$";
private static final Pattern pattern = Pattern.compile(PATTERN);

public static void main(String[] args) {
    String input = "09:00-10:00,12:00-14:30,16:00-18:00";
    if (pattern.matcher(input).matches()) {
        System.out.println("We have a match!");
    }
}

Explanation:

  • HOURLY_TIME_PATTERN is the pattern required for a single hour in a 24h format (e.g. 16:25)
  • TIME_RANGER_PATTERN is the pattern to find a single time range (e.g. 16:25-22:50)
  • PATTERN - is the pattern that ensure that we have at least 1 time range, and any other time range must be lead by a comma (we can have zero or more of them)
Yonatan Karp-Rudin
  • 1,056
  • 8
  • 24