Hello I made a software that generates HTML calendar. I followed Method 1 algorithm from wiki http://www.wikihow.com/Calculate-the-Day-of-the-Week to get exact day of the week in current day for a year. But problem is that there is a bug when it goes from year 2099 to 2100 then in year 2100 it is about one day behind.
My question is... is that algorithm correct? Should it be a day back behind in year 2100? I have no time to wait 85 years to figure this out :(
Also I tried Easter Sunday algorithm and it also generates Sunday on the day it should be Sunday by Day of the week algorithm so I am not sure who has the right, if me or the two correctly generating algorithms.
Here are next years what are buggy in my opinion:
Testing years 0 to 2200
Incorrect day from year to year: 99/100
Incorrect day from year to year: 199/200
Incorrect day from year to year: 299/300
Incorrect day from year to year: 499/500
Incorrect day from year to year: 599/600
Incorrect day from year to year: 699/700
Incorrect day from year to year: 899/900
Incorrect day from year to year: 999/1000
Incorrect day from year to year: 1099/1100
Incorrect day from year to year: 1299/1300
Incorrect day from year to year: 1399/1400
Incorrect day from year to year: 1499/1500
Incorrect day from year to year: 1699/1700
Incorrect day from year to year: 1799/1800
Incorrect day from year to year: 1899/1900
Incorrect day from year to year: 2099/2100
*EDIT
Here is algorithm to get Easter Sunday:
int c = year/100;
int n = year - 19*(int)(year/19);
int k = (c - 17)/25;
int i = c - (int)(c/4) - (int)((c - k)/3) + 19*n + 15;
i -= 30*(int)(i/30);
i -= (int)(i/28)*(1 - (int)(i/28)*(int)(29/(i + 1))*(int)((21 - n)/11));
int j = year + (int)(year/4) + i + 2 - c + (int)(c/4);
j -= 7*(int)(j/7);
int l = i - j;
int m = 3 + (int)((l + 40)/44); //Your month when is Easter Sunday
int d = l + 28 - 31*(int)(m/4); //Your day when is Easter Sunday
Here is algorithm to get day of the week in a Year Month Day
int [] CENTURY_TABLE = {0, 5, 3, 1};
int [] MONTH_TABLE = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
boolean leap = false;
int t1 = (day + MONTH_TABLE[month - 1]) % 7;
int m1 = year % 100;
int t2 = (m1 % 7) + (m1/4) + CENTURY_TABLE[((int)(year/100)) % CENTURY_TABLE.length] - (leap && (month == 1 || month == 2) ? 1 : 0);
if(t2 == -1){
t2 = 6;
}
int d = (t1 + t2) % 7; //0 - Saturday, 1 - Sunday, 2 - Monday... 6 - Friday
*FIX
Change "leap" summary in Day of Week algorithm to
leap = year % 4 == 0 && (year % 100 == 0 ? year % 400 == 0 : true) //This fixed my problem <3
I think your program is affected by leap years: https://en.wikipedia.org/wiki/Leap_year
You have a problem on all years dividable through 100 but not 400.
Edit after select as solution:
The code works without problems. I slightly changed for a test and got no error:
#Test
public void dayTest()
{
for (int y = 2099; y <=2100; y++)
{
int day = easterSundayDay(y);
int month = easterSundayMonth(y);
assertTrue("Wrong year: " + day + "."+ month + "."+ y + " is day: " + dayOfWeek(day, month, y), 1 ==dayOfWeek(day, month, y));
}
}
public int easterSundayDay(int year)
{
int c = year/100;
int n = year - 19*(int)(year/19);
int k = (c - 17)/25;
int i = c - (int)(c/4) - (int)((c - k)/3) + 19*n + 15;
i -= 30*(int)(i/30);
i -= (int)(i/28)*(1 - (int)(i/28)*(int)(29/(i + 1))*(int)((21 - n)/11));
int j = year + (int)(year/4) + i + 2 - c + (int)(c/4);
j -= 7*(int)(j/7);
int l = i - j;
int m = 3 + (int)((l + 40)/44); //Your month when is Easter Sunday
int d = l + 28 - 31*(int)(m/4);
return d;
}
public int easterSundayMonth(int year)
{
int c = year/100;
int n = year - 19*(int)(year/19);
int k = (c - 17)/25;
int i = c - (int)(c/4) - (int)((c - k)/3) + 19*n + 15;
i -= 30*(int)(i/30);
i -= (int)(i/28)*(1 - (int)(i/28)*(int)(29/(i + 1))*(int)((21 - n)/11));
int j = year + (int)(year/4) + i + 2 - c + (int)(c/4);
j -= 7*(int)(j/7);
int l = i - j;
int m = 3 + (int)((l + 40)/44); //Your month when is Easter Sunday
int d = l + 28 - 31*(int)(m/4);
return m;
}
public int dayOfWeek(int day, int month, int year)
{
int [] CENTURY_TABLE = {0, 5, 3, 1};
int [] MONTH_TABLE = {0, 3, 3, 6, 1, 4, 6, 2, 5, 0, 3, 5};
boolean leap = false;
int t1 = (day + MONTH_TABLE[month - 1]) % 7;
int m1 = year % 100;
int t2 = (m1 % 7) + (m1/4) + CENTURY_TABLE[((int)(year/100)) % CENTURY_TABLE.length] - (leap && (month == 1 || month == 2) ? 1 : 0);
if(t2 == -1){
t2 = 6;
}
int d = (t1 + t2) % 7;
return d;
}
Related
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));
}
}
I have code that takes user input as the year, the month and then the date. I have three methods, one gets the day of the week, one gets the amount of days in that month, and the other calculates whether or not that year is a leap year.
When a user enters a year a month and a date, for example "2016 3 3" I want my code to then list the months from 1-12 and next to each number the amount of days in that month. The code I have for all three methods is as follows.
class Date {
int year, month, day;
Date(int y, int m, int d) {
year = y;
month = m;
day = d;
}
/**
* This method returns the day of the week as an integer: 0 and 6: Sunday
* and Saturday 1 - 5: Weekdays
*/
public int getDayOfWeek() {
int y0 = year - (14 - month) / 12;
int x = y0 + y0 / 4 - y0 / 100 + y0 / 400;
int m0 = month + 12 * ((14 - month) / 12) - 2;
int d0 = (day + x + (31 * m0) / 12) % 7;
return d0;
}
/**
* This method returns the number of days in a given month an integer
*/
public int getDaysInMonth(int month) {
int daysInMonth = (int) (28 + (Math.floor(month / 8.0) + month) % 2 + 2 % month + 2 * Math.floor(1.0 / month));
if (month == 2 && isLeapYear()) {
daysInMonth += 1;
}
return daysInMonth;
}
public boolean isLeapYear() {
boolean isLeapYear = true;
if (year % 4 != 0) {
isLeapYear = false;
}
else {
if (year % 100 != 0) {
isLeapYear = true;
}
else if (year % 400 != 0) {
isLeapYear = false;
}
else {
isLeapYear = true;
}
}
return isLeapYear;
}
I'm in my first year of computer science and am still very fresh to this, i've been staring at this code and googling for the better part of a day and can't seem to figure anything out, any help would be appreciated.
I know this is wrong but this is all I've been able to come up with so far
public void printDaysInMonth() {
int m = getDaysInMonth(month);
System.out.println("Month " + " Days");
for (int i=0; i<12; i++) {
System.out.println(m);
}
}
You're on the right track, but you're assigning your m variable outside of the for loop, and thus printing the same month every time. Instead, try assigning it and printing it inside the loop you already have:
public void printDaysInMonth() {
for (int i = 1; i <= 12; i++) {
int m = getDaysInMonth(i);
System.out.println("Month " + i + " has " + m + "days.");
}
}
Since your getDaysInMonth method already accounts for leap years, this should be enough!
In Java 8, you can use below code for easy Date manipulation:
public static void main(String[] args) {
LocalDate date1=getDate(12,12,2020);
int dayOfWeek=getDayOfWeek(date1);
boolean isLeapYear=isLeapYear(date1);
System.out.println("date: "+date1);
System.out.println("dayOfWeek: "+dayOfWeek);
System.out.println("is Leap year: "+isLeapYear);
}
// Will return LocalDate value
private static LocalDate getDate(int date,int month, int year){
return LocalDate.of(year,month,date);
}
// Will return Dayofweek
private static int getDayOfWeek(LocalDate date){
return date.getDayOfWeek().getValue();
}
// Will return true/false if year is/is not leap year
private static boolean isLeapYear(LocalDate date){
return date.isLeapYear();
}
/* If you want to print days of all months of a particular year, use below method*/
public void printLengthsOdDaysInMonthsOfYearPassed(int year){
year=2020;
for(int i=1;i<=12;i++){
LocalDate date2=LocalDate.of(year,i,1);
int length=date2.getMonth().maxLength();
System.out.println("Month: "+i+ " length: "+length);
System.out.println("is leap year: "+date2.isLeapYear());
}
}
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);
}
I am trying to right a program for my introduction to java course. The user enters their birthdate in the following format(19900506), the amount of days the person is then displayed. The program uses the GregorianCalendar class to get today's date and compares the two. Leap years are taken into account. I was able to right the program, but I need to write another version that calculates the difference using my own algorithm. I have hit a wall and can't figure out how to do this. I was thinking of converting the difference between the two dates to milliseconds and then converting to days again. But there is a lot of things to be considerd, like days in months, days remaining from todays date, etc. Any help would be appreciated.
Here is my code:
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Scanner;
public class DayssinceBirthV5 {
public static void main(String[] args) {
GregorianCalendar greg = new GregorianCalendar();
int year = greg.get(Calendar.YEAR);
int month = greg.get(Calendar.MONTH);
int day = greg.get(Calendar.DAY_OF_MONTH);
Scanner keyboard = new Scanner(System.in);
System.out.println("Enter your birthday: AAAAMMDD): ");
int birthday = keyboard.nextInt();//
int testyear = birthday / 10000;// year
int testmonth = (birthday / 100) % 100;// Month
int testday = birthday % 100;// Day
int counter = calculateLeapYears(year, testyear);
GregorianCalendar userInputBd = new GregorianCalendar(testyear, testmonth - 1, testday);// Input
long diffSec = (greg.getTimeInMillis() - userInputBd.getTimeInMillis());// Räkna ut diff
// long diffSec = greg.get(Calendar.YEAR)-birthday;//calc Diff
long total = diffSec / 1000 / 60 / 60 / 24;// calc dif in sec. Sec/min/hours/days
total += counter;
System.out.println("Today you are : " + total + " days old");
}
private static int calculateLeapYears(int year, int testyear) {
int counter = 0;
for (int i = testyear; i < year; i++) {
if (i % 4 == 0 && i % 100 != 0 || i % 400 == 0) {
counter++;
System.out.println("Amount of leap years: " + counter);
}
}
return counter;
}
}
You can calculate the number of days like this -
Write a method that finds the number of days in a year: Leap years have 366 days, non-leap years have 365.
Write another method that gets a date and finds the day of year - January 1st is day 1, January 2nd is day 2 and so on. You'll have to use the function from 1.
Calculate the following:
Number of days until year's end from date of birth.
Number of days from year's begining until current date.
Numer of days of all years between.
Sum up all of the above.
def daysBetweenDates(self, date1: str, date2: str) -> int:
y1, m1, d1 = map(int, date1.split('-'))
y2, m2, d2 = map(int, date2.split('-'))
m1 = (m1 + 9) % 12
y1 = y1 - m1 // 10
x1= 365*y1 + y1//4 - y1//100 + y1//400 + (m1*306 + 5)//10 + ( d1 - 1 )
m2 = (m2 + 9) % 12
y2 = y2 - m2 // 10
x2= 365*y2 + y2//4 - y2//100 + y2//400 + (m2*306 + 5)//10 + ( d2 - 1 )
return abs(x2 - x1)
This question already has answers here:
Java Code for calculating Leap Year
(22 answers)
Closed 5 years ago.
I've written this program using Java in Eclipse.
I was able to utilize a formula I found that I explained in the commented out section.
Using the for loop I can iterate through each month of the year, which I feel good about in that code, it seems clean and smooth to me. Maybe I could give the variables full names to make everything more readable but I'm just using the formula in its basic essence :)
Well my problem is it doesn't calculate correctly for years like 2008... Leap Years.
I know that
if (year % 400 == 0 || (year % 4 == 0 && year % 100 != 0))
then we have a leap year.
Maybe if the year is a leap year I need to subtract a certain amount of days from a certain month.
Any solutions, or some direction would be great thanks :)
package exercises;
public class E28 {
/*
* Display the first days of each month
* Enter the year
* Enter first day of the year
*
* h = (q + (26 * (m + 1)) / 10 + k + k/4 + j/4 + 5j) % 7
*
* h is the day of the week (0: Saturday, 1: Sunday ......)
* q is the day of the month
* m is the month (3: March 4: April.... January and Feburary are 13 and 14)
* j is the century (year / 100)
* k is the year of the century (year %100)
*
*/
public static void main(String[] args) {
java.util.Scanner input = new java.util.Scanner(System.in);
System.out.print("Enter the year: ");
int year = input.nextInt();
int j = year / 100; // Find century for formula
int k = year % 100; // Find year of century for formula
// Loop iterates 12 times. Guess why.
for (int i = 1, m = i; i <= 12; i++) { // Make m = i. So loop processes formula once for each month
if (m == 1 || m == 2)
m += 12; // Formula requires that Jan and Feb are represented as 13 and 14
else
m = i; // if not jan or feb, then set m to i
int h = (1 + (26 * (m + 1)) / 10 + k + k/4 + j/4 + 5 * j) % 7; // Formula created by a really smart man somewhere
// I let the control variable i steer the direction of the formual's m value
String day;
if (h == 0)
day = "Saturday";
else if (h == 1)
day = "Sunday";
else if (h == 2)
day = "Monday";
else if (h == 3)
day = "Tuesday";
else if (h == 4)
day = "Wednesday";
else if (h == 5)
day = "Thursday";
else
day = "Friday";
switch (m) {
case 13:
System.out.println("January 1, " + year + " is " + day);
break;
case 14:
System.out.println("Feburary 1, " + year + " is " + day);
break;
case 3:
System.out.println("March 1, " + year + " is " + day);
break;
case 4:
System.out.println("April 1, " + year + " is " + day);
break;
case 5:
System.out.println("May 1, " + year + " is " + day);
break;
case 6:
System.out.println("June 1, " + year + " is " + day);
break;
case 7:
System.out.println("July 1, " + year + " is " + day);
break;
case 8:
System.out.println("August 1, " + year + " is " + day);
break;
case 9:
System.out.println("September 1, " + year + " is " + day);
break;
case 10:
System.out.println("October 1, " + year + " is " + day);
break;
case 11:
System.out.println("November 1, " + year + " is " + day);
break;
case 12:
System.out.println("December 1, " + year + " is " + day);
break;
}
}
}
}
Do you need to develop your own algorithm?
GregorianCalendar class have method:
boolean isLeapYear(int year)
This method returns true if year is a leap year and false otherwise.
You should use JodaTime for all things to do with dates in Java and it's easy to use.
Using JodaTime you won't have to worry about leap years or anything as it takes care of it all for you. A simple for loop and a DateTime object will give you what you need.
int year = 2012;
DateTime dt = new DateTime(year, 01, 01, 00, 00, 00, 00);
for (int i = 0; i < 12; i++) {
System.out.println(dt.toString() + " " + dt.property(DateTimeFieldType.dayOfWeek()).getAsText());
dt = dt.plusMonths(1);
}
You would obviously replace the year variable with your input, but basically the code works as so:
Initialise a DateTime object for the year input starting at 01 January.
Print out the current DateTime and the day of the week as a text format
Increment the month in the DateTime object by 1.
Outputs:
2012-01-01T00:00:00.000+11:00 Sunday
2012-02-01T00:00:00.000+11:00 Wednesday
2012-03-01T00:00:00.000+11:00 Thursday
. . .
int h = (1 + (26 * (m + 1)) / 10 + k + k/4 + j/4 + 5 * j) % 7; // Formula created by a really smart man somewhere
Here's your problem. That formula is Zeller's Congruence, named after Christian Zeller. You aren't using it correctly. The problem is that in this formula, you have to treat January and February as the 13th and 14th month of the previous year. For example, you need to tread February, 2000 as the 14th month of 1999.
Addendum
Your program would have yielded Thursday for February 1, 2000. The correct answer is Tuesday.
As an example, let's use the formula to calculate the day of the week for February 29, 2000. (The algorithm is general; just replace your 1 with the day of the month.)
We're in February, so we have to calculate as if this were the 14th month of 1999. With this, j is 19, k is 99, m is 14. I'll use d=29 rather than 1 in the congruence. With this, h = (d + (26 * (m + 1)) / 10 + k + k/4 + j/4 + 5*j) % 7 = (29 + (26*(14+1))/10 + 99 + 99/4 + 19/4 + 5*19) % 7 = 290 % 7 = 3. Counting from Saturday=0, that's Tuesday.
To verify, a quick and dirty perl script:
#!/usr/bin/perl
# Usage: dayofweek.pl <year number> <month number> <day of month>
# Validation of inputs is an exercise left to the reader.
my ($y, $m, $d) = #ARGV;
use integer;
my $wd = [qw(Sun Mon Tues Wednes Thurs Fri Satur)]->
[(index `cal $m $y | tail +3 | grep -E "(^| )$d( |\$)"`, $d) / 3];
print "$y/$m/$d -> ${wd}day\n";
Running this against 2000 2 29 yields 2000/2/29 -> Tuesday, as expected.
I have not gone through your code, but for a leap year check you should do this: (Source: Wiki-Leap Year Alg.)
if year modulo 400 is 0 then
is_leap_year
else if year modulo 100 is 0 then
not_leap_year
else if year modulo 4 is 0 then
is_leap_year
else
not_leap_year
Also see a similar question (and answer) here:
stackOverFlow-calc-leap-year