Find out if a series of dates covering an interval - java

I have two objects calendar
Calendar startCalendar = new GregorianCalendar(2013,0,31);
Calendar endCalendar = new GregorianCalendar();
I want to know if the interval between the two dates listed above is covered by n of other objects pair calendars without holes between intervals
Example1:
Calendar startCalendar1(2013,0,31);
Calendar endCalendar1(2014,0,31);
Calendar startCalendar2(2013,5,31);
Calendar endCalendar2();
Is GOOD
Example2:
Calendar startCalendar1(2013,0,31);
Calendar endCalendar1(2014,0,31);
Calendar startCalendar2(2014,2,31);
Calendar endCalendar2();
NOT GOOD
I use Java 6
Thanks

First approach: Only using Java 6
When I see your date examples like 2015-01-31 then I get the strong suspicion that you speak about closed date intervals otherwise choosing the end of a month might appear a little bit strange. This is a wide spread and reasonable approach. Unfortunately choosing a data type like java.util.Calendar representing an instant (also a date-time-zone-combo, too) is not in harmony with closed intervals. Such instant-like types work better with half-open intervals. The consequence is:
If you decide to use only Java-6-types then you can try to convert all Calendar-objects to Long-values representing the elapsed millisecs since Unix epoch as suggested by #guillaume girod-vitouchkina (has got my upvote as an example how to do this without any external library) . But you have to add an extra day to every single Calendar-object (if representing an end boundary) in advance to achieve the effect of closed date intervals.
And of course, you have still to do some home grown interval arithmetic yourself as shown in that answer in a sketchy way. If you carefully study the other proposals and your own requirements you will find that the final solution even requires more than just a new interval class or basic comparisons of intervals. You will also need a higher abstraction layer, namely defined operations between several intervals. Doing this all yourself might cause some headache. On the other hand: Implementing a Long-based interval arithmetic might save some performance overhead as typical for an extra interval library if you have good programming skills.
Second approach: Using a dedicated interval library
I only know four libraries which promise to handle intervals. Threeten-Extra as mentioned by #Basil Bourque cannot be used because it requires Java-8. Its interval class has the disadvantage to handle instants only, but not calendar dates. There is also almost no support for handling collections of intervals. The same can be said for Joda-Time (which is at least working on Java-6 and also offers a dedicated calendar date type, namely LocalDate but no date intervals).
An interesting option is using Guava and its class RangeSet, especially if you decide to continue using Calendar-objects and Longs. This class has some support for handling operations between intervals - for me much more appealing than using the simple interval class of Joda-Time.
Finally you also have the option to use my library Time4J which has the range-package. I will show now a complete solution for your problem:
// our test interval
PlainDate start = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate end = SystemClock.inLocalView().today();
DateInterval test = DateInterval.between(start, end);
IntervalCollection<PlainDate> icTest = IntervalCollection.onDateAxis().plus(test);
// two intervals for your GOOD case
PlainDate s1 = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate e1 = PlainDate.of(2014, Month.JANUARY, 31);
DateInterval i1 = DateInterval.between(s1, e1);
PlainDate s2 = PlainDate.of(2013, Month.MAY, 31);
PlainDate e2 = end; // today
DateInterval i2 = DateInterval.between(s2, e2);
IntervalCollection<PlainDate> goodCase =
IntervalCollection.onDateAxis().plus(i1).plus(i2);
boolean covered = icTest.minus(goodCase).isEmpty();
System.out.println("Good case: " + covered); // true
// two intervals for your BAD case
PlainDate s3 = PlainDate.of(2013, Month.JANUARY, 31);
PlainDate e3 = PlainDate.of(2014, Month.JANUARY, 31);
DateInterval i3 = DateInterval.between(s3, e3);
PlainDate s4 = PlainDate.of(2014, Month.MARCH, 31);
PlainDate e4 = end; // today
DateInterval i4 = DateInterval.between(s4, e4);
IntervalCollection<PlainDate> badCase =
IntervalCollection.onDateAxis().plus(i3).plus(i4);
covered = icTest.minus(badCase).isEmpty();
System.out.println("Bad case: " + covered); // false
The biggest part of code is just interval construction. The real interval arithmetic itself is done by this surprisingly small code fragment:
boolean covered =
IntervalCollection.onDateAxis().plus(test).minus(
IntervalCollection.onDateAxis().plus(i1).plus(i2)
).isEmpty();
Explanation: The test interval is covered by intervals i1 and i2 if the remainder of the subtraction of i1 and i2 from test is empty.
By the way: Date intervals in Time4J are closed intervals by default. You can change these intervals to half open intervals however if you really want (simply by calling withOpenEnd() on a given date interval).
And if you plan to migrate to Java-8 later, you can just update the Time4J-version to version line 4.x (version v3.x is for Java-6) and get very easy conversions to Java-8 types like java.time.LocalDate (for example: PlainDate.from(localDate) or LocalDate ld = plainDate.toTemporalAccessor()) so you can continue to use Time4J for extra features not covered by standard Java even in the future.

1 Rude but simple method
Use a Set< Long>
Set<Long> all_times_in_milli=new HashSet<Long>();
// Put every interval
// interval 1
for (long time_in_millis=startCalendar1.getTimeInMillis();
time_in_millis<= endCalendar1.getTimeInMillis();
time_in_millis+=86400000)
all_times_in_milli.add(time_in_millis);
// interval 2
for (long time_in_millis=startCalendar2.getTimeInMillis();
time_in_millis<= endCalendar2.getTimeInMillis();
time_in_millis+=86400000)
all_times_in_milli.add(time_in_millis);
// ETC
// AND TEST !
boolean failed=false;
for (long time_in_millis=startCalendar.getTimeInMillis();
time_in_millis<= endCalendar.getTimeInMillis();
time_in_millis+=86400000)
{
if (all_times_in_milli.contains(time_in_millis))
{
failed=true; break;
}
}
if (failed) System.out.println("Your are done !");
2 SMARTER METHOD
As every interval is an [long - long] interval
assemble your intervals to get continuous intervals (sets of overlaping intervals) => then you get B1-E1, B2-E2, B3-E3 distincts intervals
check if you first interval is inside of of them: B1 <= start <= end <=E1,
or B2 <= start <= end <=E2, ...
interesting only if you have a lot of datas

You using old date-time classes that have been supplanted by the java.time framework in Java 8 and later. Those old classes have proven to be clunky, confusing, and flawed.
java.time
The new java.time classes are inspired by the highly successful Joda‑Time library, intended as its successor, similar in concept but re-architected. Defined by JSR 310. Extended by the ThreeTen‑Extra project. See the Tutorial.
The new classes include LocalDate for a date-only value without time-of-day. For your purpose, use this instead of Calendar.
Note that month numbers sensibly start from one, unlike Calendar.
LocalDate start = LocalDate.of( 2013 , 1 , 31 );
Note that in order to determine a date the time zone is crucial. The date is not simultaneously the same around the world. A new day dawns earlier in Paris than Montréal, for example.
ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate today = LocalDate.now ( zoneId );
From there you can call any combination of isAfter, isBefore, or isEqual to do your logic. Your Question is not clear exactly about that logic, so I cannot address that.
The ThreeTen-Extra project that extends java.time includes an Interval class that would help you. Unfortunately that class works only with Instant objects (date-time in UTC), not LocalDate. Specifically the methods for comparing intervals would help, abuts, encloses, and overlaps.
You would whip up your own IntervalLD class for LocalDate objects. Usually I do not recommend rolling your own date-time handling classes because date-time work is surprisingly tricky. But in this case with LocalDate the logic might simple. Here is my quick rough-draft completely untested example to get you started.
package com.example.javatimestuffmaven;
import java.time.LocalDate;
/**
* Similar to the 'Interval'class in the ThreeTen-Extra project, but for LocalDate objects.
*
* #author Basil Bourque
*/
public class IntervalLD {
private LocalDate start, end;
// Constructor
public IntervalLD ( LocalDate startArg , LocalDate endArg ) {
this.start = startArg;
this.end = endArg;
}
public Boolean isBefore ( IntervalLD interval ) {
// True if this one's end is before that one's start.
boolean before = this.getEnd ().isBefore ( interval.getStart () );
return before;
}
public Boolean isAfter ( IntervalLD interval ) {
// True if this one's start is after that one's end.
boolean after = this.getStart ().isAfter ( interval.getStart () );
return after;
}
public Boolean abuts ( IntervalLD interval ) {
// True if the intervals are next to each other on the time line but do not share a date. (exclusive of each other, not half-open)
// True if either one's end is a day ahead of the other's start or vice versa, either's start is day after the other's end.
if ( this.isBefore ( interval ) ) {
if ( this.getEnd ().plusDays ( 1 ).equals ( interval.getStart () ) ) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
} else if ( this.isAfter ( interval ) ) {
if ( this.getStart ().minusDays ( 1 ).equals ( interval.getEnd () ) ) {
return Boolean.TRUE;
} else {
return Boolean.FALSE;
}
} else if ( this.isEqual ( interval ) ) {
return Boolean.FALSE;
}
// Impossible. Should never reach this point.
// TODO: Handle this error condition.
return Boolean.FALSE;
}
public Boolean encloses ( IntervalLD interval ) {
//This checks if the specified interval is fully enclosed by this interval.
// The result is true if the start of the specified interval is contained in this interval, and
// the end is contained or equal to the end of this interval.
boolean thatOneStartsOnOrAfterThisOne = ! interval.getStart ().isBefore ( this.getStart () );
boolean thatOneEndsOnOrAfterThisOne = ! interval.getEnd ().isAfter ( this.getEnd () );
boolean doesEnclose = ( thatOneStartsOnOrAfterThisOne && thatOneEndsOnOrAfterThisOne );
return doesEnclose;
}
public Boolean overlaps ( IntervalLD interval ) {
// True if the two intervals share some part of the timeline.
// True if this interval does NOT start after that one ends OR this interval does NOT end before that one starts.
boolean startsTooLate = this.getStart ().isAfter ( interval.getEnd () );
boolean endsTooEarly = this.getEnd ().isAfter ( interval.getEnd () );
boolean doesOverlap = ( ! startsTooLate && ! endsTooEarly );
return ( doesOverlap );
}
public Boolean isEqual ( IntervalLD interval ) {
boolean sameStart = this.getStart ().isEqual ( interval.getStart () );
boolean sameEnd = this.getEnd ().isEqual ( interval.getEnd () );
return ( sameStart && sameEnd );
}
#Override
public String toString () {
String output = this.getStart () + "/" + this.getEnd ();
return output;
}
// Getters. Read-only (immutable) so no Setters.
/**
* #return the start
*/
public LocalDate getStart () {
return this.start;
}
/**
* #return the end
*/
public LocalDate getEnd () {
return this.end;
}
}

Related

How to code new appointments in a planner to be arranged by date

I was tasked with creating an appointment planner in Java. I have everything done except I am having trouble with making the dates of new appointments be sorted by date.
I have tried switching the order around but no matter what I cannot get new appointments to be sorted properly by date.
{"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"};
int ind1 = 0,ind2 = 0;
for(int i=0;i<12;i++) {
if(monthArray[i].equalsIgnoreCase(month)) {
ind1=i;
}
if(monthArray[i].equalsIgnoreCase(app.getMonth())) {
ind2=i;
}
}
if(ind1<ind2) {
return 1;
}
else if(ind1==ind2) {
if(this.day<app.getDay()) {
return 1;
}
else if(this.getDay()>app.getDay()) {
return -1;
}
else {
if(this.getHour()<app.getHour()) {
return 1;
}
else if(this.getHour()>app.getHour()) {
return -1;
}
else {
if(this.getMin()<app.getMin()) {
return 1;
}
else if(this.getMin()>app.getMin()) {
return -1;
}
else {
return 0;
}
}
}
}
else {
return -1;
}
}
}
I expect new appointments to be sorted by date but they are not.
Time Zone
A proper appointment system must account for the fact that politicians around the world have shown a proclivity for redefining the time zone(s) under their juridiction. They do so surprisingly often, and with little or no warning.
So your Appointment class should carry two member fields:
LocalDateTime to hold the date and the time of day. Note that this does not represent a moment, is not a point on the timeline. If it holds a value of 3 PM on January 23rd next year, we don’t know if that means 3 PM in Tokyo, Kolkata, Paris, or Montreal — all different moments, several hours apart.
ZoneId for the time zone in which we intend that 3 PM appointment.
Example:
LocalDate ld = LocalDate.of( 2020 , Month.JANUARY , 23 ) ;
LocalTime lt = LocalTime.of( 15 , 0 ) ;
this.localDateTime = LocalDateTime.of( ld , lt ) ;
this.zoneId = ZoneId.of( "America/Los_Angeles" ) ;
Sorting
For sorting purposes, your class can implement the Comparable interface, with the required compareTo method.
The trick is that you want the 3 PM appointments on the east coast of the US, for example, to sort above the 3 PM appointments of the west coast which occur a few hours later.
So the compareTo method must dynamically calculate a moment, determine a specific point on the timeline. Then, compare the moments of the various Appointment objects to sort properly.
First step is being sure that your JVM has been updated with the latest rules about the time zones. Remember, as mentioned above, these change quite often. Updates to Java will often include an update to the “tzdata” zone information. If a time zone you care about has changed more recently, you may need to update the tzdata yourself.
Next step is dynamically applying the zone to the date-time to determine a moment. Apply the ZoneId to the LocalDateTime to get a ZonedDateTime.
ZonedDateTime zdt = this.localDateTime.atZone( this.zoneId ) ;
Adjust that to UTC. Extract a Instant object, always in UTC by definition.
Instant thisInstant = zdt.toInstant() ;
Compare the Instant of this Appointment object with the other one passed to your compareTo. We can, in turn, call the Instant::compareTo method to do the work of actually comparing.
return thisInstant.compareTo( other.localDateTime.atZone( other.zoneId ).toInstant() ) ;
Alternatively, you might choose to use Objects.compare.
Java has a DateTime library that could be very helpful, but I'm assuming you don't want that seeing as you're doing it manually.
https://dzone.com/articles/java-comparable-interface-in-five-minutes
I'd recommend reading something like that, which gives a little bit of information about comparables. This allows you to create a method doing what you're doing, comparing two objects to each other. Then you can use a lot of standard solutions such as Collections.sort in order to test out and use your code more easily.
I'm not sure if that's what you're already doing so i thought I'd throw it out there.
But for the actual problem, the best solution is funnily enough using an inbuilt function.
Integer.compareTo(int a, int b) will compare two integers for you. All you're doing is repeatedly comparing integers. You can run your code like
int comp = Integer.compare(monthA, monthB;
if(comp != 0) return comp;
//proceed with rest of comparisons the same way you did the months
If you are getting appointment date then why dont you directing comparing them instead of comparing month ,date and time.
Though you can simply convert your appointment date to valid date object as below.
String sDate1="31/12/1998";
Date date1=new SimpleDateFormat("dd/MM/yyyy").parse(sDate1);
System.out.println(sDate1+"\t"+date1);
Reference link : https://www.javatpoint.com/java-string-to-date
Then simply compare date object
if (date1.compareTo(date2) > 0) {
some opertaion...
}
Reference link : https://www.mkyong.com/java/how-to-compare-dates-in-java/
Hope this will help you.

check if this hours is available

I have a question.
I am new and I need help with this.
I have an array of lessons in training room, each lesson has date, and time for ex.
KICKBOXING Lesson in on 01/05/2016 from 16:00 to 18:00.
Now i am making a method, that adds a lesson to this array.
but, I have to make sure, while adding a new lesson, that in this lesson's Date and time, I need to make sure that the room is not busy.
I mean that there is no other lesson in has the same date and time.
how should i check that?
I though about a way like this:
but did not work
public boolean checkDate(Date date)
{
for (int i = 0;i<Lesson.length;i++)
if(Lesson[i].getStartDate().getHours() == date.getHours() && Lesson[i].getStartDate().getMinutes() == date.getMinutes())
{
return true;
}
return false;
}
public boolean addLessons(Lesson les)
{
for(int i = 0; i < Lesson.length; i++)
if(les.getRoom().getRoomType() != E_Rooms.GYM && Lesson[i] != null && checkDate(les.getStartDate())== false)
{
for(int a = 0; i<Lesson.length;i++)
if(Lesson[i]==null)
{
Lesson[a] = les;
return true;
}
}
thank you.
I think that this should work
public boolean checkDate(Date beginDate, Date endDate){
for (int i = 0;i<Lesson.length;i++)
if(Lesson[i].getBeginDate() < endDate || Lesson[i].getEndDate() > beginDate){
return false;
}
return true;
}
Try this :
for (int i = 0;i<Lesson.length;i++)
if(Lesson[i].getBeginDate() == beginDate || Lesson[i].getEndDate() == endDate){
return false; //means there's a class in this date/time }
else
return true; // there's no class in this time. do something..
java.time
The troublesome legacy date-time classes have been supplanted by the java.time framework built into Java 8 and later.
Interval
Those classes are further extended by the ThreeTen-Extra project. That project’s classes include the Interval class that may be of use to you. An Interval represents a span of time between a pair of Instant objects. An Instant is a moment on the timeline in UTC with a resolution of nanoseconds. The Interval class has handy methods for comparing: abuts, contains, overlaps, encloses.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt1 = ZonedDateTime.of( LocalDate.of( 2016 , 1 , 2 ) , LocalTime.of( 16 , 0 , 0 ) , zoneId );
Instant start1 = zdt1.toInstant();
Instant stop1 = zdt1.plusHours( 2 ).toInstant(); // 18:00:00.0 = ( 16:00:00.0 + 2 hours ).
Interval reservation1 = Interval.of( start1 , stop1 );
A look to the class doc shows that you can create an Interval with use of a Duration. This might be handy for you.
Duration duration = Duration.of( 2 , ChronoUnit.HOURS );
Interval reservation = Interval( zdt.toInstant() , duration );
You could collect instances of Interval objects, each representing a reservation. Additional Interval objects can be compared to the already-collected objects to see if they overlap.
boolean res1OverlapsRes2 = reservation1.overlaps( reservation2 );
If you are certain reservations do not roll over midnight, you might create a Map with LocalDate as the Key and a collection of that date’s Interval objects collection as the Value. For any ZonedDateTime, call toLocalDate to get a LocalDate object to do lookup in the Map. With that date’s collection of Intervals, loop to see if the Interval being added overlaps with any of the pre-existing Interval objects.
The java.time and ThreeTen-Extra classes use the Half-Open approach where a span of time is defined with the beginning being inclusive while the ending is exclusive. Search for "half-open" to learn more.

Java: when setting a date in a Calendar object, can I use day/month/year references?

I'm pretty new to Java world, and I'm practicing a lot.
My last exercize is about an Apartment Renting program. My question refers to the "booking" part in the Manager class, in which I have to check if the requested arrival date is linked to the low, medium or high season lot in the array double tariffs[].
Here is the portion of code with the bookApartment() method, where code and id are the keys in the HashMaps of Apartments and Clients (booking is correct only if the arrival date is a Saturday):
public Booking bookAppartment(String code, String id, int day, int month, int year, int nweeks) throws WrongDay {
Calendar date = Calendar.getInstance();
date.set(year, month-1, day);
int weekday = date.get(Calendar.DAY_OF_WEEK);
Booking book=null;
if(code!="" && id!=""){
if(weekday!=Calendar.SATURDAY)
throw new WrongDay(date);
else{
for(Map.Entry<String , Apartment> apt : apts.entrySet()){
for(Map.Entry<String, Client> client : clients.entrySet()){
if(apt.getKey()==code && client.getKey()==id && weekday==Calendar.SATURDAY){
book = new Booking(client.getValue(), apt.getValue(), d, m, y, nweeks);
bookings.add(book);
book.setPrice(d, m, y, apt.getValue().getTariffs(), nweeks);
break;
}
}
}
}
}
return book;
}
And here I attach the constructor of the Booking object and my personal override of the setPrice() method, which calculates the entire booking price selecting the correct tariffs[] lot:
public class Booking {
private Client client;
private Apartment apt;
private double price;
private int numweeks;
private static int day, month, year;
public Booking(Client client, Apartment apt, int day, int month, int year, int numweeks){
this.client = client;
this.apt = apt;
Booking.day = day;
Booking.month = month;
Booking.year = year;
this.numweeks = numweeks;
}
// other stuff
public void setPrice(int day, int month, int year, double[] tariff, int numweeks){
tariff = apt.getTariffs();
Booking.day=day;
Booking.month=month;
Booking.year=year;
Calendar date = Calendar.getInstance();
date.set(year, month-1, day);
Calendar date1 = Calendar.getInstance();
date1.set(2008, 6, 1);
Calendar date2 = Calendar.getInstance();
date2.set(2008, 6, 31);
Calendar date3 = Calendar.getInstance();
date3.set(2008, 7, 1);
Calendar date4 = Calendar.getInstance();
date4.set(2008, 7, 31);
Calendar date5 = Calendar.getInstance();
date5.set(2008, 11, 20);
Calendar date6 = Calendar.getInstance();
date6.set(2009, 0, 1);
if(date.equals(date1) || date.equals(date2) || (date.after(date1) && date.before(date2))){
this.price = tariff[1] * numweeks;
} else if(date.equals(date3) || date.equals(date4) || (date.after(date3) && date.before(date4))){
this.price = tariff[2] * numweeks;
} else if(date.equals(date5) || date.equals(date6) || (date.after(date5) && date.before(date6))){
this.price = tariff[2] * numweeks;
} else{
this.price = tariff[0] * numweeks;
}
}
}
I encounter the problem when setting the price of a Booking object with arrival date on the 20th December 2008 (considered high season): it skips the third if check (expected) and goes directly to the last else.
But if I run my own program to check if the dates are the same, passing directly the values to day, month and year, the test is passed.
So it seems to me that I cannot pass only references not pointing to an int value not manually setted.
Is it possible I am right?
If so, I really don't know how to go on.
Thanks in advance: I hope I used all the right words in the right places.
When you get a calendar instance, it defaults to using the current time (right down to the millisecond). Thus, when set your date in it:
Calendar date = Calendar.getInstance();
date.set(year, month-1, day);
... the date is still left with "random" values for the hours, minutes, seconds and milliseconds. The same goes for date1 through to date6.
In your code, you create all the dates one right after the other, so the speed of executing those instructions may mean that the first few dates end up with identical values for hours, minutes, seconds and milliseconds. However there is no guarantee of this.
What you're finding is that when you do, for example, date.equals(date3), the year month and day match, but the other fields potentially don't.
To solve this, call clear() first:
Calendar date = Calendar.getInstance();
date.clear();
date.set(year, month-1, day);
Also, you probably don't actually want to compare calendars for equality. You can, but if you look at the Javadoc for it, it says:
* Compares this <code>Calendar</code> to the specified
* <code>Object</code>. The result is <code>true</code> if and only if
* the argument is a <code>Calendar</code> object of the same calendar
* system that represents the same time value (millisecond offset from the
* Epoch) under the same
* <code>Calendar</code> parameters as this object.
*
* <p>The <code>Calendar</code> parameters are the values represented
* by the <code>isLenient</code>, <code>getFirstDayOfWeek</code>,
* <code>getMinimalDaysInFirstWeek</code> and <code>getTimeZone</code>
* methods. If there is any difference in those parameters
* between the two <code>Calendar</code>s, this method returns
* <code>false</code>.
*
* <p>Use the {#link #compareTo(Calendar) compareTo} method to
* compare only the time values.
You're probably better off using:
if (date.getTime().equals(date1.getTime()))
{
...
}
... and comparing the returned Date objects, or doing as the Javadoc suggests and using compareTo():
if (date.compareTo(date1) == 0)
{
...
}
I understand you are doing an exercise, but you should know:
(a) Avoid java.util.Calendar
The java.util.Date and .Calendar classes bundled with Java are notoriously troublesome. Avoid them. Use either the new java.time package bundled with Java 8, or the Joda-Time library which inspired java.time. Both java.time and Joda-Time have some pros and cons over each other, both are active projects, and you can even use them both in a project.
(b) Date-Only
The old .Date & .Calendar classes lack a representation of date-only without a time-of-day. But that is what your Question demands, a class that is date-only without time and time zones. Fortunately both Joda-Time and java.time have such a class, both called LocalDate.
(c) Half-Open
The best approach to spans of time is called "Half-Open" where the beginning is inclusive and the ending exclusive. For example the month of June would be June 1 and going up to, but not including, July 1. This simplifies things whether doing date-only or date-time work. Joda-Time and java.time adopt this approach.
The other answer by Greg Kopff seems to be correct, the time-of-day portion is throwing you off.
Here is some example code in Joda-Time 2.4 to get you headed in the right direction.
LocalDate target = new LocalDate( 2008, 12, 20 );
LocalDate highSummerStart = new LocalDate( 2008, 6, 1 ); // Half-Open. Inclusive.
LocalDate highSummerStop = new LocalDate( 2008, 7, 1 ); // Exclusive.
LocalDate lateSummerStart = new LocalDate( 2008, 7, 1 ); // Half-Open. Inclusive.
LocalDate lateSummerStop = new LocalDate( 2008, 8, 1 ); // Exclusive.
LocalDate holidaysStart = new LocalDate( 2008, 11, 20 ); // Half-Open. Inclusive.
LocalDate holidaysStop = new LocalDate( 2009, 1, 2 ); // Exclusive.
if ( this.rangeContainsTarget( highSummerStart, highSummerStop, target ) ) {
System.out.println( "Apply High Summer rates." );
} else if ( this.rangeContainsTarget( lateSummerStart, lateSummerStop, target ) ) {
System.out.println( "Apply Late Summer rates." );
} else if ( this.rangeContainsTarget( holidaysStart, holidaysStop, target ) ) {
System.out.println( "Apply Holidays rates." );
} else { // Else not in special season.
System.out.println( "Apply default rates." );
}
And the comparison method.
private boolean rangeContainsTarget( LocalDate start, LocalDate stop, LocalDate target )
{
// Half-Open approach. If the Target is GREATER THAN OR EQUAL TO Start AND Target is LESS THAN Stop.
if ( start.isAfter( stop ) ) {
return false; // Or throw exception.
}
boolean startGood = ( target.isEqual( start ) || target.isAfter( start ) );
boolean stopGood = target.isBefore( stop );
boolean containsTarget = ( startGood && stopGood );
return containsTarget;
}
The old .Date/.Calendar classes lack a way to represent a span of time. Joda-Time offers three classes to define a span of time in various ways: Interval, Period, and Duration. Unfortunately they work only with DateTime, not LocalDate. So I did not use them in the example above, where Interval would have been handy.
By the way, if in Joda-Time you do need a date plus time-of-day yet want to focus on days, call the withTimeAtStartOfDay() method to get a DateTime object set to the first moment of the day. That first moment is not always the time 00:00:00.000 because of Daylight Saving Time and perhaps other anomalies.

Java Newbie Calendar Class Questions

Need help understanding below test code. Specifically I do not understand what the "11" and "12" represent in the calendar.set method? example "openCal.set(11, openHrs).
public static void main(String[] args) {
{
int openHrs = 07;
int openMins = 30;
int closedHrs = 23;
int closedMins = 00;
Calendar cal = Calendar.getInstance();
Calendar openCal = Calendar.getInstance();
openCal.set(11, openHrs);
openCal.set(12, openMins);
Calendar closeCal = Calendar.getInstance();
closeCal.set(11, closedHrs);
closeCal.set(12, closedMins);
if(openCal.before(cal) && closeCal.after(cal))
{
System.out.println("The Business is OPEN");
} else
{
System.out.println("The Business is CLOSED");
}
}
}
This is perfect example of why we should avoid magic numbers.
Instead of set(11 code should look like set(Calendar.HOUR_OF_DAY.
Instead of set(12 code should look like set(Calendar.MINUTE.
If you take a look at documentation of Calendar class you will find few examples of how to use set methods like
set(Calendar.MONTH, Calendar.SEPTEMBER)
set(Calendar.DAY_OF_MONTH, 30)
By looking at source code of Calendar class you will find many constants and their values. They can also be found at
http://docs.oracle.com/javase/8/docs/api/constant-values.html
so you see that
Calendar.HOUR_OF_DAY equals 11 -> (click here to check)
Calendar.MINUTE equals 12 -> (click here to check)
Just digging into Calendar source code those magic numbers are tied to the following fields
private static final String[] FIELD_NAME = {
"ERA", "YEAR", "MONTH", "WEEK_OF_YEAR", "WEEK_OF_MONTH", "DAY_OF_MONTH",
"DAY_OF_YEAR", "DAY_OF_WEEK", "DAY_OF_WEEK_IN_MONTH", "AM_PM", "HOUR",
"HOUR_OF_DAY", "MINUTE", "SECOND", "MILLISECOND", "ZONE_OFFSET",
"DST_OFFSET"
};
So in that case you can see that 11 is HOUR_OF_DAY and 12 is MINUTE
Where are you looking at this tutorial? In the set function for Calendar that has two parameters the first parameter is an index for where the data is and the second is the value to set. So from the code that would suggest that 11 is for Hours and 12 is for minutes. The documentation is at http://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html . The numbers should be replaced with constants from the Calendar class to make this code more readable and self answer your question.
Calendars get and set methods use integers as the first parameters, which indicate the field that should be retrieved respectively changed. This might seem strange, but Calendar is older than Enums in Java (and considering all the other stupidities in Java's date related classes, this one is a minor one).
As others have pointed out, the only acceptable practice is to use the constants defined in Calendar (HOUR_OF_DAY etc.), but syntactically, a [expletive removed] programmer can use numerical literals too (or even expressions that result in an int value).
tl;dr
LocalTime now = LocalTime.now( ZoneId.of( "America/Montreal" ) );
Boolean isOpenNow =
( ! now.isBefore( LocalTime.of( 7 , 30 ) ) )
&&
now.isBefore( LocalTime.of( 23 , 00 ) )
;
Details
The Answer by Pshemo is correct and should be accepted.
Avoid legacy date-time classes
The Question and answers have outmoded code using troublesome old date-time classes now supplanted by the java.time classes.
LocalTime
The LocalTime classe represents a time-of-day without a date and without a time zone.
LocalTime opening = LocalTime.of( 7 , 30 );
LocalTime closing = LocalTime.of( 23 , 00 );
Time zone
Determining the current time of day requires a time zone. For any given moment the time-of-day (and the date) vary around the globe by zone.
ZoneId z = ZoneId.of( "America/Montreal" );
LocalTime now = LocalTime.now( z );
Comparing
We can compare the LocalTime objects with compareTo, equals, isAfter, and isBefore.
In this example code we use the Half-Open approach to defining a span of time, where the beginning is inclusive while the ending is exclusive. This approach is sensible and commonly used. Using this approach throughout all your code makes your logic easier to comprehend and makes errors less likely. So we ask “is the current moment the same or later than the start but also earlier than the stop?”. A more compact way to say the same thing is:
Is now not earlier than start AND now is earlier than stop?
Boolean isOpenNow = ( ! now.isBefore( opening ) ) && now.isBefore( closing ) ;

Date Util in java that will explode date range in weeks,month,quarter,year

I am looking for a java library that when given from and to date would return a list of dates in weeks,months,quarter or year which ever is most applicable. I have done this manually and i wanted to know if this is already implemented and tested as a part of a standard package.
Example
Given 1/1/2009 , 1/4/2009 it should give 1/1/2009,1/2/2009,1/3/2009,1/4/2009
Given 1/1/2009 , 1/14/2009 it should give 1/1/2009,1/7/2009,1/14/2009
hope you that is clear :)
The DateTime class provided by Joda Time has methods such as plusDays(int), plusWeeks(int), plusMonths(int) which should help.
Assuming you want to get all the dates between start and end in weeks (pseudocode):
DateTime start = // whatever
DateTime end = // whatever
List<DateTime> datesBetween = new ArrayList<DateTime>();
while (start <= end) {
datesBetween.add(start);
DateTime dateBetween = start.plusWeeks(1);
start = dateBetween;
}
Alternative to Jado is use standart java API
Calendar start = // whatever
Calendar end = // whatever
List<Calendar> datesBetween = new ArrayList<Calendar>();
while (start.compareTo(end) <= 0) {
datesBetween.add(start);
Calendar dateBetween = start.add(Calendar.DAY_OF_MONTH, 7);
start = dateBetween;
}
java.time
The Answer by Dónal using Joda-Time is correct, but outdated. The Joda-Time team has advised that we should migrate to the java.time framework built into Java 8 and later. Much of the java.time functionality has been back-ported to Java 6 & 7 and further adapted to Android.
LocalDate
For a date-only value, without time-of-day and without time zone, use the LocalDate class.
Half-Open
Generally the best practice in handling a span of time is known as Half-Open. In this approach, the beginning of the span is inclusive while the ending is exclusive. So with the example code below, you will see the results do not include the stop date. If you insist on the ending being inclusive, change the date.isBefore ( stop ) to ! date.isAfter ( stop ).
Example code
In its current state, the Question is vague, not addressing issues such as whether to consider if the start date happens to align with start of week or start of month and so on. Another issue: whether to use the Half-Open approach or not. So those issues are left as an exercise for the reader. ;-)
This code counts the number of days in the span of time. If under a week, we loop day-by-day. If over a week, we loop week-by-week. The same logic could be extended to handle month-by-month, quarter-by-quarter, and year-by-year as mentioned in the Question.
LocalDate start = LocalDate.of ( 2016 , Month.JANUARY , 2 );
LocalDate stop = start.plusDays ( 4 );
// LocalDate stop = start.plusWeeks ( 4 );
long days = ChronoUnit.DAYS.between ( start , stop );
List<LocalDate> dates = new ArrayList<> ();
if ( days == 0 ) {
dates.add ( start );// Just one date, as start equals stop.
} else if ( days < 7 ) { // Under a week, count day-by-day.
LocalDate date = start;
do {
dates.add ( date );
// Prep for next loop.
date = date.plusDays ( 1 );
} while ( date.isBefore ( stop ) ); // Using “isBefore” for Half-Open approach where ending is exclusive. For inclusive, use “! isAfter”.
} else if ( days > 7 ) { // Over a week, count week-by-week.
LocalDate date = start;
do {
dates.add ( date );
// Prep for next loop.
date = date.plusWeeks ( 1 );
} while ( date.isBefore ( stop ) ); // Using “isBefore” for Half-Open approach where ending is exclusive. For inclusive, use “! isAfter”.
} else {
// FIXME: ERROR. Should not be possible.
}
Dump to console.
System.out.println ( "start: " + start + " | stop: " + stop + " | dates: " + dates );
When run with the line for stop adding 4 days:
start: 2016-01-02 | stop: 2016-01-06 | dates: [2016-01-02, 2016-01-03, 2016-01-04, 2016-01-05]
When run with the line for stop adding 4 weeks:
start: 2016-01-02 | stop: 2016-01-30 | dates: [2016-01-02, 2016-01-09, 2016-01-16, 2016-01-23]
A sample java implementation using jodatime to create a date split over a large range, with minimal memory footprint.
https://github.com/atulsm/Test_Projects/blob/master/src/DateSplitter.java

Categories