Java TimeZone and Linux TimeZone Daylight Savings doesnot match - java

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());
}
}
}
}
}

Related

convert time(12h and 24h)

I'm writing a program that converts the time (12h and 24h).
The result I want to get is the following:
convertTime ("12:00") ➞ "0:00"
convertTime ("6:20 pm") ➞ "18:20"
convertTime ("21:00") ➞ "9:00 pm"
convertTime ("5:05") ➞ "5:05"
this is my code, unfortunately the result is not what I expected, in fact:
A time input of 12 hours will be indicated with an am or pm suffix.
An input time of 24 hours contains no suffix.
I would appreciate a help so much, thanks in advance!
public static String convertTime(String time) {
String hour = time.substring(0, time.indexOf(":"));
String min = time.substring(3, time.indexOf(":") + 3);
int hourInteger = Integer.parseInt(hour);
if (hourInteger > 12 && hourInteger < 24) {
hourInteger = hourInteger - 12;
}
if (hourInteger == 24) {
hourInteger = 0;
}
if (hourInteger < 12) {
return hourInteger + ":" + min + " AM";
}
if (hourInteger > 12)
return hourInteger + ":" + min + " PM";
return hourInteger;
}
You can use below code snippet, you can make additional changes accordingly as your wish. Using Date API to parse vise versa 12 <-> 24 Hours format.
public static String convertTime(String time) throws ParseException {
if (time.contains("am") || time.contains("pm")) {
SimpleDateFormat displayFormat = new SimpleDateFormat("HH:mm");
SimpleDateFormat parseFormat = new SimpleDateFormat("hh:mm a");
Date date = parseFormat.parse(time);
return displayFormat.format(date);
} else {
SimpleDateFormat parseFormat = new SimpleDateFormat("HH:mm");
SimpleDateFormat displayFormat = new SimpleDateFormat("hh:mm a");
Date date = parseFormat.parse(time);
return displayFormat.format(date);
}
}
There were few problems with your code.
One is return hourInteger. As the convertTime() return type is String, you can't return an Integer. To convert it you can use,
String.valueOf(hourInteger);
Second in 24h clock format, there is no 24:00. A minute after 23:59 is 00:00. So,
if (hourInteger == 24) {
should be,
if (hourInteger == 0) {
Third,
if (hourInteger > 12 && hourInteger < 24) {
hourInteger = hourInteger - 12;
}
above code will convert all possible hours larger than 12 to hours smaller than 12. So after that line checking if(hourInteger>12) always returns false.
Below code will work for your situation.
public static String convertTime(String time) {
String hour = time.substring(0, time.indexOf(":"));
String min = time.substring(3, time.indexOf(":") + 3);
int hourInteger = Integer.parseInt(hour);
int newHour = hourInteger;
if (hourInteger > 12 && hourInteger < 24) {
newHour = hourInteger - 12;
}
if (hourInteger==0) {
newHour = 12;
}
if (hourInteger < 12) {
return newHour + ":" + min + " AM";
}else {
return newHour + ":" + min + " PM";
}
}
You can use StringTokenizer to split the string into tokens using delimiters : and , then convert based on number of tokens (2 for 24 hour format, 3 for 12 hour format):
import java.util.*;
public class Main
{
public static String convertTime(String time) {
StringTokenizer sb = new StringTokenizer(time, ": ");
if (sb.countTokens() == 2)
{
// 24 hr to 12 hr
int hour = Integer.parseInt(sb.nextToken());
int min = Integer.parseInt(sb.nextToken());
boolean isEvening = false;
if (hour >= 12 && hour <= 24)
{
hour -= 12;
if (hour != 0)
isEvening = true;
}
return String.format("%02d:%02d %s", hour, min, (isEvening ? "pm" : "am"));
}
else if (sb.countTokens() == 3)
{
// 12 hr to 24 hr
int hour = Integer.parseInt(sb.nextToken());
int min = Integer.parseInt(sb.nextToken());
boolean isEvening = sb.nextToken().equalsIgnoreCase("pm");
if (isEvening || hour == 0)
{
hour += 12;
}
return String.format("%02d:%02d", hour, min);
}
return "";
}
public static void main(String[] args) {
System.out.println(convertTime("12:00"));
System.out.println(convertTime("6:20 pm"));
System.out.println(convertTime("21:00"));
System.out.println(convertTime("5:05"));
}
}

missing second(00) from LocalDateTime.parse

missing second (00) from LocalDateTime.parse
LocalTime time = LocalTime.NOON;
DateTimeFormatter formatTime = DateTimeFormatter.ofPattern("HH:mm:ss");
String value ="20200810" + time.format(formatTime);
LocalDateTime localDateTime = LocalDateTime.parse(value, DateTimeFormatter.ofPattern("yyyyMMddHH:mm:ss"));
LOGS
=========value========== 2020081012:00:00
===localDateTime===2020-08-10T**12:00**
I tried to change LocalTime.NOON to LocalTime.of(12,0,0) too but still same result.
Write the following line into log:
localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
The above line returns a string as per DateTimeFormatter.ISO_LOCAL_DATE_TIME.
You can also specify a custom pattern as per your requirement e.g.
localDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"))
or
localDateTime.format(DateTimeFormatter.ofPattern("yyyyMMddHH:mm:ss"))
If you print localDateTime directly, it will print the string returned by toString method of LocalDateTime.
Note that since the second part in the time, 12:00:00 is 00, the default toString implementation of LocalDateTime ignores the second part.
For your reference, given below is the toString() implementation of LocalDateTime:
#Override
public String toString() {
return date.toString() + 'T' + time.toString();
}
and given below the toString() implementation of LocalTime:
#Override
public String toString() {
StringBuilder buf = new StringBuilder(18);
int hourValue = hour;
int minuteValue = minute;
int secondValue = second;
int nanoValue = nano;
buf.append(hourValue < 10 ? "0" : "").append(hourValue)
.append(minuteValue < 10 ? ":0" : ":").append(minuteValue);
if (secondValue > 0 || nanoValue > 0) {
buf.append(secondValue < 10 ? ":0" : ":").append(secondValue);
if (nanoValue > 0) {
buf.append('.');
if (nanoValue % 1000_000 == 0) {
buf.append(Integer.toString((nanoValue / 1000_000) + 1000).substring(1));
} else if (nanoValue % 1000 == 0) {
buf.append(Integer.toString((nanoValue / 1000) + 1000_000).substring(1));
} else {
buf.append(Integer.toString((nanoValue) + 1000_000_000).substring(1));
}
}
}
return buf.toString();
}
As you can see, the second and nano parts are included only when their values are greater than 0.

Schedule assignment, Java current time between to times that are parse from a schedule

I'm new here and I already have a question.
I'm making a assignment for school (in Processing with Java), we are loading a schedule from a txt file.
And I need to make a visualisation from it, it's going good but I'm stuck at one point.
I want to make a if statement, to see if the current time is between the Start time and end time. I did parse the start time and End time from the txt file and I can call the current time. But i can't find or know the if statement. can someone help?
Parts of my code ( i can't show everything because i have 6 tabs) :
**//From the main tab**
int s = second(); // Values from 0 - 59
int mi = minute(); // Values from 0 - 59
int h = hour(); // Values from 0 - 23
int d = day(); // Values from 1 - 31
int mo = month(); // values from 1 - 12
int y = year();
// searching all data from Table, comparing location with roomsTTH, if its the same check iff itint(random(20)), 20's free
for (TableRow singleRow : tableRooster.rows()) {
ParseInfo parse = new ParseInfo(singleRow);
for (Room roomToCheck : roomsTTH) {
if (parse.location == roomToCheck.id) {
if (roomToCheck.available) {
if ( y == parseInt(parse.year)) {
if (mo == parseInt(parse.month)) {
if ( d == parseInt(parse.day)) {
// if ( isBetween = currentTime.after(parse.startTime) && currantTime.before(parse.endTime)) {
// occupied = true;
// Floor.maxRooms ++;
}
}
}
}
}
}
}
// }
**//From tab Parse**
//StartTime
String startTime;
//EndTime
String endTime;
TableRow myTableRow;
ParseInfo(TableRow tableRow) {
parseRow(tableRow);
}
// Parse data into variables
void parseRow(TableRow row) {
// Divide the parse location to level and room
this.location = row.getString("Location");
this.level = this.location.substring(5, 6);
this.room = this.location.substring(8, 9);
// Divide the parse start date to year, month, day
this.date = row.getString("Start date");
this.day = this.date.substring(9, 10);
this.month = this.date.substring(6, 7);
this.year = this.date.substring(0, 3);
// Parse Start time & End time
this.startTime = row.getString("Start time");
this.endTime = row.getString("End time");
}
}
It looks like your dates are stored as String values. String values don't have a concept of whether they are before or after each other, so you have to do the comparison yourself. You have two options:
Option 1: Compare the String values alphabetically. Something like this:
String date1 = "2015/10/24";
String date2 = "2015/10/25";
if(date1.compareTo(date2) < 0){
//date 1 is before date2
}
else if(date1.compareTo(date2) > 0){
//date 1 is after date2
}
else{
//they are the same date
}
Option 2: If that won't work for some reason (if the dates are in different formats, for example), then you can use Java's SimpleDateFormat class to parse the date Strings into Date objects. Something like this:
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd");
Date date1 = sdf.parse("2015/10/24");
Date date2 = sdf.parse("2015/10/25");
if(date1.before(date2)){
//date 1 is before date2
}
else if(date1.after(date2)){
//date 1 is after date2
}
else{
//they are the same date
}

How to determine a date in between Friday and Sunday of the week at a particular time

I'm trying to check a current date and time is in between Friday 17:42 and Sunday 17:42 of the week with Java.
At the moment I'm doing this with really really bad code block. It was a hurry solution. Now I'm refactoring but I couldn't find any method in joda or etc.
Any ideas?
Thanks
private final Calendar currentDate = Calendar.getInstance();
private final int day = currentDate.get(Calendar.DAY_OF_WEEK);
private final int hour = currentDate.get(Calendar.HOUR_OF_DAY);
private final int minute = currentDate.get(Calendar.MINUTE);
if (day != 1 && day != 6 && day != 7) {
if (combined != 0) {
return badge == 1;
} else {
return badge == product;
}
} else {
if (day == 6 && hour > 16) {
if (hour == 17 && minute < 43) {
if (combined != 0) {
return badge == 1;
} else {
return badge == product;
}
} else {
return badge == 0;
}
} else if (day == 6 && hour < 17) {
if (combined != 0) {
return badge == 1;
} else {
return badge == product;
}
} else if (day == 1 && hour > 16) {
if (hour == 17 && minute < 43) {
return badge == 0;
} else {
if (combined != 0) {
return badge == 1;
} else {
return badge == product;
}
}
} else {
return badge == 0;
}
}
I've used the solution like thiswith the help of #MadProgrammer and #Meno Hochschild
Method:
public static boolean isBetween(LocalDateTime check, LocalDateTime startTime, LocalDateTime endTime) {
return ((check.equals(startTime) || check.isAfter(startTime)) && (check.equals(endTime) || check.isBefore(endTime))); }
Usage:
static LocalDateTime now = LocalDateTime.now();
static LocalDateTime friday = now.with(DayOfWeek.FRIDAY).toLocalDate().atTime(17, 41);
static LocalDateTime sunday = friday.plusDays(2).plusMinutes(1);
if (!isBetween(now, friday, sunday)) { ... }
Thanks again for your efforts.
Date and Calendar have methods that can perform comparisons on other instances of Date/Calendar, equals, before and after
However, I'd encourage the use of Java 8's new Time API
public static boolean isBetween(LocalDateTime check, LocalDateTime startTime, LocalDateTime endTime) {
return ((check.equals(startTime) || check.isAfter(startTime)) &&
(check.equals(endTime) || check.isBefore(endTime)));
}
Which will return true if the supplied LocalDateTime is within the specified range inclusively.
Something like...
LocalDateTime start = LocalDateTime.now();
start = start.withDayOfMonth(26).withHour(17).withMinute(42).withSecond(0).withNano(0);
LocalDateTime end = start.plusDays(2);
LocalDateTime check = LocalDateTime.now();
System.out.println(check + " is within range = " + isBetween(check, start, end));
check = start;
System.out.println(check + " is within range = " + isBetween(check, start, end));
check = end;
System.out.println(check + " is within range = " + isBetween(check, start, end));
check = start.plusDays(1);
System.out.println(check + " is within range = " + isBetween(check, start, end));
check = end.plusMinutes(1);
System.out.println(check + " is within range = " + isBetween(check, start, end));
Which outputs
2015-06-25T18:31:32.969 is within range = false
2015-06-26T17:42 is within range = true
2015-06-28T17:42 is within range = true
2015-06-27T17:42 is within range = true
2015-06-28T17:43 is within range = false
Joda-Time has an Interval class which makes it even eaiser
Interval targetInterval = new Interval(targetStart, targetEnd);
System.out.println("Contains interval = " + interval.contains(targetInterval)
which is demonstrated here
A different approach...
So I was thinking on way home, assuming all you have is the date/time you want to check, how you might determine if the day falls within your range
LocalDateTime now = LocalDateTime.now();
boolean isBetween = false;
switch (now.getDayOfWeek()) {
case FRIDAY:
case SATURDAY:
case SUNDAY:
LocalDateTime lastFriday = getLastFriday(now);
LocalDateTime nextSunday = getNextSunday(now);
isBetween = isBetween(now, lastFriday, nextSunday);
System.out.println(lastFriday + " - " + nextSunday + ": " + end);
break;
}
What this does is checks the dayOfWeek to see if it's within the desired range, if it is, it finds the previous Friday and next Sunday from the specified date and checks to see if it falls between them (see the previous example)
lastFriday and nextSunday simply adds/subtracts a day from the specified date/time until to reaches the desired dayOfWeek, it then seeds the required time constraints
public static LocalDateTime getLastFriday(LocalDateTime anchor) {
LocalDateTime ldt = LocalDateTime.from(anchor);
return ldt.with(DayOfWeek.FRIDAY).withHour(17).withMinute(42).withSecond(0).withNano(0);
}
public static LocalDateTime getNextSunday(LocalDateTime anchor) {
LocalDateTime ldt = LocalDateTime.from(anchor);
return ldt.with(DayOfWeek.SUNDAY).withHour(17).withMinute(42).withSecond(0).withNano(0);
}
With Calendar you can know what DAY_OF_WEEK is the given date, then simply check the hours:
Calendar c = Calendar.getInstance();
int dayOfWeek = c.get(Calendar.DAY_OF_WEEK);
int hour = c.get(Calendar.HOUR_OF_DAY);
int minute = c.get(Calendar.MINUTE);
// in friday the hour must be greater than 17:42
if (dayOfWeek == 5 && ((hour > 17) || (hour == 17 && minute >= 42)) {
// successss!!
}
// days from 1 to 7... saturday(6) all day
if (dayOfWeek == 6) {
// successss!!
}
// sunday hour must be lower than 17:42
if (dayOfWeek == 7 && ((hour < 17) || (hour == 17 && minute <= 42)) {
// successss!!
}
A better solution using old Java would look like this:
// current timestamp
GregorianCalendar gcal = new GregorianCalendar();
// specify ISO-week (you are searching for friday until sunday in this order)
gcal.setMinimalDaysInFirstWeek(4);
gcal.setFirstDayOfWeek(Calendar.MONDAY);
// sunday at 17:43
GregorianCalendar sunday = (GregorianCalendar) gcal.clone();
sunday.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
sunday.set(Calendar.HOUR_OF_DAY, 17);
sunday.set(Calendar.MINUTE, 43);
sunday.set(Calendar.SECOND, 0);
sunday.set(Calendar.MILLISECOND, 0);
// friday at 17:42
GregorianCalendar friday = (GregorianCalendar) sunday.clone();
friday.add(Calendar.DATE, -2);
friday.add(Calendar.MINUTE, -1);
// logging for test purposes
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
System.out.println(f.format(friday.getTime()));
System.out.println(f.format(gcal.getTime()));
System.out.println(f.format(sunday.getTime()));
// result (assumption: half-open-interval)
boolean withinTimeWindow = !gcal.before(friday) && gcal.before(sunday);
Java-8 offers a shorter approach (assuming ISO-weekmodel):
LocalDateTime now = LocalDateTime.now();
LocalDateTime friday = now.with(DayOfWeek.FRIDAY).toLocalDate().atTime(17, 42);
LocalDateTime sunday = friday.plusDays(2).plusMinutes(1);
boolean withinTimeWindow = !now.isBefore(friday) && now.isBefore(sunday);
Finally your equivalent evaluation can look like this:
if (!withinTimeWindow) {
if (combined != 0) {
return badge == 1;
} else {
return badge == product;
}
} else {
return badge == 0;
}

Check if a given time lies between two times regardless of date

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.

Categories