I need to create a method for a program that accepts the date and if valid will add all the days from 01/01/xx to the date in the that year, eg 10/1/1999 will display "day 274 in 1999". I have the following code below, but its not adding the correct values. Not sure what I am doing wrong.
public static int dayNumber(int day, int month, int year){
int daysInMonth = 0;
int days = 0;
boolean leapYear = isLeapYear(year);
for(int i = 1; i <= month; i++){
switch(month){
case 1: daysInMonth += 31;
case 2: if(leapYear)
daysInMonth += 29;
else
daysInMonth += 28;
case 3: daysInMonth += 31;
case 4: daysInMonth += 30;
case 5: daysInMonth += 31;
case 6: daysInMonth += 30;
case 7: daysInMonth += 31;
case 8: daysInMonth += 31;
case 9: daysInMonth += 30;
case 10: daysInMonth += 31;
case 11: daysInMonth += 30;
case 12: daysInMonth += 31;
break;
default:
break;
}
while(month <= 12){
days += daysInMonth + day;
month++;
}
}
return days;
}
You need to terminate each case with a break:
case 1: daysInMonth += 31;
break;
case 2: if(leapYear)
daysInMonth += 29;
else
daysInMonth += 28;
break;
case 3: daysInMonth += 31;
break;
and so on.
Without this, statements in a switch fall through.
Additionally, your loop variable is i and you switch on month (but then modify month in another, nested, loop).
There is really no need for a loop here... This should do the trick:
days = day
days += (month-1)*30;
days += (month)/2; // every odd month until July has 31 days
days += (month >= 8 && month % 2 == 1) ? 1 : 0; // so if we have august or later and in an even month, add 1 day
if (month > 2) {
days -= (isLeapYear(year)) ? 1 : 2;
}
Just read your comment about this being exercise for school, so I'll better explain my code a little bit more.
First, we assume every month just has 30 days.
This, of course, is incorrect - every second month, starting with January, has 31. SO we're calculating how many month with 31 days we had so far. As it's the odd month (at least until August) that have the 31 days, we're dividing the month by two (remember - integer division, we'll get floor(month/2)) to get the number of month that have passed and had 31 days.
This is still incorrect, as starting with August, we have another day to add - our previous calculation yields one month with 31 days less than we really had. So we just add that one day if an even number of month has passed (we can tell this by dividing month by two and looking at the leftover, this is called "modulo division" and written "month % 2").
Finally, we're going for February. If February has passed (=we are in march or later) we just subtract two days - or one if it's a leap year. I used a so called "ternary statement" here (the ... ? ... : ... thing). Basically it's short for if (isLeapYear(year)) { days -= 1; } else { days -= 2; }
Related
right now i have a problem that i want to run my code with this
i make to check februay on the case 2 if year is true than run the execute if statement if it was false it will go to default but right now it go to the case 3 statement how to solve that not go to the case 3 but go to the default?
//this is my code
public static void main(String[] args) {
getDaysInMonth(1, 2018);
System.out.println(getDaysInMonth(2, 2018));
}
public static boolean isLeapYear(int year) {
if(year < 1 && year > 9999) {
return false;
} else {
if(year % 4 == 0) {
return true;
} else if(year % 100 == 0) {
return false;
} else if(year % 400 == 0) {
return true;
} else {
return false;
}
}
}
public static int getDaysInMonth(int month, int year) {
if((month < 1 || month > 12) && (year < 1 || year > 9999)) {
return -1;
}
isLeapYear(year);
int days;
switch(month) {
case 1:
days = 31;
break;
case 2:
if(year == 1) {
days = 29;
break;
}
case 3:
days = 31;
break;
case 4:
days = 30;
break;
case 5:
days = 31;
break;
case 6:
days = 30;
break;
case 7:
days = 31;
break;
case 8:
days = 31;
break;
case 9:
days = 30;
break;
case 10:
days = 31;
break;
case 11:
days = 30;
break;
case 12:
days = 31;
break;
default:
days = 28;
break;
}
return days;
}
This happens because your break is in the IF scope -> then if the year not 1 its continue to case 3.
You can use if else clause:
case 2:
if(year == 1) {
days = 29;
} else {
days = 28;
}
break;
But I have to remind you, year != 1 does not mean its Feb get 28 days, maybe you want this:
case 2:
if(!isLeapYear(year)) {
days = 29;
} else {
days = 28;
}
break;
Aside from the question about if statements and switch, there are some problems to be addressed with the method for leap year checking first. Here is the beginning of original code below:
public static boolean isLeapYear(int year) {
if(year < 1 && year > 9999) {
return false;
} else {
...
The condition year < 1 && year > 9999 can never happen since year can't be both less than one and greater than 9999 at the same time so it's redundant.
Other than this, the algorithm for determining if a year is a leap year is as follows (in plain English):
See if the year is evenly divisible by 4. If not, it can't be a leap year (return false).
Here a year is evenly divisible by 4 (determined in step 1). If it is not evenly divisible by 100, it is a leap year (return true).
Here a year is evenly divisible by 4 and also by 100. If the year is also evenly divisible by 400 then it is a leap year. Otherwise it isn't.
Putting all of the above considerations into code, it can be made more readable:
public static boolean isLeapYear(int year) {
if (year % 4 != 0) {
// year is not evenly divisible by 4 (it has a remainder, can't be a leap year).
return false;
}
// year is evenly divisible by 4
if (year % 100 != 0) {
// divisible by 4 and not 100, it's a leap year
return true;
}
// divisible by 4 and also 100
if (year % 400 != 0) {
// divisible by 4, 100 and not by 400
return false;
}
// divisible by 4, 100 and 400
return true;
}
Considering your getDaysInMonth method, we have the following cases, with 1 = January, 2 = February and so on:
30 days: September (9), April (4), June (6), November (11)
31 days: All others but February (2) (28, 29 on a leap year)
public static int getDaysInMonth(int month, int year) {
switch (month) {
case 9:
case 4:
case 6:
case 11:
return 30;
case 2:
if (isLeapYear(year)) {
return 29;
} else {
return 28;
}
default:
return 31;
}
}
Regarding validation of arguments, if you are receiving user input, it should all be validated outside of the methods used for calculation (pass the methods input that's already been validated instead of validating directly inside them).
I'm trying to print out a calendar for an entire year given any year. The code starts each month on the correct day, but continues to count out seven number and returns the next line to the same starting column. How might I correct this?
Here is my current output:
2017
January
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
February
Sun Mon Tue Wed Thu Fri Sat
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
And continues on for the year. I believe the error is in the printCalendar method but I don't know what to do.
Here is my code:
import java.util.Scanner;
import java.io.*;
public class CalendarPrinter{
public static void main(String[]args)throws IOException{
Scanner kbd = new Scanner(System.in);
System.out.println("Calendar Printer\n");
System.out.print("Enter the year? ");
int year = kbd.nextInt();
printCalendar(year);
System.out.println("\n" + year + ".txt generated.");
}
public static void printCalendar(int year) throws IOException {
PrintWriter outputFile = new PrintWriter(year + ".txt");
outputFile.println(" " + year);
for(int month = 1; month <=12; month++) {
outputFile.println("\n " + getMonthName(month));
outputFile.println("Sun Mon Tue Wed Thu Fri Sat");
int numDays = getNumberofDays(month, year);
for(int day = 1; day <= numDays; day++){
int dayWeek = getDayofTheWeek(day, month, year);
for(int k = 0; k < dayWeek; k++)
outputFile.print(" ");
outputFile.printf("%3d ", day);
if(day % 7 == 0) {
outputFile.println("");
dayWeek = 0;
}
}
}
outputFile.close();
}
public static String getMonthName(int month){
String name;
switch(month){
case 1: name = "January";
break;
case 2: name = "February";
break;
case 3: name = "March";
break;
case 4: name = "April";
break;
case 5: name = "May";
break;
case 6: name = "June";
break;
case 7: name = "July";
break;
case 8: name = "August";
break;
case 9: name = "September";
break;
case 10: name = "October";
break;
case 11: name = "November";
break;
case 12: name = "December";
break;
default: name = "Unknown";
break;
}
return name;
}//method
public static int getNumberofDays(int month, int year){
int numDays;
switch(month){
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
numDays = 31;
break;
case 4:
case 6:
case 9:
case 11:
numDays = 30;
break;
case 2:
numDays = isLeap(year)? 29:28;
break;
default:
numDays = 0;
break;
}
return numDays;
}//method
public static boolean isLeap(int year){
if(((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0))
return true;
else
return false;
}
public static int getDayofTheWeek(int day, int month, int year){
int y = year - (14-month)/12;
int x = y+y/4 - y/100 + y/400;
int m = month + 12 * ((14-month)/12) -2;
int d = (day + x + (31*m)/12)%7;
return d;
}//method
}//class
Your approach to using the day of the week is what messes up your printed data. In this example I'm using a temporary array to save one row of days (a.k.a. one printed line). Once the 7th day of a week is stored in the array, we print the whole week. This also happens when the last day of the month is reached.
for (int month = 1; month <= 12; month++) {
outputFile.println("\n " + getMonthName(month));
outputFile.println("Sun Mon Tue Wed Thu Fri Sat");
int numDays = getNumberofDays(month, year);
int[] week = new int[7];
for (int day = 1; day <= numDays; day++) {
int dayWeek = getDayofTheWeek(day, month, year);
week[dayWeek] = day;
// did we reach the 7th day of the week or the last day of the month?
if ((dayWeek + 1) % 7 == 0 || day == numDays) {
// print the week as one row
for (int d : week) {
// don't print 0 values
outputFile.printf("%3s ", d == 0 ? "" : d);
}
outputFile.println("");
// reset the array to store a new row in the next loop iteration
week = new int[7];
}
}
outputFile.println("");
}
I'm trying to find the day of the year after you enter a date. I have a way that works but it is not the best way it seems.
I ask for the date using a Scanner object then send it through to a method where it checks what day of the year it is.
public static int theDay(int month, int day, int year)
{
int numDay = day;
/* Code here to check for leap year */
for(int i = 1; i < month; i++)
{
switch(i)
{
case 1:
numDay += 31;
break;
case 2:
numDay += 28;
break;
case 3:
numDay += 31;
break;
...
... //goes until case 12
...
}
}
return numDay;
}
I cannot use Calendar, LocalDate, arrays, and anything my teacher hasn't taught us yet. So just loops would be OK, I believe. As mentioned, this works and I get the correct day. But what would be a better way of doing this? Any help would be appreciated. Thanks!
Depending on what you're using:
Standard Java libraries, before Java 8
Calendar calendar = new GregorianCalendar();
// Just to avoid corner cases
calendar.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
calendar.set(year, month - 1, day);
int dayOfYear = calendar.get(Calendar.DAY_OF_YEAR);
Joda Time
LocalDate date = new LocalDate(year, month, day);
int dayOfYear = date.getDayOfYear();
Java 8, using java.time
LocalDate date = LocalDate.of(year, month, day);
int dayOfYear = date.getDayOfYear();
Coding it yourself
(Now that we know that's what you need to do.)
Your current approach is okay, if you really need to do this yourself. You can do it without a loop though:
int daysInFebruary = ...; // Leap year calculation
switch (month)
{
case 1:
break; // Nothing to do
case 2:
numDay += 31; // Just add January
break;
case 3:
numDay += 31 + daysInFebruary; // Add January and February
break;
case 4:
numDay += 31 + daysInFebruary + 31; // Add January to March
break;
case 5:
numDay += 31 + daysInFebruary + 31 + 30; // Add January to April
break;
// etc
default:
throw new IllegalArgumentException("Invalid month: " + month);
}
That's more efficient, but I'd consider it less readable than the code you've already got.
It would be much cleaner to do this with an array, mind you - you could have one array with the lengths of each month, and another with the cumulative lengths of each month (0, 31, 59 etc). Add a special case for leap years, and Bob's your uncle. But if you're not allowed to use arrays...
This question already has answers here:
Excluding Dates from Print Loop
(2 answers)
Closed 10 years ago.
I have almost completed my code; however, instead of eliminating solely the dates which fall on Friday and also happen to be the 13th day of the month, it has eliminated every 13th submission. I thought that:
int friday = ((startingDayOfWeek+dayOfYear) % 7);
if (dayOfYear != 13 && friday != 5)
System.out.println(month + "/" + dayOfYear);
dayOfYear++;
Would work, but it is eliminating them all. I understand that there are easier ways to accomplish this; however, I am required to do it in this manner. Here is the full code:
public class LoopDate {
public static void main(String[] args) {
//Denotes that Tuesday is the first day of 2013
int startingDayOfWeek = 2;
int year = 2013;
int numDays = 0;
for (int month = 1; month <= 12; month++) {
switch (month) {
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
numDays = 31;
break;
case 4:
case 6:
case 9:
case 11:
numDays = 30;
break;
case 2:
if (((year % 4 == 0) && !(year % 100 == 0))
|| (year % 400 == 0))
numDays = 29;
else
numDays = 28;
break;
default:
System.out.println("Invalid month.");
break;
}
int dayOfYear = 1;
while (dayOfYear <= numDays)
{
int friday = ((startingDayOfWeek+dayOfYear) % 7);
if (dayOfYear != 13 && friday != 5)
System.out.println(month + "/" + dayOfYear);
dayOfYear++;
}
}
}
}
Your boolean logic is wrong.
if (dayOfYear != 13 && friday != 5)
Should be:
if (dayOfYear != 13 || friday != 5)
You are doing the negative check of "is it friday the 13th". When converting a positive check into a negative check, you need to NOT the conditions (done), and flip the operators (OR becomes AND, AND becomes OR).
Also, when dealing with boolean logic like that, I usually give the segments meaningful names. It 'costs' a variable, but can save you countless hours later on!
boolean isFridayThe13th = (dayOfYear == 13 && friday == 5);
if (!isFridayThe13th) ...
I am attempting to write a loop that will get its values from my switch statement. I want it to print out the dates in order each on their own line, such as:
1/1
1/2
1/3
...
12/31
I have attempted to write it myself, but I'm not entirely sure how to assign the months in correct order to the 3 cases I have in the switch statement.
Below is the switch statement I am using:
int month = 0;
int yearInt = year;
int totalDays = 0;
switch (month) {
case 1:
totalDays = 30;
break;
case 2:
if (((yearInt % 4 == 0) && !(yearInt % 100 == 0))
|| (yearInt % 400 == 0))
totalDays = 29;
else
totalDays = 28;
break;
default:
totalDays = 31;
break;
Like this? January is assumed 1
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
totalDays = 31;
break;
case 2:
if (((yearInt % 4 == 0) && !(yearInt % 100 == 0))
|| (yearInt % 400 == 0))
totalDays = 29;
else
totalDays = 28;
break;
default:
totalDays = 30;
break;
Note that the fall-through syntax I used is sometimes considered harmfull
You can as well get the desired result using built-in methods:
Calendar c = Calendar.getInstance();
c.set(Calendar.YEAR, yearInt);
c.set(Calendar.MONTH, month);
int totalDays = c.getActualMaximum(Calendar.DAY_OF_MONTH);
Note: Value of month starts from 0 (0 for January, 1 for February..).