See if the current time falls within a specific range of time in the current day in Java
this is all you should need to do, this method is loosely coupled from the input and highly coherent.
boolean isNowBetweenDateTime(final Date s, final Date e)
{
final Date now = new Date();
return now.after(s) && now.before(e);
}
how you get the Date objects for start and end is irrelevant to comparing them. You are making things way more complicated than you need to with passing String
representations around.
Here is a better way to get the start and end dates, again loosely coupled and highly coherent.
private Date dateFromHourMinSec(final String hhmmss)
{
if (hhmmss.matches("^[0-2][0-9]:[0-5][0-9]:[0-5][0-9]$"))
{
final String[] hms = hhmmss.split(":");
final GregorianCalendar gc = new GregorianCalendar();
gc.set(Calendar.HOUR_OF_DAY, Integer.parseInt(hms[0]));
gc.set(Calendar.MINUTE, Integer.parseInt(hms[1]));
gc.set(Calendar.SECOND, Integer.parseInt(hms[2]));
gc.set(Calendar.MILLISECOND, 0);
return gc.getTime();
}
else
{
throw new IllegalArgumentException(hhmmss + " is not a valid time, expecting HH:MM:SS format");
}
}
Now you can make two well named method calls that will be pretty self documenting.
As pointed out by Kevin, Fuzzy Lollipop's Regex won't pick up times between 14:00 and 19:00.
To get match a full 24 hour clock, you can use this:
if (hhmmss.matches("^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$"))
{
// Do stuff here
}
tl;dr
LocalTime now = ZonedDateTime.now( ZoneId.of( "America/Montreal" ) )
.toLocalTime() ;
Boolean isBetween = ( ! now.isBefore( LocalTime.of( 18 , 0 ) ) // "not before" means "is equal to OR after".
&&
now.isBefore( LocalTime.of( 18 , 30 ) ) ; // Half-Open, beginning is *inclusive* while ending is *exclusive*.
Using java.time
You are using old date-time classes that have proven to be poorly designed, confusing, and troublesome. They are now legacy, supplanted by the java.time classes.
LocalTime
Do not pass mere strings representing time-of-day values. We now have a type for that, the LocalTime
class.
LocalTime start = LocalTime.of( 18 , 0 );
LocalTime stop = LocalTime.of( 18 , 30 );
Pass those instances to your utility method. That method should not have to do any parsing, so no need to throw the parsing exception.
public static boolean isCurrentTimeBetween( LocalTime start , LocalTime stop ) {
…
ZonedDateTime
A time zone is crucial in determining the current date and time-of-day. For any given moment, the date varies around the globe by zone. For example, a few minutes after midnight in Paris France is a new day while still “yesterday” in Montréal Québec.
Specify a proper time zone name in the format of continent/region
, such as America/Montreal
, Africa/Casablanca
, or Pacific/Auckland
. Never use the 3-4 letter abbreviation such as EST
or IST
as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.now( z );
To compare the time-of-day of now, we could simply extract a LocalTime
from that ZonedDateTime
. But we have the problem of anomalies, such as Daylight Saving Time (DST) and politicians redefining time zones. There may not be any 6 PM hour on a particular date. The solution to this conundrum depends on your business context and your business rules. You could either ignore the conundrum and stick with literally asking if the current time is between your target start-stop time. Or you could apply the time zone to your start-stop times-of-day of day and let ZonedDateTime
class make adjustments as it sees fit. Let's look at both approaches.
Ignore anomalies
First, ignore any anomalies. Ask simply and literally if the current time-of-day is between the target start and stop times-of-day.
We can extract a time-of-day object from the zoned date-time object.
LocalTime localTimeNow = zdt.toLocalTime(); // Extract a time-of-day from the zoned date-time object.
Compare that to our stop-start times-of-day. Note that we use here the Half-Open approach to defining a span of time. In this approach the beginning is inclusive while the ending is exclusive. This approach is common in date-time work and generally is the wise way to go.
Boolean isNowOnOrAfterStart = ( ! localTimeNow.isBefore( start ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before".
Boolean isNowBeforeStop = localTimeNow.isBefore( stop );
Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive.
Consider anomalies
Next we consider any anomalies. We apply the start and stop times-of-day to the current date within the same time zone. We extract the date-only from the zoned date-time object.
LocalDate localDateToday = zdt.toLocalDate();
ZonedDateTime zdtStart = ZonedDateTime.of( localDateToday , start , z );
ZonedDateTime zdtStop = ZonedDateTime.of( localDateToday , stop , z );
Study the class documentation to understand the behavior of ZonedDateTime.of
in resolving invalid time-of-day values. There is no perfect way to resolve nonexistent time-of-day values, so you must decide if this class’ way meets your business rules.
ZonedDateTime.of
public static ZonedDateTime of(LocalDate date, LocalTime time, ZoneId zone)
Obtains an instance of ZonedDateTime from a local date and time. This creates a zoned date-time matching the input local date and time as closely as possible. Time-zone rules, such as daylight savings, mean that not every local date-time is valid for the specified zone, thus the local date-time may be adjusted.
The local date time and first combined to form a local date-time. The local date-time is then resolved to a single instant on the time-line. This is achieved by finding a valid offset from UTC/Greenwich for the local date-time as defined by the rules of the zone ID.
In most cases, there is only one valid offset for a local date-time. In the case of an overlap, when clocks are set back, there are two valid offsets. This method uses the earlier offset typically corresponding to "summer".
In the case of a gap, when clocks jump forward, there is no valid offset. Instead, the local date-time is adjusted to be later by the length of the gap. For a typical one hour daylight savings change, the local date-time will be moved one hour later into the offset typically corresponding to "summer".
Apply the same comparison logic as we saw above.
Boolean isNowOnOrAfterStart = ( ! zdt.isBefore( zdtStart ) ) ; // A briefer way of asking "is equal to OR is after" is "is not before".
Boolean isNowBeforeStop = zdt.isBefore( zdtStop );
Boolean isNowInTargetZone = ( isNowOnOrAfterStart && isNowBeforeStop ); // Half-Open: beginning is inclusive while ending is exclusive.
Alternative way to make the comparison is to use the handy Interval
class from the ThreeTen-Extra project. That class takes a pain of Instant
objects, which you can extract from your ZonedDateTime
objects. The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Interval interval = Interval.of( zdtStart.toInstant() , zdtStop.toInstant() );
Boolean isNowInTargetZone = interval.contains( zdt.toInstant() );
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date
, Calendar
, & SimpleDateFormat
.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
- Java SE 8 and SE 9 and later
- Built-in.
- Part of the standard Java API with a bundled implementation.
- Java 9 adds some minor features and fixes.
- Java SE 6 and SE 7
- Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
- Android
- The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
- See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval
, YearWeek
, YearQuarter
, and more.