Try this. Start with the base regex:
\d{1,2}(:\d\d)?-\d{1,2}(:\d\d)?
That is:
- one-to-two digits, optionally followed by : and two more digits
- followed by a hyphen
- followed by one-to-two digits, optionally followed by : and two more digits
This matches all your core cases:
11-12
1-2
1:15-2
10-3:45
2:15-11:30
etc. Now mix in negative lookbehind and negative lookahead to invalidate matches that appear within undesired contexts. Let's invalidate the match when a digit or dash or colon appears directly to the left or right of the match:
The negative lookbehind: (?<!\d|-|:)
The negative lookahead: (?!\d|-|:)
Slap the neg-lookbehind at the beginning, and the neg-lookahead at the end, you get:
(?<!\d|-|:)(\d{1,2}(:\d\d)?-\d{1,2}(:\d\d)?)(?!\d|-|:)
or as a Java String (by request)
Pattern p = Pattern.compile("(?<!\\d|-|:)(\\d{1,2}(:\\d\\d)?-\\d{1,2}(:\\d\\d)?)(?!\\d|-|:)");
Now while the lookaround has eliminated matches within dates, you're still matching some silly things like 99:99-88:88 because \d matches any digit 0-9. You can mix more restrictive character classes into this regex to address that issue. For example, with a 12-hour clock:
For the hour part, use
(1[0-2]|0?[1-9])
instead of
\d{1,2}
For the minute part use
(0[0-9]|[1-5][0-9])
instead of
\d\d
Mixing the more restrictive character classes into the regex yields this nearly impossible to grok and maintain beast:
(?<!\d|-|:)(((1[0-2]|0?[1-9]))(:((0[0-9]|[1-5][0-9])))?-(1[0-2]|0?[1-9])(:((0[0-9]|[1-5][0-9])))?)(?!\d|-|:)
As Java code:
Pattern p = Pattern.compile("(?<!\\d|-|:)(((1[0-2]|0?[1-9]))(:((0[0-9]|[1-5][0-9])))?-(1[0-2]|0?[1-9])(:((0[0-9]|[1-5][0-9])))?)(?!\\d|-|:)");