I would like to ask someone if he/she can help me find the bug where I lose 2 solutions in this problem. My code isn't very pretty and readable but I think it is simple enough to understand logic here. I am sitting on this one for hour and even made up different solution which works but can't find problem in this one.
private static int _year = 1900;
private static int[] _months = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
private static int _month = 0;
private static int _day = 7; //we start from Sunday
private static int counter = 0;
public static void main(String[] args) {
while(_year !=1901)
nextSunday(_day, _month, _year);
while(true) {
if(_year == 2000 && _month == 11 && _day > 31) break;
nextSunday(_day, _month, _year);
}
System.out.println(counter);
}
private static void nextSunday(int day, int month, int year) {
if(isSundayFirst(_day)) counter++;
if(year == 2000 && month == 11 && day + 7 > _months[month]) { //to break loop
_day = day + 7;
} else if(month == 11 && day + 7 > _months[month]) { // new year, end of month
_day = day + 7 - _months[month];
_month = 0;
_year++;
} else if(month == 1 && isLeapYear(year) && day + 7 > 29) { // leap year end of february
_day = day + 7 - 29;
_month++;
} else if(month == 1 && !isLeapYear(year) && day + 7 > _months[month]) { // not leap year end of february
_day = day + 7 - _months[month];
_month++;
} else if(day + 7 > _months[month]) { // end of month
_day = day + 7 - _months[month];
_month++;
} else { // next in same month
_day = day + 7;
}
}
private static boolean isSundayFirst(int day) {
return day == 1;
}
private static boolean isLeapYear(int year) {
if(isCentury(year)) {
if(year % 400 == 0) return true;
} else {
return year % 4 == 0;
}
return false;
}
private static boolean isCentury(int year) {
return year % 100 == 0;
}
I got 169 such Sundays. I should get 2 more.
Here is the problem:
You are given the following information, but you may prefer to do some
research for yourself.
1 Jan 1900 was a Monday.
Thirty days has September,
April, June and November.
All the rest have thirty-one,
Saving February alone,
Which has twenty-eight, rain or shine.
And on leap years, twenty-nine.
A leap year occurs on any year evenly divisible by 4, but not on a century unless it is divisible by 400.
How many Sundays fell on the first of the month during the twentieth
century (1 Jan 1901 to 31 Dec 2000)?
I will appreciate any effort. Thank you.
PS I know this _name style isn't Java like but I was writing it fast without intention of posting it anywhere tbh.
There are two issues with your code, one that causes you to over count by 2 and another that causes you to undercount by 4.
Issue #1 The problem to tells you to start counting in 1901, but you start counting in 1900.
Change
if(isSundayFirst(_day)) counter++;
to
if(isSundayFirst(_day) && _year >= 1901) counter++;
to fix this.
Issue #2 The issue lies in this condition:
else if(day + 7 > _months[month]) { // end of month
_day = day + 7 - _months[month];
_month++;
}
You've handled the case where it is February in the previous two conditions, so you need to check to make sure it is not February here. Changing the condition to
else if(month != 1 && day + 7 > _months[month])
will fix your issue.
Sidenote: The structure of your nextSunday method made it quite difficult to decipher, so here is my effort to simplify it (you will now break when _year > 2000):
private static void nextSunday(int day, int month, int year) {
int febNum = isLeapYear(_year) ? 29 : 28;
int dayCount = (month == 1) ? febNum : _months[_month]; //days in current month
_day += 7;
if (_day > dayCount) { //new month
_month++;
_day -= dayCount;
}
if (_month == 12) { //new year
_month = 0;
_year++;
}
}
Related
So I got an assignment to build a Date class. When I am receiving a day, month and a year as parameters, I need to make sure that the Date is valid. I do it by calling a function named isDateValid. According to the instructions, if the date is valid, the parameters will be set has the properties of the class, otherwise, I need to create the date with the default value of 1/1/2000. however, when I run the testers the university has provided, it seems that even if the Date is valid, the actual Date will be set the default - meaning that the function isDateValid is returning false when it is supposed to return true.
Here is one of the objects created by the tester:
Date d1 = new Date(3, 5, 1998);
, when I run it, I get the default date.
the function is:
private boolean isDateValid(int day, int month, int year)
{
return (((month == JANUARY || month == MARCH || month == JULY || month == AUGUST || month == OCTOBER || month == DECEMBER || month == MAY) &&
day <= DAYS_IN_JAN_MAR_MAY_JUL_AUG_OCT_DEC) ||
((month == APRIL || month == JUNE || month == SEPTEMBER || month == NOVEMBER) && day <= DAYS_IN_JUN_APR_SEP_NOV) ||
(((month == FEBRUARY && day <= DAYS_IN_FEB_LEAP)) || (isLeapYear(year) && day <= DAYS_IN_FEB_NO_LEAP && month == FEBRUARY)) ) &&
( day >= MINIMUM_DAY && month >= MINIMUM_MONTH && month <= MAXIMUM_MONTH && year >= MINIMUM_YEAR && year <= MAXIMUM_YEAR);
}
Here are the contants being used:
private final int MINIMUM_YEAR = 1000;
private final int MINIMUM_MONTH = 1;
private final int MINIMUM_DAY = 1;
private final int MAXIMUM_DAY = 31;
private final int MAXIMUM_MONTH = 12;
private final int MAXIMUM_YEAR = 9999;
private final int JANUARY = 1;
private final int FEBRUARY = 2;
private final int MARCH = 3;
private final int APRIL = 4;
private final int MAY = 5;
private final int JUNE = 6;
private final int JULY = 7;
private final int AUGUST = 8;
private final int SEPTEMBER = 9;
private final int OCTOBER = 10;
private final int NOVEMBER = 11;
private final int DECEMBER = 12;
private final int DAYS_IN_JAN_MAR_MAY_JUL_AUG_OCT_DEC = 31;
private final int DAYS_IN_JUN_APR_SEP_NOV = 30;
private final int DAYS_IN_FEB_NO_LEAP = 28;
private final int DAYS_IN_FEB_LEAP = 29;
Edit:
I got a comment suggesting that the source of the error can be somewhere else, so I will provide all related code to this function:
this is the function I use in order to determent whether or not it is a leap year
private static boolean isLeapYear(int year) {
if (year % 4 != 0) {
return false;
} else if (year % 400 == 0) {
return true;
} else if (year % 100 == 0) {
return false;
} else {
return true;
}
}
and here is the constructor of the Date class:
public Date (int day, int month, int year)
{
if(isDateValid(day, month, year))
{
_day = day;
_month = month;
_year= year;
}
else
{
_day = DEFULTE_DAY;
_month = DEFULTE_MONTH;
_year = DEFULTE_YEAR;
}
}
I really can't determent what is the problem, and the fact that it is one complex condition and not multiple if statements make it hard to debug.
Since it is an assignment I am not allowed to use "actual java" - the java date class etc...
Where did I was mistaken?
Thank you in advance!
As you've sort of identified, that return statement is hard to debug. I'd break it up into manageable sections.
private boolean isDateValid(int day, int month, int year) {
bool retVal = true;
retVal = retVal && (month >= JANUARY) && (month <= DECEMBER);
retVal = retVal && (day >= 1) && (day <= DAYS_IN_JAN_MAR_MAY_JUL_AUG_OCT_DEC);
if (month == APRIL || month == JUNE ...) {
retVal = retVal && (day < DAYS_IN_JUN_APR_SEP_NOV);
}
if (month == FEBRUARY) {
.. handle the complex case of February
}
return retVal;
}
Note also that because January through December are values in the range [1..12] without gaps, you don't need to check month against each value but can just check within January..December. That makes this a little simpler.
That weird-ass complicated return statement is just begging for something problematic. It's too easy to get something that complicated wrong.
I have tested your isDateValid method with every valid date from year 1799 through 2100 and with every valid date in year 1000 and year 9999. It returns true every time. Also for the example date you gave, isDateValid(3, 5, 1998) returns true. So I believe that the cause for returning a default date doesn’t lie within the isDateValid method that you have posted. I can’t tell you where then, but you need to look elsewhere.
You have got a bug, though: isDateValid(29, 2, 1999) returns true. 1999 was not a leap year, so it should return false. So let’s examine the code dealing with February:
((month == FEBRUARY && day <= DAYS_IN_FEB_LEAP))
|| (isLeapYear(year) && day <= DAYS_IN_FEB_NO_LEAP && month == FEBRUARY)
(I have broken it over two lines to fit it better into Stack Overflow.) In case of 29th February in a leap year, the first line evaluates to true. Since there is || (logical or) between the two lines, true is the result of the entire expression. Java uses lazy evaluation here and doesn’t even evaluate the second line, but even if it did, the result of the logical or operation would still be true.
You could probably find a way to fix it, but you shouldn’t. Instead rewrite your entire method along the lines in the other answer.
this is what I've got so far, but all I get is zero for the output. I've tried for loops that are separate for the first year and last year to calculate just the months in those years then a separate for loop for the years inbetween since they would be full years and still I get the wrong output. I just need some guidance and as the title says I can't use calender or date or any other similar class just loops and logic.
package cop2250.spring18.week3.ledesma;
import java.util.Scanner;
public class Week3assignment1 {
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int days1 = 0, days2 = 0, days3 = 0, totalDays = 0, month3 = 0, betweenYears, year3;
System.out.println("Enter a starting Date in the format mm-dd-yyyy: ");
String[] startDate = input.next().split("-");
int month1 = Integer.parseInt(startDate[0]);
int day1 = Integer.parseInt(startDate[1]);
int year1 = Integer.parseInt(startDate[2]);
System.out.println("Enter an ending Date in the format mm-dd-yyyy: ");
String[] endDate = input.next().split("-");
int month2 = Integer.parseInt(endDate[0]);
int day2 = Integer.parseInt(endDate[1]);
int year2 = Integer.parseInt(endDate[2]);
for(year3 = 0; year3 > year1 && year3 < year2; year3++) {
for (month3 = 0; month3 < 12; month3++) {
days1 = daysInMonth(year3, month3);
}
totalDays =+ days1;
}
System.out.println("Days is : "+ totalDays);
}
private static boolean isLeapYear(int year) {
return year % 400 == 0 || (year % 4 == 0 || year % 100 == 0);
}
private static int daysInMonth(int year, int month) {
if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12)
return 31;
if (month == 4 || month == 6 || month == 9 || month == 11)
return 30;
if (month == 2)
return isLeapYear(year) ? 29 : 28;
return 0;
}
}
I see some issues here:
The outer loop starts from 0, shouldn't it start from year1?
The inner loop numbers months from 0 to 11 but the method you call numbers them from 1 to 12.
x =+ y is quite different from x += y.
If I give a date in 2016 and one in 2017 it looks to me like you are counting the days of all the months in those two years. So the inner loop also need to consider the given months (and days):
I've made a function that should get the number of weeks for a given month. For January, May, July and October, it should return 5 weeks.
However, it returns 5 for March, June, September. and November. Surprisingly, the total amount of weeks are correct (52).
public static int getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(Calendar calendar) {
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.MONDAY) {
calendar.roll(Calendar.DATE, true);
}
int currentMonth = calendar.get(Calendar.MONTH);
int nextMonth = (currentMonth + 1) % 12;
int prePreviousMonth = (currentMonth + 12 - 2) % 12;
int nofWeeks = 0;
do {
int month = calendar.get(Calendar.MONTH);
if (month == nextMonth) {
nofWeeks++;
}
if (month == prePreviousMonth) {
break;
}
calendar.roll(Calendar.WEEK_OF_YEAR, true);
} while (true);
return nofWeeks;
}
public static void main(String[] args) {
int numWeeks;
int totalWeeks=0;
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2016);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.MONTH, Calendar.MAY);
numWeeks=getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(calendar);
System.out.println("no of weeks " + numWeeks);
}
Output:
no of weeks 4
Month start is in Week that has first day. e.g.:
25 - 1 May
2 - 8 May
9 - 15 May
16 - 22 May
23 - 29 May
5 Weeks in May:
It sounds to me like you should:
Work out the first day of the month
Determine from that how many "extra" days are "borrowed" from the previous month (e.g. 0 if day 1 is a Monday; 1 if day 1 is a Tuesday etc)
Add that to the number of days in the regular month
Divide by 7 (with implicit truncation towards 0)
There's no need to do half the work you're currently doing.
Using java.util.Calendar, it would be something like:
// Note: day-of-week runs from Sunday (1) to Saturday (7).
// Entry 0 here is not used. We could do this without an array lookup
// if desired, but it's whatever code you think is clearest.
private static final int[] EXTRA_DAYS = { 0, 6, 0, 1, 2, 3, 4, 5 };
// Note: 0-based month as per the rest of java.util.Calendar
public static int getWeekCount(int year, int month) {
Calendar calendar = new GregorianCalendar(year, month, 1);
int dayOfWeekOfStartOfMonth = calendar.get(Calendar.DAY_OF_WEEK);
int extraDays = EXTRA_DAYS[dayOfWeekOfStartOfMonth];
int regularDaysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
int effectiveDaysInMonth = regularDaysInMonth + extraDays;
return effectiveDaysInMonth / 7;
}
If at all possible, I'd recommend using Joda Time or java.time instead, however.
With that code, the results for 2016 are:
January: 5
February: 4
March: 4
April: 4
May: 5
June: 4
July: 5
August: 4
September: 4
October: 5
November: 4
December: 4
From the comments I deduce that you want to count the number of weeks in a month starting at the 1st of the month.
You need to:
Set the day of the month to 1
add forward, not roll backward
start on Sunday instead of Monday
The code would be something like this:
public static int getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(Calendar calendar) {
while (calendar.get(Calendar.DAY_OF_WEEK) != Calendar.SUNDAY) {
calendar.roll(Calendar.DATE, true);
}
int currentMonth = calendar.get(Calendar.MONTH);
int nextMonth = (currentMonth + 1) % 12;
int prePreviousMonth = (currentMonth + 12 - 2) % 12;
int nofWeeks = 0;
do {
int month = calendar.get(Calendar.MONTH);
if (month == currentMonth) {
nofWeeks++;
} else {
break;
}
calendar.add(Calendar.WEEK_OF_YEAR, 1);
} while (true);
return nofWeeks;
}
public static void main(String[] args) {
int numWeeks;
int totalWeeks=0;
for (int i = 0; i < 12; i++) {
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.YEAR, 2016);
calendar.set(Calendar.DAY_OF_MONTH, 1);
calendar.set(Calendar.MONTH, i);
numWeeks=getNofWeeksWithFirstWeekStartingWhenFirstDayOfMonthOccurs(calendar);
System.out.println("no of weeks " + numWeeks);
}
}
Output:
no of weeks 5
no of weeks 4
no of weeks 4
no of weeks 4
no of weeks 5
no of weeks 4
no of weeks 5
no of weeks 4
no of weeks 4
no of weeks 5
no of weeks 4
no of weeks 4
I have a method that is supposed to return the seasons of the year depending upon the month and day. The first three times I call the method it works fine. However, the fourth method returns spring when it should return fall.
It should bypass the else-if statement for spring and continue down to fall but when I debug it, that is not what it does. it goes into that else-if and returns it.
I tried moving the months and dates around but no matter where I put it, it returns spring. I cannot figure out why since the arguments do not meet the criteria for that particular statement.
Here is my code:
public static void main(String[] args) {
System.out.println(season(1, 5));
System.out.println(season(4, 12));
System.out.println(season(7, 1));
System.out.println(season(10, 31));
}
public static String season(int month, int day) {
if(month >= 12 && day >= 16 || month <= 3 && day <= 15) {
return "winter";
} else if(month >= 3 && day >= 16 || month <= 6 && day <= 15) {
return "spring";
} else if(month >= 6 && day >= 16 || month <= 9 && day <= 15) {
return "summer";
} else {
return "fall";
}
}
Your program is doing exactly what you told it to. When you call season(10, 31), you get to the test:
if (month >= 3 && day >= 16 || ...)
which is true because the month is 10 and the day is 31 (both greater than their targets in this test). Clearly, this is not what you want. So you have to make a slightly more complicated test:
if (month == 3 && day >= 16 || month > 3 && month < 6 || month == 6 && day <= 15)
This tests the day only if the month is not the starting or ending month for spring. Your other tests will need similar adjustments.
You may find that you might like to add parentheses to your tests to help group them as suggested by other answers here, but due to the Java operator precedence, it is not strictly necessary in this case.
If you remove first half of your conditions it will work fine.
public static String season(int month, int day)
{
if(month <= 3 && day <= 15)
{
return "winter";
}
else if(month <= 6 && day <= 15)
{
return "spring";
}
else if(month <= 9 && day <= 15)
{
return "summer";
}
else
{
return "fall";
}
}
Given an instance of java.util.Date which is a Sunday. If there are 4 Sundays in the month in question, I need to figure out whether the chosen date is
1st Sunday of month
2nd Sunday of month
2nd last Sunday of month
Last Sunday of month
If there are 5 Sundays in the month in question, then I need to figure out whether the chosen date is
1st Sunday of month
2nd Sunday of month
3rd Sunday of month
2nd last Sunday of month
Last Sunday of month
I've had a look in JodaTime, but haven't found the relevant functionality there yet. The project is actually a Groovy project, so I could use either Java or Groovy to solve this.
Thanks,
Donal
Solutions given so far will tell you 1st, 2nd, 3rd, 4th, or 5th. But the question said he wanted to know "last" and "second to last". If the questioner really needs to know "last" etc, there's a little extra complexity. You have to figure out how many Sundays are in the month to know whether or not the 4th Sunday is the last. The first way to figure that out that occurs to me is:
GregorianCalendar gc=new GregorianCalendar();
gc.setTime(mydate);
gc.set(Calendar.DAY_OF_MONTH,1); // Roll back to first of month
int weekday=gc.get(Calendar.DAY_OF_WEEK); // day of week of first day
// Find day of month of first Sunday
int firstSunday;
if (weekday==Calendar.SUNDAY)
firstSunday=1;
else
firstSunday=weekday-Calendar.SUNDAY+6;
// Day of month of fifth Sunday, if it exists
int fifthSunday=firstSunday+7*4;
// Find last day of month
gc.add(Calendar.MONTH,1);
gc.add(Calendar.DATE,-1);
int lastDay=gc.get(DAY_OF_MONTH);
int sundays;
if (fifthSunday<lastDay)
sundays=4;
else
sundays=5;
That seems like rather a lot of work. Anybody see an easier way?
DAY_OF_WEEK_IN_MONTH
import java.sql.Date;
import java.util.Calendar;
public class Dow {
public static void main(String[] args) {
Date date = new Date( 2010, 4, 1 );
Calendar cal = Calendar.getInstance();
cal.setTime( date );
for ( int week = 0 ; week < 5 ; week++ ) {
System.out.println( cal.getTime() + " week:" + cal.get( Calendar.DAY_OF_WEEK_IN_MONTH ) );
cal.add( Calendar.WEEK_OF_MONTH, 1 );
}
}
}
> Sun May 01 00:00:00 CEST 3910 week:1
> Sun May 08 00:00:00 CEST 3910 week:2
> Sun May 15 00:00:00 CEST 3910 week:3
> Sun May 22 00:00:00 CEST 3910 week:4
> Sun May 29 00:00:00 CEST 3910 week:5
return dayOfMonth / 7 + 1;
MORE EDIT
Okay, taking Jay's comment in consideration, let's try this one:
int sundayId = dayOfMonth / 7 + 1;
if (sundayId == 1) {
return "1st";
} else if (sundayId == 2) {
return "2nd";
} else if (sundayId == 3) {
return ((dayOfMonth + 14 <= daysInMonth) ? "3rd" : "2nd Last");
} else if (sundayId == 4) {
return ((dayOfMonth + 7 <= daysInMonth) ? "2nd Last" : "Last");
} else {
return "Last";
}
whereas daysInMonth is calculated as follows:
if (month == 2) {
if (year % 100) {
return ((year % 400 == 0) ? 29 : 28);
} else {
return ((year % 4 == 0) ? 29 : 28);
}
} else if (month == 4 || month == 6 || month == 9 || month == 11) {
return 30;
} else {
return 31;
}
... or in some other way.
int sundayOfMonth = dayOfMonth / 7 + 1;
You can just use java.util.Calendar to do your date calculations:
import java.util.Calendar as CAL
def cal = CAL.getInstance(date)
def isFirst= cal.get(CAL.WEEK_OF_MONTH) == 1
def isSecond = cal.get(CAL.WEEK_OF_MONTH) == cal.getMaximum(CAL.WEEK_OF_MONTH)
Also, do not assume that there are only five weeks in a month with the Calendar object. For instance, the maximum weeks of 05/01/2010 would be 6.
EDIT: Here's my final version:
today = Calendar.instance
dayOfWeekInMonth = today.get(Calendar.DAY_OF_WEEK_IN_MONTH)
// move to last day of week occurrence in current month
today.set(Calendar.DAY_OF_WEEK_IN_MONTH, -1)
maxDayOfWeekInMonth = today.get(Calendar.DAY_OF_WEEK_IN_MONTH)
dayOfWeekCount = ["1st", "2nd", "3rd", "2nd last", "Last"]
turningPoint = maxDayOfWeekInMonth - 2
if (dayOfWeekInMonth <= turningPoint) {
println dayOfWeekCount[dayOfWeekInMonth - 1]
}
else {
// use negative index to access list from last to first
println dayOfWeekCount[dayOfWeekInMonth - maxDayOfWeekInMonth - 1]
}