Java 8 Time API / Is current time in time frame [duplicate] - java

Please suggest if there is an API support to determine if my time is between 2 LocalTime instances, or suggest a different approach.
I have this entity:
class Place {
LocalTime startDay;
LocalTime endDay;
}
which stores the working day start and end time, i.e. from '9:00' till '17:00', or a nightclub from '22:00' till "5:00".
I need to implement a Place.isOpen() method that determines if the place is open at a given time.
A simple isBefore/isAfter does not work here, because we also need to determine if the end time is on the next day.
Of course, we can compare the start and end times and make a decision, but I want something without additional logic, just a simple between() call. If LocalTime is not sufficient for this purpose, please suggest other.

If I understand correctly, you need to make two cases depending on whether the closing time is on the same day as the opening time (9-17) or on the next day (22-5).
It could simply be:
public static boolean isOpen(LocalTime start, LocalTime end, LocalTime time) {
if (start.isAfter(end)) {
return !time.isBefore(start) || !time.isAfter(end);
} else {
return !time.isBefore(start) && !time.isAfter(end);
}
}

This looks cleaner for me:
if (start.isBefore(end)) {
return start.isBefore(date.toLocalTime()) && end.isAfter(date.toLocalTime());
} else {
return date.toLocalTime().isAfter(start) || date.toLocalTime().isBefore(end);
}

I have refactored #assylias answer so i use int instead of local time as i get open and close hour from api int integer format
public static boolean isOpen(int start, int end, int time) {
if (start>end) {
return time>(start) || time<(end);
} else {
return time>(start) && time<(end);
}
}
public static boolean isOpen(int start, int end) {
SimpleDateFormat sdf = new SimpleDateFormat("HH");
Date resultdate = new Date();
String hour = sdf.format(resultdate);
int time = Integer.valueOf(hour);
if (start>end) {
return time>(start) || time<(end);
} else {
return time>(start) && time<(end);
}
}

Related

How do I determine if a time entered into a text field falls within the range of two pre-established opening and closing times?

The opening and closing hours for the company are 8am to 10 pm. The code below seems to add 4 hours on to whatever time is entered into the text field. So if I change the opening time to 11:59 I get the correct 8 am start date, but it's not possible to change the end time to 26:01 so I can't get the end time to work correctly. The data has to be stored in the database in UTC, but for display purposes it's displayed in EST.
public static boolean insideBusinessHours(String startTime, String endTime, String date) {
LocalDateTime localStart = stringToLDT_UTC(startTime, date);
LocalDateTime localEnd = stringToLDT_UTC(endTime, date);
String UTCstart = localStart.toString().substring(11,16);
String UTCend = localEnd.toString().substring(11,16);
LocalTime enteredStart = LocalTime.parse(UTCstart);
LocalTime enteredEnd = LocalTime.parse(UTCend);
LocalTime openingHour = LocalTime.of(07, 59);
LocalTime closingHour = LocalTime.of(22, 1);
Boolean startTimeAllowed = enteredStart.isAfter(openingHour);
Boolean endTimeAllowed = enteredEnd.isBefore(closingHour);
if (startTimeAllowed && endTimeAllowed) {
return true;
}
else {
return false;
}
}
public static LocalDateTime stringToLDT_UTC(String time, String date) {
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime ldt = LocalDateTime.parse(date + " " + time, format)
.atZone(ZoneId.systemDefault())
.withZoneSameInstant(ZoneId.of("UTC"))
.toLocalDateTime();
return ldt;
}
Even though dates and times need to be stored in UTC, I believe that it makes more sense to do the comparisons in your local time.
private static final LocalTime OPENING_HOUR = LocalTime.of(8, 0);
private static final LocalTime CLOSING_HOUR = LocalTime.of(22, 0);
public static boolean insideBusinessHours(String startTime, String endTime) {
LocalTime start = LocalTime.parse(startTime);
LocalTime end = LocalTime.parse(endTime);
boolean startTimeAllowed = !start.isBefore(OPENING_HOUR);
boolean endTimeAllowed = !end.isAfter(CLOSING_HOUR);
return startTimeAllowed && endTimeAllowed;
}
Further comments:
You don’t need the date if the opening hours are valid every day (you would need it to convert to or from UTC, which I have avoided).
It seems you had added a minute in each end to make sure to allow start and end to fall on the opening and closing hour, respectively. It’s more correct to require the start time to fall on or after the opening time. Similarly the end time before or on the closing time. In the code I am using not before to mean on or after.
In Java integer literals with a leading 0 are interpreted as octal. So don’t use a leading 0 unless you intended octal. You may find that 07 for the hour of the day looks nice. but you will get a surprise when 08 does not work. And in a different context, your users could get a pretty unpleasant surprise when for example 0700 does work but denotes 448.
Don’t use Boolean objects. Don’t ever if you can avoid it since the risk of a null reference to a Boolean is confusing and from experience often leads to errors. Use primitive boolean (lower case b).
Most seasoned programmers prefer return startTimeAllowed && endTimeAllowed; as terser than your if-else statement.
Link
Octal on Wikipedia.

Check if current date date is within current month

I'm aware there are several similiar questions. But mine is different in two points
Usage of java.util.* classes only (our server currently operates only with those)
I need to determine whether given date is after the specified date OR represents same day (typically today)
This is what I got:
if ((new Date().getMonth() == object.getDate().getMonth() && new Date().getYear() == object.getDate().getYear()
&& new Date().getDay() == object.getDate().getDay())
|| (new Date().after(object.getDate()) && new Date().getMonth() == object.getDate().getMonth()
&& new Date().getYear() == object.getDate().getYear()))
This thing works, but let's be honest - doesn't look really elegant. Is there way to do this in prettier way?
if you want to use your solution, it's anyway worth optimizing it. For example, create new Date() only once. Also to make it more readable and shorter, extract object.getDate() as a variable above all these comparisons. One more way to solve your problem can be:
public static void main(String[] args) {
Calendar min = getMinDateOfMonth();
Calendar max = getMinDateOfMonth();
max.set(Calendar.MONTH, min.get(Calendar.MONTH) + 1);
if (min.getTime().before(object.getDate()) && max.getTime().after(object.getDate())) {
// you're inside the month
}
}
private static Calendar getMinDateOfMonth() {
Calendar min = Calendar.getInstance();
min.set(Calendar.DAY_OF_MONTH, 1);
min.set(Calendar.HOUR, 0);
min.set(Calendar.MINUTE, 0);
min.set(Calendar.SECOND, 0);
min.set(Calendar.MILLISECOND, 0);
return min;
}

Converting 24 format to 12 format with updateDisplay()

I was asked to only used the updateDisplay() method to change the format for the hour in this clockDisplay, eveythings works perfectly the hour can get to 12:59PM and use the method timeTick() it gets to 1:00PM but after using timeTick() again it goes to 1:01AM again. How can i fix this problem?
public class ClockDisplay
{
private NumberDisplay hours;
private NumberDisplay minutes;
private String displayString;
public ClockDisplay()
{
hours = new NumberDisplay(24);
minutes = new NumberDisplay(60);
updateDisplay();
}
public ClockDisplay(int hour, int minute)
{
hours = new NumberDisplay(24);
minutes = new NumberDisplay(60);
setTime(hour, minute);
}
public void timeTick()
{
minutes.increment();
if(minutes.getValue() == 0) { // it just rolled over!
hours.increment();
}
updateDisplay();
}
public void setTime(int hour, int minute)
{
hours.setValue(hour);
minutes.setValue(minute);
updateDisplay();
}
public String getTime()
{
return displayString;
}
private void updateDisplay()
{
int h = hours.getValue()%12;
String format = (hours.getValue()/12 == 0 ? "AM":"PM");
if(h == 0)
{
h = 12;
}
else if(hours.getValue() > 12)
{
hours.setValue(hours.getValue() - 12);
}
displayString = hours.getDisplayValue() + ":" +
minutes.getDisplayValue() + format;
}
}
What’s wrong? When the time reaches 1 PM, your updateDisplay method sets the value of the hours display back to 1. Now your clock display object is back in the state it had at 1 AM, that is, you have no way of distinguishing those two times.
How to fix? I suggest you introduce an instance variable (field) to hold the information whether we are in the AM or PM period of the day. You may use a Boolean variable or introduce an enum with two constants like AM and PM. Then you need to set this variable in the timeTick method and also in your setTime method. Then it will be fairly straightforward to use this variable to decide whether to display the string AM or PM in your updateDisplay method.
If you are asked to do this without adding a new field: then you need to let the hours in the hours display run to 23 so you keep track of whether you are in the AM or PM time of day. So in updateDisplay don’t set the hours value. Only in the display string generated put 12 instead of 0 and 1 through 11 instead of 13 through 23.
For production code: In real life one wouldn’t use a design like yours and would rely heavily on standard library classes for handling time. One would have a clearer separation between model (the current time) and presentation (the string printed). So the current time would be held in a LocalTime:
private LocalTime time;
Ticking the time 1 minut forward:
time = time.plusMinutes(1);
For displaying the time you would use a DateTimeFormatter:
private static final DateTimeFormatter TIME_FORMATTER
= DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT);
With this the display string is created this way:
displayString = time.format(TIME_FORMATTER);
The code is not tested, so forgive if there is a typo.

get count back of DateTime that where within the correct range - Joda Time

I want to get the count back of DateTime that where within the correct range with Joda Time.
I have this version at the moment which is only good to check for a specific day:
public int getIntFatalitiesAtDay(DateTime AtDay) {
int resultCount = 0;
for( Fatality f : fatalities) {
if(Days.daysBetween(f.date, AtDay).getDays() == 0) {
resultCount++;
}
}
return resultCount;
}
This was usefull when i looped threw every day. However now i go by months with:
for (DateTime iDate = fa.firstDate; iDate.isBefore(fa.lastDate); iDate = iDate.plusMonths(1)) { ... }
And now i would like to get the count of fatalities that month.
Could someone help?
(Also from that year, althought i would like to see a option aswell where it doesn't look at the year but that's less important.)
Java's java.util.Date class has methods for determining if one date is before or after another. If you convert the DateTime objects to Date objects, you can do:
if (f.date.after(beginngingDate) && f.date.before(endingDate)).

How to compare two Joda time Periods

It does not seem straighforward.
I am trying this:
#Override
public int compare(Period o1, Period o2) {
return o1.toStandardDays().getDays() > o2.toStandardDays().getDays() ? -1 : (o1.toStandardDays().getDays() == o2.toStandardDays().getDays() ? 0 : 1);
}
But I get this exception:
java.lang.UnsupportedOperationException: Cannot convert to Days as this period contains months and months vary in length
at org.joda.time.Period.checkYearsAndMonths(Period.java:1455)
at org.joda.time.Period.toStandardDays(Period.java:1314)
I hoped Peroid would have an isLongerThan(Period p) method.
From the Joda Documentation:
To compare the actual duration of two periods, convert both to durations using toDuration, an operation that emphasises that the result may differ according to the date you choose.
The two toDuration methods are BasePeriod#toDurationTo(ReadableInstant) and BasePeriod#toDurationFrom(ReadableInstant). This means that you must choose either a start or end instant of this period in order to be able to compute its duration.
If that is a problem for you, then you might want to directly use Duration instead of Period.
As Matt Ball also explained in his answer, to compare 2 periods you need to convert them to a duration first. Durations are relative to a certain point in time, so you need to do something like this:
public static boolean isLonger(Period p1, Period p2) {
Instant now = Instant.now();
Duration d1 = p1.toDurationTo(now);
Duration d2 = p2.toDurationTo(now);
return d1.isLongerThan(d2);
}
public static boolean isShorter(Period p1, Period p2) {
Instant now = Instant.now();
Duration d1 = p1.toDurationTo(now);
Duration d2 = p2.toDurationTo(now);
return d1.isShorterThan(d2);
}
I wrote a method that should be able to compare two Periods to the nearest day (I didn't care about hours and minutes):
private int comparePeriods(Period period1, Period period2)
{
if (period1.getYears() != period2.getYears())
{
return Integer.compare(period1.getYears(), period2.getYears());
}
if (period1.getMonths() != period2.getMonths())
{
return Integer.compare(period1.getMonths(), period2.getMonths());
}
if (period1.getWeeks() != period2.getWeeks())
{
return Integer.compare(period1.getWeeks(), period2.getWeeks());
}
if (period1.getDays() != period2.getDays())
{
return Integer.compare(period1.getDays(), period2.getDays());
}
return 0;
}
Note that this method expects both periods to be normalised or it will not give accurate results.

Categories