Building a calendar
Hey..not totally sure where to post this, and I couldn't really find anything like it in searches, but I'm trying to find the best approach to build a 2 Dimension String array (String[ ] [ ]) with calendar data. I'm also aiming to keep it locale/timezone sensitive. Does anybody know what the best approach for this is?
Thanks!
[344 byte] By [
GAndersona] at [2007-11-27 9:00:28]

What, more precisely, do you want to go into your 2D array?Take a look at the Calendar class. Methods set(int, int, int), add(), getActualMaximum(), getFirstDayOfWeek() and more may be interesting?
OleVVa at 2007-7-12 21:29:09 >

I was looking through that but I can't seem to wrap my head around how to piece the information together. I essentially want a String[ ][ ] like:
String[][] june =
{{"Sun","Mon","Tue","Wed","Thu","Fri","Sat"},
{"","","","","","1","2"},
{"3","4","5","6","7","8","9"},
.
.
.
{"24","25","26","27","28","29","30"}};
Just dynamic such that I can specify a date (using Calendar.set()) and it'll build a String[ ] [ ] for the month of that date.
You basically only need to know 2 things from the Calendar after you set it's date, the day of the week of the first day, and how many days there are. The first array is just Sun, Mon, etc. Then start filling the array with blanks until you get to the first day of the month (Friday in your example). Then keep filling it in, wrapping back around to Sunday when you reach Saturday, until you get to the last day of the the month. I suppose you'd probably also need to calculate how many weeks the month spanned first, since it could be from 4 to 6.
To me it looks doable, but I haven't actually tried.
Whether you can have locale specific day names; well, maybe you need a specialized SimpleDateFormat or something else for this part, I'm not sure. I would investigate the options of combining Calendar.getTime() and SimpleDateFormat.format(). I'd probably leave this to the end and solve the numbers first.
How many rows do you need? Calendar can tell you the week numbers of the first and the last day of the month; can you calculate from these numbers? You may get into trouble around new year, since either the last day of December may be in week one of the next year or January 1 may be in the last week of the previous year, but other than that? getActualMaximum() should be able to tell you which is the last day of the month.
Into which column does "1" go? Calendar can tell you the weekday of the first day of the week and also the weekday of the first day of the month. Take into account that either may be greater than the other and do the proper calculation.
From the field where you put the "1", iterate through the fields and the days of the month in parallel.
Does this help?
OleVVa at 2007-7-12 21:29:09 >

Thanks alot..I was able to get a basic generator pulled together properly. Now I just need to add code to make it support different locales. Here's my solution:
public String[][] genCalendar() {
String[][] data = new String[0][0]; // 2D array for calendar
Vector row = new Vector(); // Vector to hold one row at a time
// Used to get days of week
java.text.DateFormatSymbols dfs = new java.text.DateFormatSymbols();
String[] days = dfs.getShortWeekdays();
// Put days into vector
for(int i = 1; i < days.length; i++) {
row.add(new String(days[i]));
}
// update the String[][] with the new row
data = fillRow(data, row);
row.clear(); // Clear vector
// Make calendar
Calendar cal = Calendar.getInstance();
cal.clear();
cal.setTimeInMillis(System.currentTimeMillis()); // example date in millis
// Get month, year, first date, and last date
int month = cal.get(Calendar.MONTH);
int year = cal.get(Calendar.YEAR);
int lastDate = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
int firstDate = cal.getActualMinimum(Calendar.DAY_OF_MONTH);
// Set calendar to first date of month
cal.set(year, month, firstDate);
// Get the day of the week that the first date is
int firstDay = cal.get(Calendar.DAY_OF_WEEK);
// add empty strings to vector until first day is found
for(int i = 1; i < firstDay; i++) {
row.add(new String(""));
}
// Add any other days for the 2nd row
for(int i = firstDay; i <= 7; i++) {
row.add(new String("" + firstDate));
firstDate++;
}
// update String[][] with 2nd row
data = fillRow(data, row);
// Loop through and add the rest of the days
while(firstDate <= lastDate) {
row.clear();
for(int i = 1; i <= 7; i++) {
row.add(new String("" + firstDate));
firstDate++;
}
data = fillRow(data, row);
}
return data;
}
public String[][] fillRow(String[][] s, Vector v) {
v.trimToSize(); // trim vector
int newHeight = s.length + 1; // get height for new array
int newWidth = v.capacity(); // get width for new array
// make new array with an extra row
String[][] strArr = new String[newHeight][newWidth];
if((newHeight - 1) > 0) {
// Fill the new array with values from the old one
for(int i = 0; i < newHeight - 1; i++) {
for(int j = 0; j < s[i].length; j++) {
strArr[i][j] = s[i][j];
}
}
}
// Add the new values to the array
for (int i = 0; i < newWidth; i++ ) {
strArr[newHeight-1][i] = (String)v.get(i);
}
return strArr;
}
Thanks alot guys!
Beautiful!
java.text.DateFormatSymbols dfs = new java.text.DateFormatSymbols();
String[] days = dfs.getShortWeekdays();
Interesting. So I learned something from this exercise too, thanks!
// Put days into vector
for(int i = 1; i < days.length; i++) {
row.add(new String(days[i]));
}
It's considered bad practice to call new String on a String argument. You can obtain the same cheaper with just row.add(days);.
// Make calendar
Calendar cal = Calendar.getInstance();
cal.clear();
cal.setTimeInMillis(System.currentTimeMillis()); // example date in millis
Probably double work. I believe Calendar.getInstance gives you an object set to System.currentTimeInMillis() already, that is, "now".
for(int i = 1; i < firstDay; i++) {
row.add(new String(""));
}
Does not seem to take into account that the week begins on Sunday in the USA and on Monday elsewhere (more variants may exist, I don't know). This may come in version 2?
public String[][] fillRow(String[][] s, Vector v) {
v.trimToSize(); // trim vector
I haven't studied your use of array and Vector closely; I have a feeling that it can be done a little smarter.
OleVVa at 2007-7-12 21:29:09 >

> t's considered bad practice to call new String on a
> String argument. You can obtain the same cheaper with
> just row.add(days);.
That should have been
// Put days into vector
for(int i = 1; i < days.length; i++) {
row.add(new String(days[i]));
}
OleVVa at 2007-7-12 21:29:09 >

// Put days into vector
for(int i = 1; i < days.length; i++) {
row.add(new String(days[i]));
}
> It's considered bad practice to call new String on a
> String argument. You can obtain the same cheaper with> just row.add(days);.
You can just drop an array into a vector like that? Because my understanding is that the add() method takes an object argument, so you'd have to give it an object.
// Make calendar
Calendar cal = Calendar.getInstance();
cal.clear();
cal.setTimeInMillis(System.currentTimeMillis()); //
example date in millis
> probably double work. I believe Calendar.getInstance
> gives you an object set to
> System.currentTimeInMillis() already, that is,
> "now".
It is double work. The reason it's there is because I plan to pass in a long for the date (which won't be the current day :P) and set it there. Thanks for mentioning that though. I didn't realize getInstance() used current system time.
for(int i = 1; i < firstDay; i++) {
row.add(new String(""));
}
> Does not seem to take into account that the week
> begins on Sunday in the USA and on Monday elsewhere
> (more variants may exist, I don't know). This may
> come in version 2?
Yea..I totally missed that. Any suggestions on the best approach for dealing with this?
public String[][] fillRow(String[][] s, Vector v) {
v.trimToSize(); // trim vector
> haven't studied your use of array and Vector
> closely; I have a feeling that it can be done a
> little smarter.
I imagine it could, but I use this method in other classes to generate arrays when I don't know the dimensions. I'm sure I could use an arraylist here, but I felt that it might get a little bloated or memory-intensive by doing that. Any suggestions are welcome though :D
By the way, I'm restricted to Java 1.42 for my coding, so I gotta write accordingly :P
Thanks again!
> You can just drop an array into a vector like that?
> Because my understanding is that the add() method
> takes an object argument, so you'd have to give it
> an object.
Where did I put my head while typing that part? I meant:
// Put days into vector
for(int i = 1; i < days.length; i++) {
row.add(days[i]);
}
By the way, an array is also considered an object, so you could add it like that if you wanted to. Only you don't want to in this case.
OleVVa at 2007-7-12 21:29:09 >

> Where did I put my head while typing that part? I
> meant:
>
> // Put days into vector
> for(int i = 1; i < days.length; i++) {
> row.add(days[i]);
> }
> y the way, an array is also considered an object, so
> you could add it like that if you wanted to. Only you
> don't want to in this case.
Yea I know an array is an object (was just trying to edit my post :P). Thanks for pointing out the fact that I don't need to make a new string object for each element in the days[] array.
woop..missed one little thing. The while loop should look like this:
// Loop through and add the rest of the days
while(firstDate <= lastDate) {
row.clear();
for(int i = 1; i <= 7; i++) {
if(firstDate <= lastDate) row.add("" + firstDate);
else row.add("");
firstDate++;
}
data = fillRow(data, row);
}
I added:
if(firstDate <= lastDate) row.add("" + firstDate);
else row.add("");
Without that little if block, it will continue printing days after the end of the last date (i.e. 32, 33, 34 for July). Also, the potential issue with sunday and monday days printing...well, works fine. so I think the code is pretty solid now. *moves on to adding locale stuffs*