I need to create POSIX format of TimeZone as defined by the following format.
std offset dst [offset],start[/time],end[/time]
For ex for "America/New_York" the POSIX format is
EST+5EDT,M3.2.0/2,M11.1.0/2
Now the value M3.2.0/2 is represented in the form Mm.w.d/t.
This specifies day d of week w of month m. The day d must be between 0 (Sunday) and 6. The week w must be between 1 and 5; week 1 is the first week in which day d occurs, and week 5 specifies the last d day in the month. The month m should be between 1 and 12. I borrowed the above explanation from the following link
http://www.gnu.org/software/libc/manual/html_node/TZ-Variable.html
So the above example states, the normal offset from UTC is 5 hours; since this is west of the prime meridian, the sign is positive. Summer time begins on March’s second Sunday at 2:00am and ends on November’s first Sunday at 2:00am.
When I check this in Linux timezone file /usr/share/zoneinfo/America/New_York, it matches the above value
EST5EDT,M3.2.0,M11.1.0
However when I construct this in java for timezone "America/New_York" I get the following string
EST-5EDT+1,M2.1.1/2,M10.1.1/2
I constructed the above string by extracting the information from the output of the following code.
TimeZone timezone = TimeZone.getTimeZone("America/New_York");
System.out.println(timezone.toString());
The output is as below
sun.util.calendar.ZoneInfo[id="America/New_York",offset=-18000000,dstSavings=3600000,useDaylight=true,transitions=235,lastRule=java.util.SimpleTimeZone[id=America/New_York,offset=-18000000,dstSavings=3600000,useDaylight=true,startYear=0,startMode=3,startMonth=2,startDay=8,startDayOfWeek=1,startTime=7200000,startTimeMode=0,endMode=3,endMonth=10,endDay=1,endDayOfWeek=1,endTime=7200000,endTimeMode=0]
Notice the values endMonth=10 which should be 11 as compared to Linux output.
Relying on the output of toString is not advisable, since there are no contractual guarantees about its format in either the TimeZone or SimpleTimeZone classes.
Obviously, your month numbers are off by one; the week of the month isn’t quite as simple, since you need to take into account the first full week of the month.
I would use Java’s documented public methods to get the information:
static String posixSpecFor(TimeZone tz) {
Formatter posixSpec = new Formatter();
float offset = (float) tz.getRawOffset() / (1000 * 60 * 60) * -1;
posixSpec.format("%s%s%s",
tz.getDisplayName(false, TimeZone.SHORT),
offset >= 0 ? "+" : "",
new DecimalFormat("0.##").format(offset));
if (tz.observesDaylightTime()) {
posixSpec.format("%s", tz.getDisplayName(true, TimeZone.SHORT));
}
ZoneId zone = tz.toZoneId();
TemporalField weekOfMonth =
WeekFields.of(DayOfWeek.SUNDAY, 7).weekOfMonth();
int thisYear = Year.now(zone).getValue();
List<ZoneOffsetTransitionRule> rules =
zone.getRules().getTransitionRules();
if (rules.size() > 2) {
rules = rules.subList(0, 2);
}
for (ZoneOffsetTransitionRule rule : rules) {
posixSpec.format(",M%d.%d.%d/%s",
rule.getMonth().getValue(),
rule.createTransition(thisYear).getDateTimeBefore().get(
weekOfMonth),
rule.getDayOfWeek().getValue() % 7,
rule.getLocalTime());
}
return posixSpec.toString();
}
Following is the complete code that I am using to construct Posix timezone string
public class PosixTimeZone {
public String toPosixTZ(String timezoneStr) {
TimeZone timezone = TimeZone.getTimeZone(timezoneStr);
sop("timezoneStr", timezoneStr);
String posixTX = "";
PosixTimeZoneData pTZData = new PosixTimeZoneData(timezone);
if (timezone.useDaylightTime()) {
posixTX = getPosixDSString(pTZData);
} else {
posixTX = getPosixString(pTZData);
}
return posixTX;
}
public static void main(String args[]) {
System.out.println("Posix TimeZone is " + new PosixTimeZone().toPosixTZ(args[0]));
}
private void sop(String varname, String meesage) {
System.out.println("**************: " + varname + " = " + meesage);
}
private String getPosixDSString(PosixTimeZoneData pTZData) {
String posixString = "";
if ((pTZData.std != null && !pTZData.std.isEmpty())
&& (pTZData.stdOffset != null)//&& !pTZData.stdOffset.isEmpty())
&& (pTZData.dst != null && !pTZData.dst.isEmpty())
&& (pTZData.dstOffset != null)// && !pTZData.dstOffset.isEmpty())
&& (pTZData.start != null && !pTZData.start.isEmpty())
&& (pTZData.end != null && !pTZData.end.isEmpty())) {
posixString = String.format("%s%s%s%s,%s,%s", pTZData.std, pTZData.stdOffset, pTZData.dst,
pTZData.dstOffset, pTZData.start, pTZData.end);
} else {
sop("Error", "Invalid Parameters");
}
return posixString;
}
private String getPosixString(PosixTimeZoneData pTZData) {
String posixString = "";
if ((pTZData.std != null && !pTZData.std.isEmpty())
&& (pTZData.stdOffset != null && !pTZData.stdOffset.isEmpty())) {
posixString = String.format("%s%s", pTZData.std, pTZData.stdOffset);
} else {
sop("Error", "Invalid Parameters");
}
return posixString;
}
class PosixTimeZoneData {
String std = "";
String stdOffset = "";
String dst = "";
String dstOffset = "";
String start = "";
String end = "";
private PosixTimeZoneData(TimeZone timeZone) {
std = timeZone.getDisplayName(false, TimeZone.SHORT);
int rawOffset = (timeZone.getRawOffset() / 3600000) * -1;
stdOffset = (rawOffset >= 0)
? ((rawOffset == 0) || (rawOffset == 1) ? "" : "+" + rawOffset)
: "" + rawOffset;
if (timeZone.useDaylightTime()) {
dst = timeZone.getDisplayName(true, TimeZone.SHORT);
int dstRawOffset = timeZone.getDSTSavings() / 3600000;
dstOffset = (dstRawOffset >= 0)
? ((dstRawOffset == 0) || (dstRawOffset == 1) ? "" : "+" + dstRawOffset)
: "" + dstRawOffset;
ZoneId zone = timeZone.toZoneId();
TemporalField weekOfMonth
= WeekFields.of(DayOfWeek.SUNDAY, 7).weekOfMonth();
int thisYear = Year.now(zone).getValue();
List<ZoneOffsetTransitionRule> rules
= zone.getRules().getTransitionRules();
if (rules != null && !rules.isEmpty()) {
if (rules.size() > 2) {
rules = rules.subList(0, 2);
}
start = String.format("M%d.%d.%d/%s",
rules.get(0).getMonth().getValue(),
rules.get(0).createTransition(thisYear).getDateTimeBefore().get(
weekOfMonth),
rules.get(0).getDayOfWeek().getValue() % 7,
rules.get(0).getLocalTime().getHour());
end = String.format("M%d.%d.%d/%s",
rules.get(1).getMonth().getValue(),
rules.get(1).createTransition(thisYear).getDateTimeBefore().get(
weekOfMonth),
rules.get(1).getDayOfWeek().getValue() % 7,
rules.get(1).getLocalTime().getHour());
}
}
}
}
}
I have timespans:
String time1 = 01:00:00
String time2 = 05:00:00
I want to check if time1 and time2 both lies between 20:11:13 and 14:49:00.
Actually, 01:00:00 is greater than 20:11:13 and less than 14:49:00 considering 20:11:13 is always less than 14:49:00. This is given prerequisite.
So what I want is, 20:11:13 < 01:00:00 < 14:49:00.
So I need something like that:
public void getTimeSpans()
{
boolean firstTime = false, secondTime = false;
if(time1 > "20:11:13" && time1 < "14:49:00")
{
firstTime = true;
}
if(time2 > "20:11:13" && time2 < "14:49:00")
{
secondTime = true;
}
}
I know that this code does not give correct result as I am comparing the string objects.
How to do that as they are the timespans but not the strings to compare?
You can use the Calendar class in order to check.
For example:
try {
String string1 = "20:11:13";
Date time1 = new SimpleDateFormat("HH:mm:ss").parse(string1);
Calendar calendar1 = Calendar.getInstance();
calendar1.setTime(time1);
calendar1.add(Calendar.DATE, 1);
String string2 = "14:49:00";
Date time2 = new SimpleDateFormat("HH:mm:ss").parse(string2);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(time2);
calendar2.add(Calendar.DATE, 1);
String someRandomTime = "01:00:00";
Date d = new SimpleDateFormat("HH:mm:ss").parse(someRandomTime);
Calendar calendar3 = Calendar.getInstance();
calendar3.setTime(d);
calendar3.add(Calendar.DATE, 1);
Date x = calendar3.getTime();
if (x.after(calendar1.getTime()) && x.before(calendar2.getTime())) {
//checkes whether the current time is between 14:49:00 and 20:11:13.
System.out.println(true);
}
} catch (ParseException e) {
e.printStackTrace();
}
tl;dr
20:11:13 < 01:00:00 < 14:49:00
LocalTime target = LocalTime.parse( "01:00:00" ) ;
Boolean targetInZone = (
target.isAfter( LocalTime.parse( "20:11:13" ) )
&&
target.isBefore( LocalTime.parse( "14:49:00" ) )
) ;
java.time.LocalTime
The java.time classes include LocalTime to represent a time-of-day only without a date and without a time zone.
So what I want is, 20:11:13 < 01:00:00 < 14:49:00.
First we define the boundaries. Your input strings happen to comply with standard ISO 8601 formats. The java.time classes use ISO 8601 formats by default, so no need to specify a formatting pattern.
LocalTime start = LocalTime.parse( "20:11:13" );
LocalTime stop = LocalTime.parse( "14:49:00" );
And define our test case, the target 01:00:00.
LocalTime target = LocalTime.parse( "01:00:00" );
Now we are set up to compare these LocalTime objects. We want to see if the target is after the later time but before the earlier time. That means middle of the night in this case, between approximately 8 PM and 3 AM the next morning.
Boolean isTargetAfterStartAndBeforeStop = ( target.isAfter( start ) && target.isBefore( stop ) ) ;
That test can be more simply stated as “not between 3 AM and 8 PM”. We could then generalize to any pair of LocalTime objects where we test for between if the start comes before the stop with a 24-hour clock, and not between if start comes after the stop (as in the case of this Question).
Further more, spans of time are usually handled with the Half-Open approach where the beginning is inclusive while the ending is exclusive. So a "between" comparison, strictly speaking, would be “is the target equal to or later than start AND the target is before stop”, or more simply, “is target not before start AND before stop”.
Boolean isBetweenStartAndStopStrictlySpeaking =
( ( ! target.isBefore( start ) && target.isBefore( stop ) ) ;
If the start is after the stop, within a 24-hour clock, then assume we want the logic suggested in the Question (is after 8 PM but before 3 AM).
if( start.isAfter( stop ) ) {
return ! isBetweenStartAndStopStrictlySpeaking ;
} else {
return isBetweenStartAndStopStrictlySpeaking ;
}
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.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 brought some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android (26+) bundle implementations of the java.time classes.
For earlier Android (<26), the process of API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
The answer given by #kocko works in only same day.
If start time "23:00:00" and end "02:00:00"[next day] and current time is "01:30:00" then result will false...
I modified the #kocko's answer to work perfectly
public static boolean isTimeBetweenTwoTime(String initialTime, String finalTime,
String currentTime) throws ParseException {
String reg = "^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
if (initialTime.matches(reg) && finalTime.matches(reg) &&
currentTime.matches(reg))
{
boolean valid = false;
//Start Time
//all times are from java.util.Date
Date inTime = new SimpleDateFormat("HH:mm:ss").parse(initialTime);
Calendar calendar1 = Calendar.getInstance();
calendar1.setTime(inTime);
//Current Time
Date checkTime = new SimpleDateFormat("HH:mm:ss").parse(currentTime);
Calendar calendar3 = Calendar.getInstance();
calendar3.setTime(checkTime);
//End Time
Date finTime = new SimpleDateFormat("HH:mm:ss").parse(finalTime);
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(finTime);
if (finalTime.compareTo(initialTime) < 0)
{
calendar2.add(Calendar.DATE, 1);
calendar3.add(Calendar.DATE, 1);
}
java.util.Date actualTime = calendar3.getTime();
if ((actualTime.after(calendar1.getTime()) ||
actualTime.compareTo(calendar1.getTime()) == 0) &&
actualTime.before(calendar2.getTime()))
{
valid = true;
return valid;
} else {
throw new IllegalArgumentException("Not a valid time, expecting
HH:MM:SS format");
}
}
}
Output
"07:00:00" - "17:30:00" - "15:30:00" [current] - true
"17:00:00" - "21:30:00" - "16:30:00" [current] - false
"23:00:00" - "04:00:00" - "02:00:00" [current] - true
"00:30:00" - "06:00:00" - "06:00:00" [current] - false
(I have included lower limit value to [upper limit value-1])
Modified #Surendra Jnawali' code. It fails
if current time is 23:40:00 i.e greater than start time and less than equals to 23:59:59.
All credit goes to the real owner
This is how it should be :This works perfect
public static boolean isTimeBetweenTwoTime(String argStartTime,
String argEndTime, String argCurrentTime) throws ParseException {
String reg = "^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
//
if (argStartTime.matches(reg) && argEndTime.matches(reg)
&& argCurrentTime.matches(reg)) {
boolean valid = false;
// Start Time
java.util.Date startTime = new SimpleDateFormat("HH:mm:ss")
.parse(argStartTime);
Calendar startCalendar = Calendar.getInstance();
startCalendar.setTime(startTime);
// Current Time
java.util.Date currentTime = new SimpleDateFormat("HH:mm:ss")
.parse(argCurrentTime);
Calendar currentCalendar = Calendar.getInstance();
currentCalendar.setTime(currentTime);
// End Time
java.util.Date endTime = new SimpleDateFormat("HH:mm:ss")
.parse(argEndTime);
Calendar endCalendar = Calendar.getInstance();
endCalendar.setTime(endTime);
//
if (currentTime.compareTo(endTime) < 0) {
currentCalendar.add(Calendar.DATE, 1);
currentTime = currentCalendar.getTime();
}
if (startTime.compareTo(endTime) < 0) {
startCalendar.add(Calendar.DATE, 1);
startTime = startCalendar.getTime();
}
//
if (currentTime.before(startTime)) {
System.out.println(" Time is Lesser ");
valid = false;
} else {
if (currentTime.after(endTime)) {
endCalendar.add(Calendar.DATE, 1);
endTime = endCalendar.getTime();
}
System.out.println("Comparing , Start Time /n " + startTime);
System.out.println("Comparing , End Time /n " + endTime);
System.out
.println("Comparing , Current Time /n " + currentTime);
if (currentTime.before(endTime)) {
System.out.println("RESULT, Time lies b/w");
valid = true;
} else {
valid = false;
System.out.println("RESULT, Time does not lies b/w");
}
}
return valid;
} else {
throw new IllegalArgumentException(
"Not a valid time, expecting HH:MM:SS format");
}
}
RESULT
Comparing , Start Time /n Thu Jan 01 23:00:00 IST 1970
Comparing , End Time /n Fri Jan 02 02:00:00 IST 1970
Comparing , Current Time /n Fri Jan 02 01:50:00 IST 1970
RESULT, Time lies b/w
Calendar now = Calendar.getInstance();
int hour = now.get(Calendar.HOUR_OF_DAY); // Get hour in 24 hour format
int minute = now.get(Calendar.MINUTE);
Date date = parseDate(hour + ":" + minute);
Date dateCompareOne = parseDate("08:00");
Date dateCompareTwo = parseDate("20:00");
if (dateCompareOne.before( date ) && dateCompareTwo.after(date)) {
//your logic
}
private Date parseDate(String date) {
final String inputFormat = "HH:mm";
SimpleDateFormat inputParser = new SimpleDateFormat(inputFormat, Locale.US);
try {
return inputParser.parse(date);
} catch (java.text.ParseException e) {
return new Date(0);
}
}
Further more, to be more precise,
If you compare a time between an interval more than 00:00 to 24:00 of that day,
you need to parse the day too.
There are lots of answers here but I want to provide a new one which is similar with Basil Bourque's answer but with a full code example. So please see the method below:
private static void checkTime(String startTime, String endTime, String checkTime) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("HH:mm:ss", Locale.US);
LocalTime startLocalTime = LocalTime.parse(startTime, formatter);
LocalTime endLocalTime = LocalTime.parse(endTime, formatter);
LocalTime checkLocalTime = LocalTime.parse(checkTime, formatter);
boolean isInBetween = false;
if (endLocalTime.isAfter(startLocalTime)) {
if (startLocalTime.isBefore(checkLocalTime) && endLocalTime.isAfter(checkLocalTime)) {
isInBetween = true;
}
} else if (checkLocalTime.isAfter(startLocalTime) || checkLocalTime.isBefore(endLocalTime)) {
isInBetween = true;
}
if (isInBetween) {
System.out.println("Is in between!");
} else {
System.out.println("Is not in between!");
}
}
Either if you are calling this method using:
checkTime("20:11:13", "14:49:00", "01:00:00");
Or using:
checkTime("20:11:13", "14:49:00", "05:00:00");
The result will be:
Is in between!
Following method checks whether 'validateTime' is between 'startTime' & 'endTime' or not while considering possibility that 'endTime' can be a next day. To use it properly parse your dates in "HH:mm" formant.
public static final boolean isBetweenValidTime(Date startTime, Date endTime, Date validateTime)
{
boolean validTimeFlag = false;
if(endTime.compareTo(startTime) <= 0)
{
if(validateTime.compareTo(endTime) < 0 || validateTime.compareTo(startTime) >= 0)
{
validTimeFlag = true;
}
}
else if(validateTime.compareTo(endTime) < 0 && validateTime.compareTo(startTime) >= 0)
{
validTimeFlag = true;
}
return validTimeFlag;
}
Java 8 - LocalDateTime
What about this?
final LocalDateTime now = LocalDateTime.now();
final LocalDateTime minRange = LocalDateTime.of(now.getYear(), now.getMonth(), now.getDayOfMonth(), 22, 30); //Today, 10:30pm
LocalDateTime maxRange = LocalDateTime.of(now.getYear(), now.getMonth(), now.getDayOfMonth(), 6, 30); //Tomorrow, 6:30am
maxRange = maxRange.plusDays(1); //Ensures that you don't run into an exception if minRange is the last day in the month.
if (now.isAfter(minRange) && now.isBefore(maxRange)) {
//Action
}
Using LocalTime would simply ignore the Date value:
public class TimeIntervalChecker {
static final LocalTime time1 = LocalTime.parse( "20:11:13" ) ;
static final LocalTime time2 = LocalTime.parse( "14:49:00" ) ;
public static void main(String[] args) throws java.lang.Exception {
LocalTime nowUtcTime = LocalTime.now(Clock.systemUTC());
if (nowUtcTime.isAfter(time1) && nowUtcTime.isBefore(time2)){
System.out.println(nowUtcTime+" is after: "+ time1+" and before: "+ time2);
}
}
After reading a few replies, I feel the writing is too complicated. Try my code
public static boolean compare(String system_time, String currentTime, String endtimes) {
try {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("HH:mm:ss");
Date startime = simpleDateFormat.parse("19:25:00");
Date endtime = simpleDateFormat.parse("20:30:00");
//current time
Date current_time = simpleDateFormat.parse("20:00:00");
if (current_time.after(startime) && current_time.before(endtime)) {
System.out.println("Yes");
return true;
}
else if (current_time.after(startime) && current_time.after(endtime)) {
return true; //overlap condition check
}
else {
System.out.println("No");
return false;
}
} catch (ParseException e) {
e.printStackTrace();
}
return false;
}
As with the help of #kocko, the complete working code is as below:
try{
Date time11 = new SimpleDateFormat("HH:mm:ss").parse("20:11:13");
Calendar calendar1 = Calendar.getInstance();
calendar1.setTime(time11);
Date time22 = new SimpleDateFormat("HH:mm:ss").parse("14:49:00");
Calendar calendar2 = Calendar.getInstance();
calendar2.setTime(time22);
Date currentTime = new SimpleDateFormat("HH:mm:ss").parse("00:00:00");
Calendar startingCalendar = Calendar.getInstance();
startingCalendar.setTime(currentTime);
startingCalendar.add(Calendar.DATE, 1);
//let's say we have to check about 01:00:00
String someRandomTime = time1;
Date d = new SimpleDateFormat("HH:mm:ss").parse(someRandomTime);
Calendar calendar3 = Calendar.getInstance();
calendar3.setTime(d);
if(startingCalendar.getTime().after(calendar1.getTime()))
{
calendar2.add(Calendar.DATE, 1);
calendar3.add(Calendar.DATE, 1);
}
Date x = calendar3.getTime();
if (x.after(calendar1.getTime()) && x.before(calendar2.getTime()))
{
System.out.println("Time is in between..");
}
else
{
System.out.println("Time is not in between..");
}
} catch (ParseException e)
{
e.printStackTrace();
}
Sounds to me that your problem is an OR situation... You want to check if time1 > 20:11:13 OR time1 < 14:49:00.
There will never be a time greater to 20:11:13 that exceeds your range through the other end (14:49:00) and viceversa. Think of it as if you are checking that a time is NOT between a properly ordered couple of timestamps.
The Actual working function will be as follows
public static boolean isTimeBetweenTwoTime(Date startTime, Date stopTime, Date currentTime) {
//Start Time
Calendar StartTime = Calendar.getInstance();
StartTime.setTime(startTime);
//Current Time
Calendar CurrentTime = Calendar.getInstance();
CurrentTime.setTime(currentTime);
//Stop Time
Calendar StopTime = Calendar.getInstance();
StopTime.setTime(stopTime);
if (stopTime.compareTo(startTime) < 0) {
if (CurrentTime.compareTo(StopTime) < 0) {
CurrentTime.add(Calendar.DATE, 1);
}
StopTime.add(Calendar.DATE, 1);
}
return CurrentTime.compareTo(StartTime) >= 0 && CurrentTime.compareTo(StopTime) < 0;
}
In your case the starting time (20:11:13) is larger than the ending time (14:49:00). It is a reasonable assumption that you could solve the problem by adding a day on the ending time or subtracting a day from the starting time. if you do so, you will be trapped because you do not know on which day the testing time is.
You can avoid this trap by checking whether your testing time is between the ending time and starting time. If true, then result is "not in between"; else result is "well in between".
Here is the function in JAVA I have been using. It works so far for me. Good luck.
boolean IsTimeInBetween(Calendar startC, Calendar endC, Calendar testC){
// assume year, month and day of month are all equal.
startC.set(1,1,1);
endC.set(1,1,1);
testC.set(1,1,1);
if (endC.compareTo(startC) > 0) {
if ((testC.compareTo(startC)>=0) && (testC.compareTo(endC)<=0)) {
return true;
}else {
return false;
}
}else if (endC.compareTo(startC) < 0) {
if ((testC.compareTo(endC) >= 0) && (testC.compareTo(startC) <= 0)) {
return false;
} else {
return true;
}
} else{ // when endC.compareTo(startC)==0, I return a ture value. Change it if you have different application.
return true;
}
}
To create a Calender instance you can use:
Calendar startC = Calendar.getInstance();
startC.set(Calendar.HOUR_OF_DAY, 20);
startC.set(Calendar.MINUTE,11);
startC.set(Calendar.SECOND,13);
In the code snipet below, it is being verified that if the current time (can be any) exists between start and end time or not:
Calendar startTimeCal = Calendar.getInstance();
startTimeCal.setTime(startTime);
int startTimeHour = startTimeCal.get(Calendar.HOUR_OF_DAY);
if (startTimeHour == 0){
startTimeHour = 24;
}
int startTimeMinutes = startTimeCal.get(Calendar.MINUTE);
Calendar curTimeCal = Calendar.getInstance();
curTimeCal.setTime(currentTime);
int curTimeHour = curTimeCal.get(Calendar.HOUR_OF_DAY);
int curTimeMinutes = curTimeCal.get(Calendar.MINUTE);
Calendar endTimeCal = Calendar.getInstance();
endTimeCal.setTime(endTime);
int endTimeHour = endTimeCal.get(Calendar.HOUR_OF_DAY);
if (endTimeHour == 0) {
endTimeHour = 24;
}
int endTimeMinutes = endTimeCal.get(Calendar.MINUTE);
if (((curTimeHour > startTimeHour) || (curTimeHour == startTimeHour && curTimeMinutes >= startTimeMinutes)) &&
((curTimeHour < endTimeHour) || (curTimeHour == endTimeHour && curTimeMinutes <= endTimeHour))) {
//time exists between start and end time
} else {
//time doesn't exist between start and end time
}
As many people noticed, it's not a date problem, it's a logic problem.
Let's assume a day is splitted in two intervals: one lies between 20:11:13 and 14:49:00, while the other lies between 14:49:00 and 20:11:13 (which interval the extremes belong is up to you).
If you want to check if a certain time is included in the 20:11:13/14:49:00 one, the one you're interested of, just check if it's included in the other one, 14:49:00/20:11:13, which is much easier because the natural order of the numbers, and then negate the result.
I did it this way:
LocalTime time = LocalTime.now();
if (time.isAfter(LocalTime.of(02, 00)) && (time.isBefore(LocalTime.of(04, 00))))
{
log.info("Checking after 2AM, before 4AM!");
}
Edit:
String time1 = "01:00:00";
String time2 = "15:00:00";
LocalTime time = LocalTime.parse(time2);
if ((time.isAfter(LocalTime.of(20,11,13))) || (time.isBefore(LocalTime.of(14,49,0))))
{
System.out.println("true");
}
else
{
System.out.println("false");
}
Here is a solution that uses the new Java 8 classes, is compact, requires no regular expressions or manual arithmetic operations. My solution is coded for inclusive startTime and exclusive endTime, but can easily be modified for your needs.
private boolean isTimeBetween(String timeToTest, String startTime, String endTime) {
LocalTime timeToTestDt = LocalTime.parse(timeToTest, DateTimeFormatter.ISO_LOCAL_TIME);
LocalTime startTimeDt = LocalTime.parse(startTime, DateTimeFormatter.ISO_LOCAL_TIME);
LocalTime endTimeDt = LocalTime.parse(endTime, DateTimeFormatter.ISO_LOCAL_TIME);
if(startTime.equals(endTime)) {
return false;
}
else if(startTimeDt.isBefore(endTimeDt)) { // Period does not cross the day boundary
return (timeToTest.equals(startTime) || timeToTestDt.isAfter(startTimeDt))
&& timeToTestDt.isBefore(endTimeDt);
} else { // Time period spans two days, e.g. 23:00 to 2:00
return (!((timeToTestDt.isAfter(endTimeDt) || timeToTest.equals(endTime))
&& timeToTestDt.isBefore(startTimeDt)));
}
}
// getTimeSpans() from the original question would then look like this
public void getTimeSpans()
{
boolean firstTime = isTimeBetween("01:00:00", "20:11:13", "14:49:00");
boolean secondTime = isTimeBetween("05:00:00", "20:11:13", "14:49:00");
}
Simple solution for all gaps:
public boolean isNowTimeBetween(String startTime, String endTime) {
LocalTime start = LocalTime.parse(startTime);//"22:00"
LocalTime end = LocalTime.parse(endTime);//"10:00"
LocalTime now = LocalTime.now();
if (start.isBefore(end))
return now.isAfter(start) && now.isBefore(end);
return now.isBefore(start)
? now.isBefore(start) && now.isBefore(end)
: now.isAfter(start) && now.isAfter(end);
}
I've implemented it in kotlin, and it's works as expected:
fun isInBetween(startTime: String, endTime: String, checkTime: String, timeFormat: String = "HH:mm:ss"): Boolean {
val calendar1 = Calendar.getInstance().apply {
time = SimpleDateFormat(timeFormat, Locale.ENGLISH).parse(startTime)!!
add(Calendar.DATE, 1)
}
val calendar2 = Calendar.getInstance().apply {
time = SimpleDateFormat(timeFormat, Locale.ENGLISH).parse(endTime)!!
add(Calendar.DATE, 1)
}
val calendar3 = Calendar.getInstance().apply {
time = SimpleDateFormat(timeFormat, Locale.ENGLISH).parse(checkTime)!!
add(Calendar.DATE, 1)
}
if(calendar1.time > calendar2.time) {
calendar2.add(Calendar.DATE, 2)
calendar3.add(Calendar.DATE, 2)
}
val x = calendar3.time
return (x.after(calendar1.time) && x.before(calendar2.time))
}
And it's result as followings:
Log.d("TAG", "08:00, 22:00, 13:40: ${isInBetween("08:00", "22:00", "13:40")}") // true
Log.d("TAG", "22:00, 08:00, 13:40: ${isInBetween("22:00", "08:00", "13:40")}") // false
Log.d("TAG", "22:00, 08:00, 05:40: ${isInBetween("22:00", "08:00", "05:40")}") // true
Log.d("TAG", "22:00, 08:00, 10:40: ${isInBetween("22:00", "08:00", "10:40")}") // false
Log.d("TAG", "22:00, 22:00, 22:10: ${isInBetween("22:00", "22:00", "22:10")}") // false
In my situation, I'm not interested at all in date times.
So this is my solution which works solely on hours as integers:
boolean isInTimeRange(int startingHour, int endingHour, int hourOfDayToCheck) {
if (endingHour > startingHour) {
return hourOfDayToCheck >= startingHour && hourOfDayToCheck < endingHour;
} else {
return hourOfDayToCheck >= startingHour || hourOfDayToCheck < endingHour;
}
}
LocalTime now = LocalTime.now();
LocalTime startTime = LocalTime.parse("23:00:00");
LocalTime endTime = LocalTime.parse("05:00:00");
if (startTime.isAfter(endTime)) {
return !(now.isAfter(endTime) && now.isBefore(startTime));
} else {
return (now.isAfter(startTime) && now.isBefore(endTime));
}
The below solution should help in cases where StartTime is from the Previous Day, and EndTime is from the next day, and you want to check something in between.
boolean isInBetween = false;
if (endLocalTime.isAfter(startLocalTime)) {
if (!startLocalTime.isAfter(checkLocalTime) && endLocalTime.isAfter(checkLocalTime)) {
isInBetween = true;
}
} else if (checkLocalTime.isAfter(startLocalTime) || !checkLocalTime.isAfter(endLocalTime)) {
isInBetween = true;
}
return isInBetween;
}
strip colons from the $time, $to and $from strings, convert to int and then use the following condition to check if the time is between from and to. Example is in php, but shouldn't matter.
if(($to < $from && ($time >= $from || $time <= $to)) ||
($time >= $from && $time <= $to)) {
return true;
}
Logically if you do the following you should always be ok granted we use military time...
if start time is greater than end time add 24 to end time
else use times as is
compare current time to be inbetween start and end time.
Based on the ideas and solutions of most authors here, I'd like to share my refined solution with a presumably cleaner code:
/**
* Checks if some date is within a time window given by start and end dates
*
* #param checkDate - date to check if its hours and minutes is between the startDate and endDate
* #param startDate - startDate of the time window
* #param endDate - endDate of the time window
* #return - returns true if hours and minutes of checkDate is between startDate and endDate
*/
public static boolean isDateBetweenStartAndEndHoursAndMinutes(Date checkDate, Date startDate, Date endDate) {
if (startDate == null || endDate == null)
return false;
LocalDateTime checkLdt = LocalDateTime.ofInstant(Instant.ofEpochMilli(checkDate.getTime()), ZoneId.systemDefault());
LocalDateTime startLdt = LocalDateTime.ofInstant(Instant.ofEpochMilli(startDate.getTime()), ZoneId.systemDefault());
LocalDateTime endLdt = LocalDateTime.ofInstant(Instant.ofEpochMilli(endDate.getTime()), ZoneId.systemDefault());
// Table of situations:
// Input dates: start (a), end (b), check (c)
// Interpretations:
// t(x) = time of point x on timeline; v(x) = nominal value of x
// Situation A - crossing midnight:
// c INSIDE
// 1) t(a) < t(c) < t(b) | v(b) < v(a) < v(c) // e.g. a=22:00, b=03:00, c=23:00 (before midnight)
// 2) t(a) < t(c) < t(b) | v(c) < v(b) < v(a) // e.g. a=22:00, b=03:00, c=01:00 (after midnight)
// c OUTSIDE
// 3) t(c) < t(a) < t(b) | v(b) < v(c) < v(a) // e.g. a=22:00, b=03:00, c=21:00
// 4) t(a) < t(b) < t(c) | v(b) < v(c) < v(a) // e.g. a=22:00, b=03:00, c=04:00
// ^--- v(b) < v(a) always when shift spans around midnight!
// Situation B - after/before midnight:
// c INSIDE
// 1) t(a) = t(c) < t(b) | v(a) = v(c) < v(b) // e.g. a=06:00, b=14:00, c=06:00
// 2) t(a) < t(c) < t(b) | v(a) < v(c) < v(b) // e.g. a=06:00, b=14:00, c=08:00
// c OUTSIDE
// 3) t(c) < t(a) < t(b) | v(c) < v(a) < v(b) // e.g. a=06:00, b=14:00, c=05:00
// 4) t(a) < t(b) = t(c) | v(a) < v(b) = v(c) // e.g. a=06:00, b=14:00, c=14:00
// 5) t(a) < t(b) < t(c) | v(a) < v(b) < v(c) // e.g. a=06:00, b=14:00, c=15:00
// ^--- v(a) < v(b) if shift starts after midnight and ends before midnight!
// Check for situation A - crossing midnight?
boolean crossingMidnight = endLdt.isBefore(startLdt);
if (crossingMidnight) {
// A.1
if ((startLdt.isBefore(checkLdt) || startLdt.isEqual(checkLdt)) // t(a) < t(c)
&& checkLdt.isBefore(endLdt.plusDays(1))) // t(c) < t(b+1D)
return true;
// A.2
if (startLdt.isBefore(checkLdt.plusDays(1)) // t(a) < t(c+1D)
&& checkLdt.isBefore(endLdt)) // t(c) < t(b)
return true;
// A.3
if (startLdt.isBefore(endLdt.plusDays(1)) // t(a) < t(b+1D)
&& checkLdt.isBefore(startLdt)) // t(c) < t(a)
return false;
// A.4
if (startLdt.isBefore(endLdt.plusDays(1)) // t(a) < t(b+1D)
&& checkLdt.isAfter(endLdt)) // t(b) < t(c)
return false;
} else {
// B.1 + B.2
if ((startLdt.isEqual(checkLdt) || startLdt.isBefore(checkLdt)) // t(a) = t(c) || t(a) < t(c)
&& checkLdt.isBefore(endLdt)) // t(c) < t(b)
return true;
}
return false;
}
For the sake of completeness I've added the conditions of A.3 and A.4, but in productive code you can leave it out.
Now you can simply create your start and end dates, as well as your time you want to check and call this static method. The code would go then as follows:
Date check = new SimpleDateFormat("HH:mm:ss").parse("01:00:00");
Date start = new SimpleDateFormat("HH:mm:ss").parse("20:11:13");
Date end = new SimpleDateFormat("HH:mm:ss").parse("14:49:00");
if (isDateBetweenStartAndEndHoursAndMinutes(check, start, end)) {
Print("checkDate is within start and End date!"); // adjust this true condition to your needs
}
For the TDD aspect I've added unit tests for the scenarios A and B as given above. Please feel free to check it out and report back if you find any errors or spots for optimization.
import org.junit.jupiter.api.Test;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
class LogiqDateUtilsTest {
private LocalDateTime startShiftSituationALdt = LocalDateTime.of(0, 1, 1, 22, 0);
private Date startOfShiftSituationA = Date.from(startShiftSituationALdt.atZone(ZoneId.systemDefault()).toInstant());
private LocalDateTime endShiftSituationALdt = LocalDateTime.of(0, 1, 1, 3, 0);
private Date endOfShiftSituationA = Date.from(endShiftSituationALdt.atZone(ZoneId.systemDefault()).toInstant());
private LocalDateTime startShiftSituationBLdt = LocalDateTime.of(0, 1, 1, 6, 0);
private Date startOfShiftSituationB = Date.from(startShiftSituationBLdt.atZone(ZoneId.systemDefault()).toInstant());
private LocalDateTime endShiftSituationBLdt = LocalDateTime.of(0, 1, 1, 14, 0);
private Date endOfShiftSituationB = Date.from(endShiftSituationBLdt.atZone(ZoneId.systemDefault()).toInstant());
#Test
void testSituationA1() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 23, 0);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertTrue(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationA, endOfShiftSituationA));
}
#Test
void testSituationA2() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 1, 0);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertTrue(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationA, endOfShiftSituationA));
}
#Test
void testSituationA3() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 21, 1);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertFalse(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationA, endOfShiftSituationA));
}
#Test
void testSituationA4() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 4, 1);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertFalse(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationA, endOfShiftSituationA));
}
#Test
void testSituationB1() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 6, 0);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertTrue(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationB, endOfShiftSituationB));
}
#Test
void testSituationB2() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 8, 0);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertTrue(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationB, endOfShiftSituationB));
}
#Test
void testSituationB3() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 5, 0);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertFalse(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationB, endOfShiftSituationB));
}
#Test
void testSituationB4() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 14, 0);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertFalse(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationB, endOfShiftSituationB));
}
#Test
void testSituationB5() {
LocalDateTime checkLdt = LocalDateTime.of(0, 1, 1, 15, 0);
Date checkBetween = Date.from(checkLdt.atZone(ZoneId.systemDefault()).toInstant());
assertFalse(isDateBetweenStartAndEndHoursAndMinutes(checkBetween, startOfShiftSituationB, endOfShiftSituationB));
}
}
Cheers!
/**
* #param initialTime - in format HH:mm:ss
* #param finalTime - in format HH:mm:ss
* #param timeToCheck - in format HH:mm:ss
* #return initialTime <= timeToCheck < finalTime
* #throws IllegalArgumentException if passed date with wrong format
*/
public static boolean isTimeBetweenTwoTime(String initialTime, String finalTime, String timeToCheck) throws IllegalArgumentException {
String reg = "^([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
if (initialTime.matches(reg) && finalTime.matches(reg) && timeToCheck.matches(reg)) {
SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss", Locale.getDefault());
Date inTime = parseDate(dateFormat, initialTime);
Date finTime = parseDate(dateFormat, finalTime);
Date checkedTime = parseDate(dateFormat, timeToCheck);
if (finalTime.compareTo(initialTime) < 0) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(finTime);
calendar.add(Calendar.DAY_OF_YEAR, 1);
finTime = calendar.getTime();
if (timeToCheck.compareTo(initialTime) < 0) {
calendar.setTime(checkedTime);
calendar.add(Calendar.DAY_OF_YEAR, 1);
checkedTime = calendar.getTime();
}
}
return (checkedTime.after(inTime) || checkedTime.compareTo(inTime) == 0) && checkedTime.before(finTime);
} else {
throw new IllegalArgumentException("Not a valid time, expecting HH:MM:SS format");
}
}
/**
* #param initialTime - in format HH:mm:ss
* #param finalTime - in format HH:mm:ss
* #return initialTime <= now < finalTime
* #throws IllegalArgumentException if passed date with wrong format
*/
public static boolean isNowBetweenTwoTime(String initialTime, String finalTime) throws IllegalArgumentException {
return isTimeBetweenTwoTime(initialTime, finalTime,
String.valueOf(DateFormat.format("HH:mm:ss", new Date()))
);
}
private static Date parseDate(SimpleDateFormat dateFormat, String data) {
try {
return dateFormat.parse(data);
} catch (ParseException e) {
throw new IllegalArgumentException("Not a valid time");
}
}
This worked for me:
fun timeBetweenInterval(
openTime: String,
closeTime: String
): Boolean {
try {
val dateFormat = SimpleDateFormat(TIME_FORMAT)
val afterCalendar = Calendar.getInstance().apply {
time = dateFormat.parse(openTime)
add(Calendar.DATE, 1)
}
val beforeCalendar = Calendar.getInstance().apply {
time = dateFormat.parse(closeTime)
add(Calendar.DATE, 1)
}
val current = Calendar.getInstance().apply {
val localTime = dateFormat.format(timeInMillis)
time = dateFormat.parse(localTime)
add(Calendar.DATE, 1)
}
return current.time.after(afterCalendar.time) && current.time.before(beforeCalendar.time)
} catch (e: ParseException) {
e.printStackTrace()
return false
}
}
Based on Konstantin_Yovkov answer I would like to share my implementation which checks if current time will be in between given START and END time.
This implementation assumes that if given END time is 'before' the START time, then END must be meant to be tomorrow:
public static boolean currentTimeInBetween(String start, String end)
throws ParseException {
// start = "15:25";
java.util.Date starttime = new SimpleDateFormat("HH:mm").parse(start);
Calendar startcal = Calendar.getInstance();
startcal.setTime(starttime);
// end = "14:00";
java.util.Date endtime = new SimpleDateFormat("HH:mm").parse(end);
Calendar endcal = Calendar.getInstance();
endcal.setTime(endtime);
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
java.util.Date currenttime = dateFormat
.parse(dateFormat.format(new java.util.Date()));
Calendar currentcal = Calendar.getInstance();
currentcal.setTime(currenttime);
// If endTime < startTime, assume that endTime is 'tomorrow'
if (startcal.after(endcal)) {
endcal.add(Calendar.DATE, 1);
}
// System.out.println("START" + " System Date: " + startcal.getTime());
// System.out.println("END" + " System Date: " + endcal.getTime());
// System.out.println("Current" + " System Date: " + currentcal.getTime());
java.util.Date current = currentcal.getTime();
if (current.after(startcal.getTime())
&& current.before(endcal.getTime())) {
return true;
} else {
return false;
}
}
Solution function written in Kotlin
/**
* #param currentTime : Time to compare
* #param startTime: Start Hour in format like 10:00:00
* #param endTime: End Hour in format like 15:45:00
*/
fun isTimeInBetweenHours(currentDate: Date, startTime: String, endTime: String): Boolean {
val simpleDateFormat = SimpleDateFormat("HH:mm:ss", Locale.US)
try {
val startTimeCalendar = Calendar.getInstance()
startTimeCalendar.time = simpleDateFormat.parse(startTime)
startTimeCalendar.add(Calendar.DATE, 1)
val endTimeCalendar = Calendar.getInstance()
endTimeCalendar.time = simpleDateFormat.parse(endTime)
endTimeCalendar.add(Calendar.DATE, 1)
val currentTime = simpleDateFormat.format(currentDate) //"01:00:00"
val currentTimeCalendar = Calendar.getInstance()
currentTimeCalendar.time = simpleDateFormat.parse(currentTime)
currentTimeCalendar.add(Calendar.DATE, 1)
val x = currentTimeCalendar.time
return x.after(startTimeCalendar.time) && x.before(endTimeCalendar.time)
} catch (e: ParseException) {
return false
}
}
The formatter only takes HH:mm:ss, so it's agnostic of date. All the dates are computed as 1st Jan 1970 being the epoch start date. Hence the comparison of time happens with only the time as the date for all the cases here is 1st Jan 1970.
Note: Used legacy Java API's instead of the newer ones (LocalTime and DateTimeFormatter) since these newer API's are not supported on older devices like Android below version Oreo. If you are using some other platform where you can get the updated API's, please use them as they are more optimised and less buggy.