Can't create objects with a required API using Calendar - java

I am trying to create multiple objects of a train schedule using the required constructor,
public Station(String city, Calendar arrival, Calendar departure, int day)
However when I create the objects I can't pass the arrival and departure times because 20:30 etc is considered an int. I would love to just change Calendar to int in the constructor, but apparently it has to be done with Calendar.
Station stop1= new Station("Vancouver",null , 2030, 1)
This is want I try to create but like I said it won't take the parameters.
So obviously I need to think outside the box here and start messing around with Calendar but I'm not sure if I should be doing that under the constructor below:
public Station(String city, Calendar arrival, Calendar departure, int day){
this.city=city;
this.arrival=arrival;
this.departure=departure;
this.day=day;
}
or if I have to create some new method and tie it all together. On my research I came across a method that I altered a bit, but I still can't seem to implement it into my object creation using those parameters of "arrival" and "departure".
private static Calendar getCalendar(int hour, int minute) {
Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, hour);
c.set(Calendar.MINUTE, minute);
return c;
}
So I guess I'm wondering if anyone can drop some hints, point me in the right direction of something else maybe I should be looking up online. This is the last and hardest question on my assignment and I can't even get the 10 objects created to start the train schedule.

I would love to just change Calendar to int in the constructor, but apparently it has to be done with Calendar.
I am not sure what you mean exactly with this, but lets say for some reason you prefer to keep the constructor as it is now, then what you need to do with the code you already posted is something like this
Station stop1= new Station("Vancouver",null , getCalendar(20, 30) , 1)
Otherwise you can do as suggested in the other answers

I like the composite approach.
public StationAdapter {
private readonly Station station;
public StationAdapter(String city, int arrival, int departure, int day) {
// Create station
}
}
Or eventually a Builder Pattern.

Related

CalendarArray get dates betweeen two Dates and skip a few

i am trying to create an Array of Calendar Objects where i get all dates between start and end, while skipping the date "skip". So let's imagine i have the dates:
start = 04.03.2016
skip = 21.07.2016
end = 02.03.2017
i tried something like this, but it didn't work that well:
public static Calendar[] getRange(Calendar start, Calendar skip, Calendar end){
Calendar[] daysRange = new Calendar[100];
Calendar placeholder = Calendar.getInstance();
while(start.before(end)){
if(placeholder.getTime() == skip.getTime()){
continue;
} placeholder.add(Calendar.Date, 1);
}
//(pseudocode)
//add placeholder to daysRange
return daysRange;
}
I would appreciate any tips on how i could continue.
Thanks!
First:
while (start.before(end)) {
You never modify start or end, so the loop is endless.
Second: you use one placeholder object, that means that your whole array points to that one object, create a new Calendar for every step en the loop.
Third: don't use an array, use an ArrayList.

Calendar (GregorianCalendar) .complete() method not visible?

So I read through a few different threads but none of them seem to directly address how I fix my issue. I'm trying to create a Calendar (Gregorian) and then use the .complete() method so that in my classes using this (Paycheck) class I can find relative dates and create new Calendar(s) from those dates to determine wages payed and wages owed. However, it's telling me that .complete() .computeTime() and .computeFields() are all not visible.
From what I've read, this seems to be because they are protected methods and even though I import the java.util for them, I can't access them because that class is not in my package. How do I get this so that I can call the .complete() method?
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.TimeZone;
public class Paycheck {
//fields
protected double grossAmount;
protected Calendar paymentDate;
protected Calendar payPeriodStart;
public Paycheck(double grossAmount, int iYear, int iMonth, int iDay, int sYear, int sMonth, int sDay) {
this.grossAmount = grossAmount;
TimeZone tz1 = TimeZone.getTimeZone("America/Chicago");
this.paymentDate = new GregorianCalendar(iYear, iMonth, iDay);
this.paymentDate.setTimeZone(tz1);
this.paymentDate.complete(); //says "method not visible"
this.payPeriodStart = new GregorianCalendar(sYear, sMonth, sDay);
this.payPeriodStart.setTimeZone(tz1);
}
In a comment you wrote:
I don't care about the actual time, I just want it to give me the date so I can determine the dayofweek (important based on various state laws).
That is very easy to do, and don't need any call to internal methods.
Calendar cal = new GregorianCalendar(2016, Calendar.SEPTEMBER, 22);
cal.setTimeZone(TimeZone.getTimeZone("America/Chicago"));
System.out.println("Day of week (1=Sun, ..., 7=Sat): " + cal.get(Calendar.DAY_OF_WEEK));
Output
Day of week (1=Sun, ..., 7=Sat): 5
Output is 5 because today is Thu 9/22/2016, and that's the date that was given.
Let's compare the typing effort:
this.paymentDate = new GregorianCalendar(iYear, iMonth, iDay);
this.paymentDate.complete(); // Why do you need to call this one?
vs the code having the same effect
this.paymentDate = new GregorianCalendar(iYear, iMonth, iDay, 0, 0, 0);
// constructor taking extra hours, minutes, seconds ----------^
So why do you try the almost-impossible of calling a protected method?
In some cases, very limited in number, one really needs to call a protected/private method and this may be possible. Exemplifying:
Class<GregorianCalendar> clazz=GregorianCalendar.class;
Method completeMethod = clazz.getDeclaredMethod("complete");
// this does the trick if it doesn't throw security exceptions
completeMethod.setAccessible(true);
completeMethod.invoke(this.paymentDate);
See the Javadoc for AccesibleObject.setAccessible, Method being derived from AccessibleObject

Most efficient way of checking if Date object and Calendar object are in the same month

I am working on a project that will run many thousands of comparisons between dates to see if they are in the same month, and I am wondering what the most efficient way of doing it would be.
This isn't exactly what my code looks like, but here's the gist:
List<Date> dates = getABunchOfDates();
Calendar month = Calendar.getInstance();
for(int i = 0; i < numMonths; i++)
{
for(Date date : dates)
{
if(sameMonth(month, date)
.. doSomething
}
month.add(Calendar.MONTH, -1);
}
Creating a new Calendar object for every date seems like a pretty hefty overhead when this comparison will happen thousands of times, soI kind of want to cheat a bit and use the deprecated method Date.getMonth() and Date.getYear()
public static boolean sameMonth(Calendar month, Date date)
{
return month.get(Calendar.YEAR) == date.getYear() && month.get(Calendar.MONTH) == date.getMonth();
}
I'm pretty close to just using this method, since it seems to be the fastest, but is there a faster way? And is this a foolish way, since the Date methods are deprecated? Note: This project will always run with Java 7
I can't comment on whether to use the deprecated methods, but if you choose not to there's no need to instantiate a new Calendar for every Date you check. Just use one other Calendar and call setTime(date) before the check (or one Calendar for every thread if you parallelize it).
As a side note, I do have to agree with ChristopheD's comment that this is something worthy of a database.
I think you can define a static DateFormat to extract the month and year from Date and use both objects as date only.
public static DateFormat formatter= new SimpleDateForm("MMyyyy");
public static boolean sameMonth(Date date1, Date date2)
{
return formatter.format(date1).equals(formatter.format(date2));
}

How to determine if the specific time is between given range?

Problem: I have a list containg hours, for example:
08:15:00
08:45:00
09:00:00
12:00:00
...
application is allowing user to make an appointment for a specific hour let'say: 8:15:00, each meeting takes half an hour.
Question: How to determine if there is a slot needed for appointment like this? I know that Calendar class have methods before() nad after(), but it doesn'solve my problem. I mean if there is appointment at 12:00 and another one at 12:00, how to prevent before making another one at 12:15?
edit:
I've tried using methods I mentioned before, like:
Calendar cal1 = Calendar.getInstance(); // for example 12:00:00
Calendar cal2 = Calendar.getInstance(); // for exmaple 12:30:00
Calendar userTime = Calendar.getInstance(); // time to test: 12:15:00
if(user.after(cal1)&& user.before(cal2)){
... // do sth
}
Check if the date to check is between the two provided:
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yyyy hh:mm");
Date before = sdf.parse("07/05/2012 08:00");
Date after = sdf.parse("07/05/2012 08:30");
Date toCheck = sdf.parse("07/05/2012 08:15");
//is toCheck between the two?
boolean isAvailable = (before.getTime() < toCheck.getTime()) && after.getTime() > toCheck.getTime();
To book for a determinate hour, I would do a class with two dates and a method to check this:
public class Appointment{
private Date start;
private Date end;
public boolean isBetween(Date toCheck){....}
}
Then you can simply do an Schedule class extending ArrayList, adding a method isDateAvailable(Date toCheck), iterating the list of Appointments and checking that there is no one conflicting.
I'd have some kind of appointment class with either a start timestamp and a duration or a start time and an end time. Then when adding new appointments to the schedule, check that the appointment with the start time before the new appointment doesn't run over the start time of the proposed new appointment.
Well how you would do it specifically depends on how you are storing your data, format, etc., but generally what you would do is simply check if there is an appointment for any time between the requested time to the requested time + requested length.
// Example (using int time(1 = 1 minute), assuming that appointments can only be at 15min intervals)
boolean isHalfHourTimeSlotAvaliable(int time) {
for (int i = 0; i < appointments.size(); i++) {
if (appointments.get(i).time == time || appointments.get(i).time == time + 15) {
return false;
}
}
return true;
}

Grouping objects by date: am I an idiot?

I have a list of objects called Activity:
class Activity {
public Date activityDate;
public double amount;
}
I want to iterate through List, group them by date and return a new list . Here's what I currently do:
private List<Activity> groupToList(List<Activity> activityList) {
SimpleDateFormatter sdf = new SimpleDateFormatter("YYYY-MM-DD");
Map<String,Activity> groupMap = new HashMap<String,Activity>();
for (Activity a in activityList) {
String key = sdf.format(a.getActivityDate());
Activity group = groupMap.get(key);
if (group == null) {
group = new Activity();
groupMap.add(key, group);
}
group.setAmount(group.getAmount() + a.getAmount());
}
return new ArrayList<Activity>(groupMap.values());
}
Is it a WTF to use the DateFormatter in this way?
I'm using the DateFormatter because each activityDate could have time information.
I would just use the date object itself as the key. If it it bothers you because the date object is mutable, then use its toString() value. No reason to go making formats.
If the issue is that you want to normalize the date by removing the time component, it would be much better to do that withing the Activity object and remove the time component. If the issue is still further that there are potential time zone issues, I would use JodaTime, but there is no object in the JDK currently that represents a pure date without time, so going with a string isn't outrageous, but it should be hidden behind a method in the Activity object and the fact that it is a date formatted string without a time component should be an implementation detail.
java.util.Date is a quite poor abstraction for your need; it is IMO fair to stick to strings if nothing better is around, HOWEVER Joda-time provides a good datatype for you: DateMidnight or alternatively LocalDate if Activity is strictly timezome-independant.
other than that, the code looks good to me, you might be able to shorten it a bit using an implementation of Multimap, to avoid messy null-checking code. to be honest, it doesn't get much shorter than your solution:
public List<Activity> groupedByDate(List<Activity> input) {
//group by day
final Multimap<DateMidnight, Activity> activityByDay
= Multimaps.index(input, new Function<Activity, DateMidnight>() {
#Override
public DateMidnight apply(Activity from) {
return new DateMidnight(from.activityDate);
}
});
//for each day, sum up amount
List<Activity> ret = Lists.newArrayList();
for (DateMidnight day : activityByDay.keySet()) {
Activity ins = new Activity();
ins.activityDate = day.toDate();
for (Activity activity : activityByDay.get(day)) {
ins.amount+=activity.amount;
}
}
return ret;
}
Why not simply create a HashMap<Date, Activity>() instead of the roundabout way with Strings?
Sorry, I didn't answer the question. The answer is: yes, unless I am an idiot ;)
You could do this using the Date as the key if you used a TreeMap and provided a Comparator that only compared the year, month and day and not the time.
As already mentioned the best solution is to represent your date with day precission. If this is not possible joda is nice library.
If you can ignore daylight saving time then grouping by date can be accomplished much easier. A unix time day is 86 400 s long. The timestamp does ignore leap seconds. (Your timer stops for one second or the leap second is distributed in some way.) All date values were day is equal are the same day:
int msPerDay = 86400 * 1000;
long day = new Date().getTime() / msPerDay
One minor point is to adjust the timezone. For my timezone CET (UTC/GMT +1 hour) the GMT day starts one our later:
new GregorianCalendar(2009, 10, 1, 1, 0).getTime().getTime() / msPerDay) ==
new GregorianCalendar(2009, 10, 2, 0, 59).getTime().getTime() / msPerDay) ==
new Date().getTime() / msPerDay
If the daylight saving time is significant the best way is to use joda. The rules are just to complicated and locale specific to implement.

Categories

Resources