3

I am having difficulty getting the correct output of my Zeller's method code, which is suppose to output the day of the week for a given date.

After int f is declared, I am not sure how to fix the if statement for if a number is less than zero. Here is a chunk of my code:

if (month == 1 || month == 2) 
{
    month += 12;
    year--;
} else {
    month-=2;
}

scan.close();        

int m = month;
int d = year % 100; 
int c = (year / 100); 
int k = day;         
int f = (k + (int)((13 * m - 1) / 5.0) + d + (int)(d / 4.0) + (int)(c / 4.0) + (2 * c));        

if (f<=0) 
{
    f= f % 7;
    else
}  

/*   
if (f>0)
{   
    //?
}   
*/

String last = ("Day of the week: ");
System.out.println(f);
sara j
  • 33
  • 1
  • 5
  • "less than zero" ? Your `if` condition without code is handling `if (f >= 0)`. For me, that's a contradiction of your statement. It also doesn't make sense to handle the case `f=0` in both `if` branches and using an `else` would also be nice – UninformedUser Oct 15 '17 at 19:22
  • Which nevertheless handles `bigger than zero" ...or not? – UninformedUser Oct 15 '17 at 19:24
  • Now it doesn't compile anymore ... – UninformedUser Oct 15 '17 at 19:26
  • Anyways, what is the problem with your code now? The Zeller's Congruence is a simple formula which you have implemented by computing `f`, or not? – UninformedUser Oct 15 '17 at 19:27
  • Are you sure that the computation is correct? Why `13 * m - 1`? Wikipedia says `13(m+1)` And why do you ignore the math operations ceil in the formula? And it's `+ 5J`. Did you use a different formula? I'm talking about this one: https://en.wikipedia.org/wiki/Zeller%27s_congruence – UninformedUser Oct 15 '17 at 19:30
  • The equation I was told to use has 13*m-1 . Also, I am trying to use those but do not know where they should go, or how to implement them properly. I am using this one http://mathforum.org/dr.math/faq/faq.calendar.html – sara j Oct 15 '17 at 19:34
  • my main issue is that if the result of f is negative, it will print the wrong date. – sara j Oct 15 '17 at 19:42
  • Ok, I see. The Wikipedia formula solves exactly this issue by using some different terms. Thus, it's always positive. – UninformedUser Oct 15 '17 at 19:42
  • I'm just citing the like you showed: *"Suppose f = -17. When we divide by 7, we have to follow the same rules as for the greatest integer function; namely we find the greatest multiple of 7 less than -17, so the remainder will be positive (or zero). -21 is the greatest multiple of 7 less than -17, so the remainder is 4 since -21 + 4 = -17. Alternatively, we can say that -7 goes into -17 twice, making -14 and leaving a remainder of -3, then add 7 since the remainder is negative, so -3 + 7 is again a remainder of 4."* – UninformedUser Oct 15 '17 at 19:43
  • What is not clear here? You could use a `while` loop that multiplies a new integer number `int val = -1` by 7 until it's smaller than `f`. Then compute the difference which is the week day – UninformedUser Oct 15 '17 at 19:45
  • Look at your `if (f<=0) ` and fix that random **else** text... – VC.One Oct 16 '17 at 00:49
  • Have you found a solution now? And again, you if is wrong. You want to handle the case when `f` is negative, i.e. `f < 0` Afterwards, you can divide by 7, but not in the if branch – UninformedUser Oct 16 '17 at 07:45

1 Answers1

2

I'm using the formula as stated in wikipedia. There are some details that differ from your code:

  • Month values are 3 = March, 4 = April, 5 = May, ..., 14 = February. So, your else { month-=2; } is not needed: only January and February must be adjusted to be 13 and 14, all the other months must remain unchanged.
  • I changed the variables names to match wikipedia's formula:
    • h is the day of the week (0 = Saturday, 1 = Sunday, 2 = Monday, ..., 6 = Friday)
    • q is the day of the month
    • m is the month (3 = March, 4 = April, 5 = May, ..., 14 = February)
    • K the year of the century
    • J is the zero-based century

Another detail (also explained in the same article), is that the modulo implementation may vary for negative numbers:

... −2 mod 7 is equal to positive 5. Unfortunately, the way most computer languages implement the remainder function, −2 mod 7 returns a result of −2.

In Java (I'm using JDK 1.8.0_144), this also happens (-2 % 7 is equals to -2), and one way to fix is to just add 7 to the final result. So the code will be like this:

// adjust January to 13 and February to 14
if (month == 1 || month == 2) {
    month += 12;
    year--;
}

int j = year / 100;
int k = year % 100;
int q = day;

// using temporary variables to make code cleaner (IMO)
int tmp1 = (13 * (month + 1)) / 5;
int tmp2 = k / 4;
int tmp3 = j / 4;
int h = (q + tmp1 + k + tmp2 + tmp3 - (2 * j)) % 7;
// if result is negative, fix
if (h < 0) {
    h += 7;
}

So, h will be 0 for Saturday, 1 for Sunday and so on. I've tested with dates from years 1900 to 2100 and it worked fine.

In wikipedia's article, there's also an alternative formula to avoid negative results: just change - 2J for + 5J:

// change "- (2 * j)" to "+ (5 * j)"
int h = (q + tmp1 + k + tmp2 + tmp3 + (5 * j)) % 7;

This will get the same results, but h will always be positive (so the if (h < 0) is not needed).


Java new Date/Time API

If you're making this code for learning purposes, then it's fine. But for business applications, it's better to use proper date/time API's.

If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.

If you're using Java 6 or 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, you'll also need the ThreeTenABP (more on how to use it here).

The code below works for both. The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.

An easy way to get the day of the week from a specific date is to use the LocalDate class, and then get the DayOfWeek from it:

LocalDate dt = LocalDate.of(year, month, day);
DayOfWeek dayOfWeek = dt.getDayOfWeek();
// getValue() returns values from 1 (Monday) to 7 (Sunday)
int value = dayOfWeek.getValue();

The only difference is that the getValue() method returns values according to ISO definition, from 1 (Monday) to 7 (Sunday). If you need the same values returned by the Zeller's method, though, you can do:

int zellerValue = (dayOfWeek.getValue() + 1) % 7;