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 check if a period of time(consisting of two temporal timevalues(start and end)) passes for example midnight ?
Im trying to use the LocalDateTime class, but can't seem to find anything usefull there..
This is the best I can come up with:
public static boolean passesTime(LocalDateTime start,
LocalDateTime end,
LocalTime time) {
// If the duration is more than a day, any time will be passed.
if (Duration.between(start, end).toDays() >= 1)
return true;
// Otherwise, the time has to be passed on the start day...
LocalDateTime timeOnStartDay = LocalDateTime.of(start.toLocalDate(), time);
if (timeOnStartDay.isAfter(start) && timeOnStartDay.isBefore(end))
return true;
// or on the end day.
LocalDateTime timeOnEndDay = LocalDateTime.of(end.toLocalDate(), time);
if (timeOnEndDay.isAfter(start) && timeOnEndDay.isBefore(end))
return true;
return false;
}
Tested with the java.time API. If you're using Joda time the code should be similar (if not identical).
I'm about to write lines of some simple math and wanted to make sure that there wasn't some simple high level construct in Joda-Time to do this already.
I have an object that represents a day of the week, an hour of the day, and a minute of the hour. For example "Wednesday at 10:14am".
I want to calculate the number of milliseconds until the next occurrence. For example if now is Thursday at 10:14 it would be 6 days worth of milliseconds. This is because Wednesday has already passed so it will take 6 days to get to the next Wednesday. If now is Wednesday at 10:13.0001 it will be 999.
Is there a high level construct in Joda-Time so I can do this in one or two lines of code or do I need to do the math myself (including edge cases to wrap on stuff like DOW < DOW_NOW).
Thanks!
Here's my novice try that does not yet work to give you some reference:
public MutableDateTime getDateTime() {
MutableDateTime date = MutableDateTime.now();
date.setDayOfWeek(this.day);
date.setHourOfDay(this.hour);
return date;
}
public long getTimeUntilNextFrom( DateTime from ) {
MutableDateTime to = getDateTime();
if (to.isBefore( from )) {
to.setWeekOfWeekyear(from.getWeekOfWeekyear() + 1);
}
return new Interval(from, to).toDurationMillis();
}
You could do something like this:
import org.joda.time.DateTime;
import org.joda.time.DateTimeConstants;
import org.joda.time.Interval;
import org.joda.time.LocalTime;
public class Main {
public static void main(String[] args) {
Interval interval = betweenNowAndNext(DateTimeConstants.MONDAY, new LocalTime(10, 14));
System.out.println(interval.toDurationMillis());
}
public static Interval betweenNowAndNext(int dayOfWeek, LocalTime time) {
DateTime now = DateTime.now();
DateTime closest = time.toDateTime(now).withDayOfWeek(dayOfWeek);
return new Interval(now, closest.isBefore(now) ? closest.plusWeeks(1) : closest);
}
}
I would do it like this:
public class DistanceCalculator {
public long getMillisecondTillNext(int dayOfWeek, int hourOfDay, int minuteOfHour) {
DateTime now = DateTime.now();
DateTime next = DateTime.now().withDayOfWeek(dayOfWeek).withHourOfDay(hourOfDay).withMinuteOfHour(minuteOfHour);
long distance = next.getMillis() - now.getMillis();
return distance > 0 ? distance : week() - distance;
}
private long week() {
return new DateTime(0).plusWeeks(1).getMillis();
}
}
Haven't hear of any readymade method to get this in Joda...
Here's what I came up with on my own. Still, would be nice to have a solution in fewer lines of code. They DayHour is the class I am working with. It contains a day of the week and the hour of the day.
public class DayHour {
int day;
int hour;
public DayHour(int day, int hour) {
this.day = day;
this.hour = hour;
}
public MutableDateTime getDateTime(DateTime base) {
MutableDateTime date = base.toMutableDateTime();
date.setDayOfWeek(this.day);
date.setHourOfDay(this.hour);
return date;
}
public long getTimeUntilNextFrom(DateTime from) {
MutableDateTime to = getDateTime(from);
if (to.isBefore(from)) {
to.setWeekOfWeekyear(from.getWeekOfWeekyear() + 1);
}
return new Interval(from, to).toDurationMillis();
}
}
#Test
public void testDayHour() {
DateTime now = DateTime.now();
DayHour date = new DayHour(now.getDayOfWeek(), now.getHourOfDay());
MutableDateTime yesterday = now.toMutableDateTime();
yesterday.addDays(-1);
assertEquals(TimeUnit.DAYS.toMillis(1), date.getTimeUntilNextFrom(yesterday.toDateTime()));
MutableDateTime tomorrow = now.toMutableDateTime();
tomorrow.addDays(1);
assertEquals(TimeUnit.DAYS.toMillis(6), date.getTimeUntilNextFrom(tomorrow.toDateTime()));
}
Not quite sure what you are doing. But if what you want is a countdown in milliseconds, I would use the Joda-Time Seconds class with its secondsBetween method. Multiply by 1,000 to report approximate milliseconds. On the last second, switch gears to use the .getMillis method if you truly need that.
For example, I have input parameter this format: "04:00-06:00" or "23:00-24:00". Type of parameter - String.
And in my method I must check, that time range in input parameter NOT before current time. How I can do it?
More details:
input time range: "12:00-15:00"
current time: 16:00.
In this case, method must return false.
Another example:
input time range: "10:30-12:10"
current time: 09:51.
method must return true.
Can you please give me some idea or algorithm? How I can implement this method?
First off, you should probably just learn to use Joda time.
That said, since the times are all zero padded, you can just compare strings lexically.
public static boolean inRange(String time, String range) {
return time.compareTo(range.substring(0, 5)) >= 0
&& time.compareTo(range.substring(6)) <= 0;
}
It's good practice to fail fast on malformed inputs.
private static final Pattern VALID_TIME = Pattern.compile("[012][0-9]:[0-5][0-9]");
private static final Pattern VALID_RANGE = Pattern.compile("[012][0-9]:[0-5][0-9]-[012][0-9]:[0-5][0-9]");
and then put an assert at the top of inRange:
assert VALID_TIME.matcher(time).matches() : time
assert VALID_RANGE.matcher(range).matches() : range
EDIT:
If you really need to represent the current time as a Date, then you should compare it this way:
public final class Range {
/** Inclusive as minutes since midnight */
public final int start, end;
public Range(int start, int end) {
assert end >= start;
}
/** #param time in minutes since midnight */
public boolean contains(int time) {
return start <= time && time <= end;
}
public static Range valueOf(String s) {
assert VALID_RANGE.matcher(s).matches() : s;
return new Range(minutesInDay(s.substring(0, 5)),
minutesInDay(s.substring(6));
}
private static int minutesInDay(String time) {
return Integer.valueOf(time.substring(0, 2)) * 60
+ Integer.valueOf(time.substring(3));
}
}
Use Range.valueOf to convert from a String, convert your Date to a number of minutes since midnight in whatever timezone you like using whatever calendar implementation you like, and then use Range.contains.
Date currentDate = new Date();
Date maxDate;
Date minDate;
//Parse range to two substrings
//parse two substrings to [HH, MM]
//for HH && MM parseInt()
//
minDate= new Date.SetHour(HH); minDate.SetMinute(MM);
//repeat for max date
if(currentDate.Before(maxDate) && currentDate.After(minDate))
{
return true;
}
else
return false;
I am trying to get a date range using Guava's new Range functionality, via
Range<Date> dateRange = Ranges.range(start, BoundType.CLOSED, end, BoundType.CLOSED);
My goal is to get the hours in this date range. So I have created a DiscreteDomain like such:
private static final DiscreteDomain<Date> HOURS = new DiscreteDomain<Date>() {
public Date next(Date value) {
return addHours(value, 1);
}
private Date addHours(Date value, int i) {
Calendar cal = Calendar.getInstance();
cal.setTime(value);
cal.add(Calendar.HOUR_OF_DAY, i);
return cal.getTime();
}
public Date previous(Date value) {
return addHours(value, -1);
}
public long distance(Date start, Date end) {
Calendar cal1 = Calendar.getInstance();
cal1.setTime(start);
Calendar cal2 = Calendar.getInstance();
cal2.setTime(end);
return cal2.getTimeInMillis() - cal1.getTimeInMillis();
}
public Date minValue() {
return new Date(Long.MIN_VALUE);
}
public Date maxValue() {
return new Date(Long.MAX_VALUE);
}
};
If I merely sysout the output, I get the closed set
[Thu Feb 24 00:00:00 EST 2011..Thu Feb 24 00:02:00 EST 2011]
I really want to see each hour in the range, however, so I try a for loop:
for (Date hour : hours) {
System.out.println(hour);
}
When running this block, I seem to get an infinite set, beginning at the left side of the range, but not stopping at the right side, making me kill the IDE. What am I doing wrong?
I think this might be due to the behavior of the Iterator returned by the ContiguousSet (returned by Range.asSet()):
#Override public UnmodifiableIterator<C> iterator() {
return new AbstractLinkedIterator<C>(first()) {
final C last = last();
#Override
protected C computeNext(C previous) {
return equalsOrThrow(previous, last) ? null : domain.next(previous);
}
};
}
private static boolean equalsOrThrow(Comparable<?> left,
#Nullable Comparable<?> right) {
return right != null && compareOrThrow(left, right) == 0;
}
private static int compareOrThrow(Comparable left, Comparable right) {
return left.compareTo(right);
}
It only stops when the next computed value is equal to the right bound of the range.
In your case, have you tried calling it using Thu Feb 24 02:00:00 instead of Thu Feb 24 00:02:00 for the right bound of your range?
I think this behavior is problematic, and it might be worth asking if equalsOrThrow() could be changed to check for left <= right instead of left == right
Also, your distance() method is incorrect. It should return the distance in hours, not in milliseconds, according to the method contract.
EDIT
All this being said, I believe the real problem is that, according to the DiscreteDomain's javadoc:
A discrete domain always represents
the entire set of values of its type;
it cannot represent partial domains
such as "prime integers" or "strings
of length 5."
In your case, you are attempting to create a discrete domain over hourly dates, which is a partial domain of all dates. This is, I think, the root cause of the problem. When you have a partial domain, the equalsOrThrow method becomes unreliable, and it can "miss" the right bound of your range.
I just tried this and it worked fine for me. #eneveu already pointed out the issue with your distance method as well. I'm also guessing that there's some minor difference at the millisecond level between start and end which means that you'll never actually get a Date equal to end by adding hours to start.
However, that's all just symptoms of using the classes in a way they aren't designed to work. The Javadoc for DiscreteDomain states:
A discrete domain always represents the entire set of values of its type; it cannot represent partial domains such as "prime integers" or "strings of length 5."
A DiscreteDomain of "hours" does not represent the domain of all possible Date objects and as such breaks its contract.
I've a code to get year, month and day for one of my application.
package com.cera.hyperionUtils;
import java.util.*;
public class HypDate {
public static int curdate(int field)
{
//1. Specify integer 1 for YEAR, 2 for MONTH, 5 DAY_OF_MONTH
Calendar c = new GregorianCalendar();
c.setLenient(true); //Allow overflow
//2. Extract and Return result
if (field == 2) {
field = c.get(Calendar.MONTH) + 1;
}
return c.get(field);
}
public static void main(String[] args)
{
System.out.println(HypDate.curdate(2));
}
}
But when i pass 2 it is giving 0 year and day prints correctly.....Also i was trying to make month as double digit. (like 01 for 1)
Can someone please help me....? (I''m very new to java coding)
Rather than returning these one by one, you may just want to use a SimpleDateFormat to format it.
Say I want a date as year-month-day:
// Necessary imports
import java.text.DateFormat;
import java.text.SimpleDateFormat;
// Declare class and stuff before this
public static String getFormattedDate() {
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
return df.format(new Date());
}
public static void main(String[] args) {
System.out.println(getFormattedDate());
}
Outputs 2010-10-29
Edit:
Since you just want the month, you can do this:
public static String getFormattedMonth() {
DateFormat df = new SimpleDateFormat("MM");
return df.format(new Date());
}
if (field == 2) {
field = c.get(Calendar.MONTH) + 1;
}
return c.get(field);
You retrieve the correct month as an index and then use that index to retrieve another field that will be unknown and related in how the constants are saved. Just return the value before, without using a second get.
Maybe you meant
if (field == 2) {
field = Calendar.MONTH;
}
return c.get(field) + 1;
but I don't get why you are redefining that constants instead that use the one already provided..
The problem comes from the fact that when you are getting the month information, you call c.get() twice, which you don't want to do. Instead, you should directly return after you get the first value
//1. Specify integer 1 for YEAR, 2 for MONTH, 5 DAY_OF_MONTH
Calendar c = new GregorianCalendar();
c.setLenient(true); //Allow overflow
//2. Extract and Return result
if (field == Calendar.MONTH) {
return c.get(field) + 1; //because Java months are 0-based
} else {
return c.get(field);
}