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]
# 1
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 > top of Java-index,Java Essentials,Java Programming...
# 2

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.

GAndersona at 2007-7-12 21:29:09 > top of Java-index,Java Essentials,Java Programming...
# 3

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.

hunter9000a at 2007-7-12 21:29:09 > top of Java-index,Java Essentials,Java Programming...
# 4

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 > top of Java-index,Java Essentials,Java Programming...
# 5

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!

GAndersona at 2007-7-12 21:29:09 > top of Java-index,Java Essentials,Java Programming...
# 6

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 > top of Java-index,Java Essentials,Java Programming...
# 7

> 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 > top of Java-index,Java Essentials,Java Programming...
# 8

// 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!

GAndersona at 2007-7-12 21:29:09 > top of Java-index,Java Essentials,Java Programming...
# 9

> 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 > top of Java-index,Java Essentials,Java Programming...
# 10

> 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.

GAndersona at 2007-7-12 21:29:09 > top of Java-index,Java Essentials,Java Programming...
# 11

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*

GAndersona at 2007-7-12 21:29:09 > top of Java-index,Java Essentials,Java Programming...