Does this Euler #19 actually work? - java

I'm doing Project Euler #19 and I'm wondering how my code works.
Project Euler #19
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)?
My code:
static int weekday = 1;
static int sundays = 0;
static int years = 1901;
static int[] monthArray = {31, 29, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
public static void solve() {
for (int yr = years; yr <= 2000; yr++) {
for (int j = 0; j < 12; j++) {
if (j != 1) {
months(monthArray[j]);
} else {
if(yr % 4 == 0 && yr % 400 != 0) {
months(monthArray[1]);
} else {
months(monthArray[2]);
}
}
}
}
System.out.println(sundays);
}
public static void months(int monthLength) {
for (int i = 0; i <= monthLength; i++) {
if (weekday == 7 && i == 1) {
sundays++;
}
if (weekday == 7) {
weekday = 0;
}
weekday++;
}
}
I thought I would have to put "j++" into the leap year so the code would jump over the next month in the array. Another thing is that I wondered why I can't start the 'months' method's for loop and weekday from 1. Is this even a bit of code that counts sundays reliably from other timespans? I get the right answer for the requested timespan, but I'm not sure if it actually works. Thanks.
EDIT: I changed the code so that the for loop with 'j' iterates through the months pretty linearly with the exception that is not in the array. Still not 100% sure if it's correct, but it seems a lot more logically sound.
public static void solve() {
for (int yr = years; yr <= 2000; yr++) {
for (int j = 0; j < 12; j++) {
if (yr % 4 == 0 && yr % 400 != 0 && j == 1) {
months(29);
} else {
months(monthArray[j]);
}
}
}
System.out.println(sundays);
}
public static void months(int monthLength) {
for (int i = 0; i < monthLength; i++) {
if (weekday == 7 && i == 1) {
sundays++;
}
if (weekday == 7) {
weekday = 1;
} else {
weekday++;
}
}
}

I don't wanna give too much because this site involve personal research and being stuck is a part of the game (give a try to another challenge, come back ... you will see things more clearly)
One way to do it is like that:
counter is 0
day_counter start on a monday
for every years between 1900 and 2000:
for each months in that year:
add month's number of day modulo 7 to day_counter
if 7 divide day_counter:
increment counter
at the end, counter is your solution.

My code in JS:
var sunday=0;
for (var year = 1901; year <= 2000; year++) {
for (var month = 1; month <= 12; month++) {
if ((new Date(year, month, 1)).getDay() == 0) {
sunday++;
}
}
}
window.alert(sunday);

Related

How i can do that?

How can I do a date validation with leap years in Java? Unfortunately, I can't use regular expressions or calendar. I will explain step by step!
This is my main component (where I implement most things):
An example of the implement I have to use:
and in another component called utility (I put the methods that will be used in the implementation, all this to carry an order, my utility code is as follows:
I put the data separately in a LOCAL ENVIRONMENT online, where I put a date that is valid in any respective year. enter image description here
For example in the image, I am putting the date 02/29/2012 which is validated and is in the correct order, but if I put a date 02/30/2012 which is incorrect data, it will throw me an error called 10005.
This is my last kick at the cat. No Calendar, no regex, and no try/catch. date range is from the year 1200 to the year 2200 (can be changed in code). The concept is used from Gilbert Le Blanc's answer:
public boolean isDateStringValid(String dateString) {
if (dateString == null || dateString.isEmpty()) {
return false;
}
// Maximum days in each month starting from January
int[] maxDays = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
// Parse the supplied date string
String m = dateString.substring(0, dateString.indexOf("/"));
String d = dateString.substring(dateString.indexOf("/") + 1, dateString.lastIndexOf("/"));
String y = dateString.substring(dateString.lastIndexOf("/") + 1);
//convert days, month, and year to integer.
int month = Integer.valueOf(m);
int day = Integer.valueOf(d);
int year = Integer.valueOf(y);
// Make sure year is in range
if (year < 1200 || year > 2200) {
return false;
}
/* If the year provided is a Leap year then change the Maximum
days for February (in maxDays[]) from 28 days to 29 days. */
if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)) {
maxDays[1] = 29;
}
// Is the provided month is range.
if (month < 1 || month > 12) {
return false;
}
// Is the day in range for the specific month
if (day < 1 || day > maxDays[month - 1]) {
return false;
}
// If everything is good we return true.
else {
return true;
}
}
The above code assumes the date format of "MM/dd/yyyy". If however it is suppose to be a format of "dd/MM/yyyy" then where the date string is parsed, swap m and d.
I should think that you would place this method into the Utility class. To use this method for your particular use-case, I believe it would be:
if(parameterIn.get("date") != null) {
String dateString = (String) parameterIn.get(Constants.DATE.getValue());
if (dateString != null && !dateString.trim().isEmpty()
&& util.isDateStringValid(dateString)) {
// Whatever you want here IF date is valid...
}
else {
// Whatever you want here IF the date is Invalid...
}
}
else {
this.addAdvice(Constants.MGBD100005.getValue());
}
Since you already have a Utility class, write one more utility method. Now all you have to do is see if the day portion of your date falls in between 1 and maxDays.
public int getMaximumDays(int month, int year) {
int[] maxDays = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
if (month < 1 || month > 12) {
return -1;
}
if (month == 2 && isLeapYear(year)) {
return 29;
} else {
return maxDays[month - 1];
}
}
You can use the lib code
public static boolean isLeapYear(int yr) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, yr);
return cal.getActualMaximum(Calendar.DAY_OF_YEAR) > 365;
}
But if you are going to reinvent this wheel then:
public 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;
}
}

I am trying to figure out the difference in days between two dates manually

I have used these two websites to measure how close my code gets.
Difference
Days
since year
zero
I use days since year zero to normalise the two entered dates, then I find the difference between those dates.
import java.util.Scanner;
public class DateDiff {
private static final int[] monthsDay = {31,28,31,30,31,30,31,31,30,31,30,31};
public static String dateChecker() {
boolean b = true;
int dateC = 0;
String date = "";
do {
Scanner scanner = new Scanner(System.in);
date = scanner.nextLine();
try {
if (date.charAt(2) == '/' && date.charAt(5) == '/') {
date = date.replace("/", "");
dateC = Integer.parseInt(date);
b = false;
} else {
System.out.println("Reenter date in the dd/mm/yyyy format");
}
} catch (Exception e) {
System.out.println("Reenter date in the dd/mm/yyyy format");
}
} while (b);
return date;
}
public static int daysForMonth(int months, int year) {
int days = 0;
for (int i = 0; i < months; i++)
if (i == 1)
days += ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0)
? monthsDay[i] + 1
: monthsDay[i];
else
days += monthsDay[i];
return days;
}
public static int daysForYears(int year) {
int days = 0;
for (int i = 0; i < year; i++)
if ((i % 4 == 0 && (i % 100 != 0)) || (i % 400 == 0))
days += 366;
else
days += 365;
return days;
}
public static int daysSinceYearZero(String date) {
int day = Integer.parseInt(date.substring(0,2));
int month = Integer.parseInt(date.substring(2,4));
int year = Integer.parseInt(date.substring(4,8));
int daysMonth = daysForMonth(month-1, year);
int daysYear = daysForYears(year);
return day + daysMonth + daysYear;
}
public static void main(String[] args) {
System.out.println("Enter first date");
String date1 = dateChecker();
System.out.println("Enter second date");
String date2 = dateChecker();
int firstDate = daysSinceYearZero(date1);
int secondDate = daysSinceYearZero(date2);
System.out.println("First Date days since Year Zero: " + firstDate);
System.out.println("Second Date days since Year Zero: " + secondDate);
System.out.println("Difference: " + Math.abs(firstDate-secondDate));
}
}
My code gets close, but always seems to miss by a few days and I can't figure out why. I have confirmed the days and daysMonth are correct, but do not understand where I am going wrong in calculating the number of days since year zero using years (the daysYear variable)
Edit: No libraries are allowed to be used. Scanner is fine however as that is just for user input.
Since you didn't explain any requirements or limitations you can do it like this.
LocalDate earliest = LocalDate.parse("2012-05-17");
LocalDate latest = LocalDate.parse("2022-06-22");
System.out.println(latest.toEpochDay()-earliest.toEpochDay());
prints
3688 (exclusive of the latest date day)
However, here is one way to home grow it. I used lambdas to facilitate the process. And no loops were required in the calculation. So this runs in constant time.
First I created an IntTrinaryOperator interface.
interface IntTrinaryOperator {
public int applyAsInt(int a, int b, int c);
}
Then an array of month days was created (leap years are handled later) the first cell is ignored but required for the following operation.
int daysPerMonth[] =
{ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
int monthSums[] = daysPerMonth.clone();
// this creates a running sum
// looks like [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365]
// the last cell is not used.
Arrays.parallelPrefix(monthSums, (a, b) -> a + b);
A leap year function
Function<Integer, Boolean> isLeapYear =
a -> a % 400 == 0 || (a % 100 != 0 && a % 4 == 0);
And the defined Trinary to be used for the actual calculation.
(y-1)*365-(y-1)/100+(y-1)/4 +(y-1)/400 - computes total leap years starting from previous year.
first total days using 365 days per year
then subtract century years
then add years divisible by 400 back in.
monthSums[m-1]+d - adds days for this year
((m > 2) && isLeapYear.apply(y) ? 1 : 0) - 1 - adds one more day if after February but subtracts 1 to exclude current day (as in most ranges in Java)
IntTrinaryOperator daysToEpoch = (y, m, d) -> (y - 1) * 365
- (y - 1) / 100 + (y - 1) / 4 + (y - 1) / 400 +
+ monthSums[m - 1] + d
+ ((m > 2) && isLeapYear.apply(y) ? 1 : 0) - 1;
Testing
generate some dates. Dates are not chronological so the days could be negative, hence the Math.abs()
Random r = new Random();
for (int i = 0; i < 10; i++) {
int eYear = r.nextInt(2022) + 1;
int eMonth = r.nextInt(12) + 1;
int eDay = r.nextInt(daysPerMonth[eMonth])
+ (eMonth == 2 && isLeapYear.apply(eYear) ? 1 :
0);
int sYear = r.nextInt(2022) + 1;
int sMonth = r.nextInt(12) + 1;
int sDay = r.nextInt(daysPerMonth[sMonth])
+ (sMonth == 2 && isLeapYear.apply(sYear) ? 1 :
0);
int eDaysToEpoch =
daysToEpoch.applyAsInt(eYear, eMonth, eDay);
int sDaysToEpoch =
daysToEpoch.applyAsInt(sYear, sMonth, sDay);
System.out.printf("%02d/%02d/%04d - %02d/%02d/%04d - %,9d total days%n",
eMonth, eDay, eYear, sMonth, sDay, sYear, Math.abs(eDaysToEpoch-sDaysToEpoch));
}
And the original dates
System.out.println(daysToEpoch.applyAsInt(2022, 6, 22)-
daysToEpoch.applyAsInt(2012, 5, 17));
prints something like.
04/10/1377 - 12/03/1486 - 40,048 total days
02/12/0727 - 03/27/0196 - 193,899 total days
11/26/0457 - 12/09/0307 - 54,775 total days
02/25/0691 - 10/23/1596 - 330,785 total days
03/28/0404 - 01/16/1567 - 424,705 total days
10/18/0372 - 01/15/1316 - 344,512 total days
08/01/1374 - 01/23/1484 - 39,986 total days
03/21/0622 - 07/24/0495 - 46,260 total days
02/05/1167 - 08/05/1558 - 142,991 total days
12/02/1824 - 07/21/0976 - 309,859 total days
3688
This has been tested using the API method first shown above. With over 1M random tests there were no discrepancies.
Here is a date validation method. It checks for leap years and days against months. It also allows single digits for month and day. It does not produce detailed error messages. I continues to re-prompt until a valid date is entered. Otherwise the day, month, and year are returned in an array.
public static int[] getDate(Scanner scanner) {
String stringDate = "\\d\\d?/\\d\\d?/\\d{4}";
while (true) {
System.out.println(
"Please enter date in dd/mm/yyyy format.");
String date = scanner.nextLine();
if (date.matches(stringDate)) {
int[] dmy = Arrays.stream(date.split("/"))
.mapToInt(Integer::parseInt).toArray();
System.out.println(Arrays.toString(dmy));
int d = dmy[0];
int m = dmy[1];
int y = dmy[2];
if (d > 0 && m > 0 && m < 13 && y > 0) {
boolean isLeap = isLeapYear.apply(y);
if (isLeap && d <= 29 && m == 2) {
return dmy;
}
if (d <= daysPerMonth[m]) {
return dmy;
}
}
}
System.out.print("Illegal date: ");
}
}
There are date libraries to do this. I am not very sure about the necessity of writing this code. In any case if you want to completely code the solution without using any libraries then here is the code to do that.
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class DateDiff {
private static final Map<Integer, Integer> monthsMap = new HashMap<>();
static {
monthsMap.put(0, 0);
monthsMap.put(1, 31);
monthsMap.put(2, 28);
monthsMap.put(3, 31);
monthsMap.put(4, 30);
monthsMap.put(5, 31);
monthsMap.put(6, 30);
monthsMap.put(7, 31);
monthsMap.put(8, 31);
monthsMap.put(9, 30);
monthsMap.put(10, 31);
monthsMap.put(11, 30);
monthsMap.put(12, 31);
}
public static String dateChecker() {
boolean incorrectDateFormat =false;
String date;
do {
Scanner scanner = new Scanner(System.in);
date = scanner.nextLine();
if (date.charAt(2) != '/' || date.charAt(5) != '/') {
System.out.println("Re-enter date in the dd/mm/yyyy format");
incorrectDateFormat =true;
} else {
incorrectDateFormat = false;
}
} while(incorrectDateFormat);
return date;
}
public static int daysSinceYearZero(String dateStr) {
int year = Integer.parseInt(dateStr.substring(dateStr.lastIndexOf("/")+1));
int totalNumberOfCompleteYearsSinceYear0 = year; //As year zero is also a complete year, so completed number of years will be equal given year in the date.
int leapYearCount = 0;
for(int i=1; i<=totalNumberOfCompleteYearsSinceYear0; i++) { //year zero is not a leap year. so starting the loop from 4 as year 4 is the first leap year.
if((i % 4 == 0 && (i % 100 != 0)) || (i % 400 == 0)) {
leapYearCount++;
}
}
int totalNumberOfDaysInCompletedYears = totalNumberOfCompleteYearsSinceYear0*365 + leapYearCount;
int monthFromGivenDate = Integer.parseInt(dateStr.substring(dateStr.indexOf("/")+1,dateStr.lastIndexOf("/")));
int completedMonth = monthFromGivenDate - 1;
int daysForCompletedMonthsOfCurrentYear = 0;
for(int i=0; i<=completedMonth;i++) {
daysForCompletedMonthsOfCurrentYear = daysForCompletedMonthsOfCurrentYear + monthsMap.get(i);
if(i==2 && year%4==0) {
daysForCompletedMonthsOfCurrentYear++;
}
}
int numberOfDaysCompletedInCurrentMonth = Integer.parseInt(dateStr.substring(0,dateStr.indexOf("/")));
int totalNumberOfDaysTillGivenDate = totalNumberOfDaysInCompletedYears + daysForCompletedMonthsOfCurrentYear + numberOfDaysCompletedInCurrentMonth;
return totalNumberOfDaysTillGivenDate;
}
public static void main(String[] args) {
System.out.println("Enter first date");
String date1 = dateChecker();
System.out.println("Enter second date");
String date2 = dateChecker();
int firstDate = daysSinceYearZero(date1);
int secondDate = daysSinceYearZero(date2);
System.out.println("First Date days since Year Zero: " + firstDate);
System.out.println("Second Date days since Year Zero: " + secondDate);
System.out.println("Difference: " + Math.abs(firstDate-secondDate));
}
}

Number theory modular arithmetic how to account for adjustments

I am not sure whether my solution is justifiable (ans. 171) - Project Euler Q.19 since I am having a hard time getting my head around modular arithmetic and not really sure whether my approach to it was correct or not... I was having trouble on trying to get the equivalence of having 0 as a key rather than 1 to Monday for reference in a hash table. The question was;
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)?
So what I did was start the sum of days at 1 (reference for days in hash table) and subtract 1 after finding the sum of Sunday's, since doing it by 0 caused problems when the total sum of days were divisible by 3 and 6 (3:Wednesday, 6:Sunday). How could I have done this by using 0 as reference for Monday?
import java.util.*;
public class p19 {
public static void main(String[] args) {
Hashtable<Integer, String> days = new Hashtable<Integer, String>();
days.put(1, "Monday");
days.put(2, "Tuesday");
days.put(3, "Wednesday");
days.put(4, "Thursday");
days.put(5, "Friday");
days.put(6, "Saturday");
days.put(7, "Sunday");
Hashtable<Integer, String> months = new Hashtable<Integer, String>();
months.put(1, "January");
months.put(2, "February");
months.put(3, "March");
months.put(4, "April");
months.put(5, "May");
months.put(6, "June");
months.put(7, "July");
months.put(8, "August");
months.put(9, "September");
months.put(10, "October");
months.put(11, "November");
months.put(12, "December");
int min, max;
min = 1900;
max = 2000;
String[][] arr = new String[12 * (max - min + 1)][];
// Total days starts at 1 to make modular arithmetic easier when accounting for days
// (i.e., 1 Monday, 2 Tuesday, etc.) and since the first day, hence, 0th day on 1 Jan 1900 is Monday.
for (int year = min, index = 0, totalDays = 1; year <= max; year++) {
for (int month = 1; month <= 12; month++, index++) {
arr[index] = new String[numberOfDays(month,year)];
int sum = 1;
System.out.println(months.get(new Integer(month)) + " " + year);
for (int day = 1; day <= numberOfDays(month, year); day++, totalDays++) {
if (totalDays % 7 == 0) {
arr[index][day - 1] = days.get(new Integer((totalDays % 7 + 7) % 365));
}
else {
arr[index][day - 1] = days.get(new Integer((totalDays % 7) % 365));
}
if (sum > 7) {
System.out.println();
sum = 1;
}
System.out.print(totalDays + ":= " + arr[index][day - 1] + ", " + day + " | ");
sum++;
}
System.out.println("\n");
}
}
int count = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i][0] == "Sunday") {
count++;
}
}
// Subtract 1 from count since the total days were overstated by 1 before inititallizing array
System.out.println("Number of Sundays that fell on the first of the month from: 1/Jan/1901 - 31/Dec/2000: " + (count - 1));
}
public static int numberOfDays (int month, int year) {
int days = 0;
switch (month) {
case 7:
case 4:
case 6:
case 11:
days = 30;
break;
case 2:
if (isLeapYear(year)) {
days = 29;
}
else {
days = 28;
}
break;
default: days = 31;
break;
}
return days;
}
public static boolean isLeapYear(int year) {
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
}
Your daysInMonth check is incorrect - the result must have been correct by incidence:
switch (month) {
case 4:
case 6:
case 9:
case 11:
days = 30;
break;
The rest of the program can be simplified - note that the start year has to be corrected too, dow stands for DayOfWeek:
public static void main (String[] args) {
int count = 0;
// dow = 2, since 1.1.1901 was a Thuesday (2)
for (int year = 1901, dow = 2; year <= 2000; ++year)
{
for (int month = 1; month <= 12; ++month)
{
if (dow == 0) {
// System.out.println ("Date: " + year + "-" + month);
++count;
}
dow = (dow + numberOfDays (month, year)) % 7;
}
}
System.out.println ("Number of Sundays that fell on the first of the month from: 1/Jan/1901 - 31/Dec/2000: " + count);
}

Method working with days in a month not behaving

So basically we have this question to do : Write a method dayNumber that determines the number of days in a year up to and including the current day. The method should have three int parameters: year, month, and day. If the value of any parameter is invalid, the method should print a warning message and return the value zero. The table gives some examples of the action of the method. Accept any non-negative year as being valid. You may want to assume the existence of a method numberOfDays that returns the number of days in a given month of a given year. And you should have a method call isLeapYear, if the user enter a year that is a leap year.
This is what I did so far....
class dayMonthYear {
public static void main(String[] args) {
System.out.println("Enter a year");
int year = In.getInt();
System.out.println("Enter the month for '1' to be January - '12' to be december");
int month = In.getInt();
System.out.println("Enter the day");
int day = In.getInt();
dayNumber(year, month, day);
System.out.println(dayNumber(year, month, day));
}
public static int dayNumber(int year, int month, int day) {
int total = 0;
for (int m = 1; m < month; m++)
total += (numberOfDays(month, year));
return total + day;
}
public static boolean isLeapYear(int yearB) {
return (yearB % 4 == 0 && yearB % 100 != 0) || yearB % 400 == 0;
}
public static int numberOfDays(int monthA, int yearA) {
int days = 0;
if (monthA == 4 || monthA == 6 || monthA == 9 || monthA == 11)
days = 30;
if (monthA == 1 || monthA == 3 || monthA == 5 || monthA == 7
|| monthA == 8 || monthA == 10 || monthA == 12)
days = 31;
else if (monthA == 2 && isLeapYear(yearA))
days = 29;
else if (monthA == 2)
days = 28;
return days;
}
}
It works and compiles but my problem is that: let say I enter "12" for December and December has 31 days, so what my program will do since December has 31 days, it thinks each month has 31 days and add them up which will give me 372 when it's suppose to give me 365. How do I make it that it won't do that and that it will work if the year is a leap year too.
Basically, this...
for (int m= 1; m < month; m++)
total += (numberOfDays(month, year));
is wrong, you are passing the value of month to this method each time it is called (12 for example), meaning that each time you call it, it thinks the number of days in the month is 31 (because it is)...
Instead, pass m
for (int m= 1; m < month; m++)
total += (numberOfDays(m, year));

Week day Finder in Java

I'm doing a project that consists on: 'Write a program that prompts for a date (month, day, year) and reports the day of the week for that date. It might be
helpful to know that January 1, 1601 was a Monday.'. This is an exercise of 'Building Java Programs - A Back to Basics Approach, 2nd Edition', a book which I bought to teach myself Java. Any feedback is highly appreciated, but I do ask that you explain why you would do something another/a certain way. Thanks!
So, my problem is that while for the dates nearer to 1600's it's giving the correct day (I believe), the same is not true for more recent days, with them having an offset of three days (at least the ones I checked). Why does this happen and how do I fix it? Thanks!
My code:
// finds the day of the week of the given date
public static String dayFinder(int month, int day, int year) {
// handle invalid input
if (month > 12 || month < 1 || day > 31 || day < 1) {
throw new IllegalArgumentException("Month must be between "
+ "1 and 12 and Day must be between 1 and 31.");
}
// convert to "absolute" day, covering day and month
int absoluteDay = monthToDay(month, day, year);
// convert year to days and add to "absolute" day
absoluteDay += yearToDay(year);
if (absoluteDay % 7 == 1) {
return "Monday";
} else if (absoluteDay % 7 == 2) {
return "Tuesday";
} else if (absoluteDay % 7 == 3) {
return "Wednesday";
} else if (absoluteDay % 7 == 4) {
return "Thursday";
} else if (absoluteDay % 7 == 5) {
return "Friday";
} else if (absoluteDay % 7 == 6) {
return "Saturday";
} else { // absoluteDay % 7 == 0
return "Sunday";
}
}
// calculates the number of days present in a given
// date since the beginning of the year
public static int monthToDay(int month, int day, int year) {
// convert to "absolute" day
int absoluteDay = 0, daysTo31 = 0;
// iterate through months
for (int i = 0, loopMonth = month; i < month; i++) {
if (loopMonth == 1 || loopMonth == 3 || loopMonth == 5
|| loopMonth == 7 || loopMonth == 8 || loopMonth == 10
|| loopMonth == 12) {
absoluteDay += 31;
daysTo31 = 0;
} else if (loopMonth == 2) {
if (year % 4 != 0) {
absoluteDay += 28;
daysTo31 = 3;
} else { // leap year
absoluteDay += 29;
daysTo31 = 2;
}
} else { // month = 4, 6, 9 or 10
absoluteDay += 30;
daysTo31 = 1;
}
loopMonth--;
}
// adjust to specific day
absoluteDay -= (31 - day - daysTo31);
return absoluteDay;
}
// calculates the number of days between
// (the beginning of) the given year and
// (the beginning of) the reference year 1601
public static int yearToDay(int year) {
// convert to "absolute" day
int absoluteDay = 0;
year -= 1601;
// iterate through years
for (int i = 0, loopYear = year; i < year; i++) {
if (loopYear % 4 != 0) {
absoluteDay += 365;
} else { // leap year
absoluteDay += 366;
}
loopYear--;
}
return absoluteDay;
}
// Year 1604 (MDCIV) was a leap year starting on Thursday
Your problem is probably connected with the leap years.
Due to Wikipedia:
Every year that is exactly divisible by four is a leap year, except for years that are exactly divisible by 100; the centurial years that are exactly divisible by 400 are still leap years. For example, the year 1900 is not a leap year; the year 2000 is a leap year. [link]
It's the reason why you have three day too much (1700, 1800, 1900).
Java.util date/calendar functionality is fraught with craziness. I think Java7 has improved it a bit (I've heard, but not investigated), but I recommend a 3rd party library Joda-Time. To do what you're trying to do with Joda would be:
DateTime anyDateTime = new DateTime(
1800, //year
4, //month
19, //day
0, //hour
0); // minutes
System.out.println("DOW = " + anyDateTime.dayOfWeek().getAsText());
prints "DOW = Saturday"
I realize your goal is to learn Java, but it's not always necessary to reinvent the wheel.
tl;dr
int dayOfWeekNumber =
LocalDate.of( 2016 , 12 , 22 ) // A date-only object, no time-of-day nor time zone.
.getDayOfWeek() // `DayOfWeek` enum object.
.getValue() ; // 1-7 for Monday-Sunday.
java.time
The Question is really about algorithm. But FYI, this functionality is built into Java with the java.time classes.
LocalDate
The LocalDate class represents a date-only value without time-of-day and without time zone.
LocalDate ld = LocalDate.of( 2016 , 12 , 22 );
DayOfWeek
The DayOfWeek enum defines seven objects for each day of the week.
DayOfWeek dow = ld.getDayOfWeek() ;
Generally best to use the DayOfWeek object. But if you absolutely need an integer number, you can ask for one. Numbered 1-7 for Monday-Sunday per ISO 8601.
int dowNumber = dow.getValue();
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old date-time classes such as java.util.Date, .Calendar, & java.text.SimpleDateFormat.
The Joda-Time project, now in maintenance mode, advises migration to java.time.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations.
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP (see How to useā€¦).
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
import java.util.*;
This code is working for any date.
Maybe it will help someone.
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner console = new Scanner(System.in);
System.out.println("Give me a special date !!!");
System.out.print("Month: ");
int month = console.nextInt();
System.out.print("Day: ");
int day = console.nextInt();
System.out.print("Year:");
int year = console.nextInt();
String date = dayFinder(month, day, year);
System.out.println("It is the date " + month + "/" + date + "/" + year);
console.close();
}
public static String dayFinder(int month, int day, int year) {
// handle invalid input
if (month > 12 || month < 1 || day > 31 || day < 1) {
throw new IllegalArgumentException("Month must be between "
+ "1 and 12 and day must be between 1 and 31");
} else {
// convert to "absolute" day, covering day and month
int absoluteDay = monthToDay(month, day, year);
// convert year to days and add to "absolute" day
absoluteDay += yearToDay(year);
if (absoluteDay % 7 == 2) {
return "Monday";
} else if (absoluteDay % 7 == 3) {
return "Tuesday";
} else if (absoluteDay % 7 == 4) {
return "Wednesday";
} else if (absoluteDay % 7 == 5) {
return "Thursday";
} else if (absoluteDay % 7 == 6) {
return "Friday";
} else if (absoluteDay % 7 == 0) {
return "Saturday";
} else { // absoluteDay % 7 == 1
return "Sunday";
}
}
}
// calculates the number of days between
// (the beginning of) the given year
// (the beginning of) the reference year 1601;
public static int yearToDay(int years) {
// covert to "absolute" day;
int absoluteDay = 0;
int leapYears = 0;
// iterate through years;
for (int i = 0; i < years; i++) {
if (((i % 4) == 0) && ((i % 100) != 0)) {
leapYears +=1;
} else if (i % 400 == 0) {
leapYears ++;
}
}
absoluteDay = (leapYears * 366) + (((years - 1) - leapYears) * 365);
return absoluteDay;
}
// Calculates the numbers of days present in a given
// date since the beginning of the year;
public static int monthToDay (int month, int day, int year) {
// convert to absolute day;
int absoluteDay = 0;
// iterate through months
for (int i = 1; i < month; i++) {
if ((i == 4) || (i == 6) || (i == 9) || (i == 11)) { // 30 day
absoluteDay += 30;
} else if (i == 2) {
if ((year % 4 == 0) && (year % 100 != 0)) {
absoluteDay += 29;
} else if (year % 400 == 0) {
absoluteDay += 29;
} else {
absoluteDay += 28;
}
} else {
absoluteDay += 31; // 1,3,5,7,8,10,12 months
}
}
return absoluteDay + day;
}
}

Categories

Resources