从给定的月份/年份打印日历

Posted

技术标签:

【中文标题】从给定的月份/年份打印日历【英文标题】:Printing a Calendar from Given Month/Year 【发布时间】:2014-07-31 23:55:21 【问题描述】:

我正在处理一项 Java 作业,它涉及在用户指定月份和年份后打印日历。我不能使用 Calendar 或 GregorianCalendar 类。我的问题是日历在星期六的第一天没有正确打印月份。我已经查看了我的代码大约一个小时,但我不确定出了什么问题。我正在使用 Zeller's Congruence 来查找该月的第一天,用“h”表示。

例如,2008 年 3 月的日历(错误地)如下所示:

     March 2008
Su Mo Tu We Th Fr Sa
 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 

这是我的代码:

package calendar;

import java.util.Scanner;

public class Calendar

    private static int numDays = 0;
    private static int h = 0;
    public static boolean leap(int year)
    
        if(((year % 4 == 0) && !(year % 100 == 0)) || (year % 400 == 0))
        
            return true;
        
        else
        
            return false;
        
    
    public static void firstDayOfYear(int year)
    
        int month = 13;
        year--;
        h = (1 + (int)(((month + 1) * 26) / 10.0) + year + (int)(year / 4.0) + 6 * (int)(year / 100.0) + (int)(year / 400.0)) % 7;
        String dayName = "";
        switch(h)
        
            case 0: dayName = "Saturday"; break;
            case 1: dayName = "Sunday"; break;
            case 2: dayName = "Monday"; break;
            case 3: dayName = "Tuesday"; break;
            case 4: dayName = "Wednesday"; break;
            case 5: dayName = "Thursday"; break;
            default: dayName = "Friday"; break;
        
        System.out.println("The first day of the year is " + dayName);
    
    public static void firstDayOfMonth(int month, int year)
    
        if(month == 1 || month == 2)
        
            month += 12;
            year--;
        
        h = (1 + (int)(((month + 1) * 26) / 10.0) + year + (int)(year / 4.0) + 6 * (int)(year / 100.0) + (int)(year / 400.0)) % 7;
        String dayName = "";
        switch(h)
        
            case 0: dayName = "Saturday"; break;
            case 1: dayName = "Sunday"; break;
            case 2: dayName = "Monday"; break;
            case 3: dayName = "Tuesday"; break;
            case 4: dayName = "Wednesday"; break;
            case 5: dayName = "Thursday"; break;
            default: dayName = "Friday"; break;
        
        System.out.println("The first day of the month is " + dayName);
    
    public static void numDaysInMonth(int month, int year)
    
        int[] days =  0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ;

        if (month == 2 && leap(year)) days[month] = 29;
        numDays = days[month];
        System.out.println("The number of days in the month is " + numDays);
    
    public static void printCal(int month, int year)
    
        String[] monthNames = "","January","February","March","April","May","June","July","August","September","October","November","December";

        System.out.println("    " + monthNames[month] + " " + year);
        System.out.println("Su Mo Tu We Th Fr Sa");
        for (int i = 0; i < h - 1; i++)
            System.out.print("   ");
        for (int i = 1; i <= numDays; i++)
        
            System.out.printf("%2d ", i);
            if (((i + h - 1) % 7 == 0) || (i == numDays)) System.out.println();
        
    
    public static void main(String[] args)
    
        Scanner input = new Scanner(System.in);
        System.out.print("Enter month (1-12): ");
        int month = input.nextInt();
        if(month < 1 || month > 12)
        
            System.out.println("Invalid month. Valids inputs are 1-12.");
            System.exit(0);
        
        System.out.print("Enter year: ");
        int year = input.nextInt();
        if(year < 1753)
        
            System.out.println("Invalid year. Valid inputs are 1753 and beyond.");
            System.exit(0);
        
        if(leap(year))
        
            System.out.println(year + " is a leap year.");
        
        else
        
            System.out.println(year + " is NOT a leap year.");
        
        firstDayOfYear(year);
        firstDayOfMonth(month, year);
        numDaysInMonth(month, year);
        printCal(month, year);
        

【问题讨论】:

【参考方案1】:

您的代码对于every month that starts with a Saturday 也会有同样的问题。这意味着问题可能出在这一行 -

for (int i = 0; i < h - 1; i++)
  System.out.print("   ");

在这里将h 设置为 7 而不是 0 将为您解决此问题。您可以在此处修复该问题,或者您可能需要从 1 到 7 而不是 0 到 6 开始 h 并进行其他必要的更改。

【讨论】:

另外,这个:case 0: dayName = "Saturday"; break; 谢谢,我知道从这里该做什么了。 更改此代码可能会很痛苦,但请确保将来您使用 0 索引而不是 1 索引。在访问数组并避免像您在这里一样的 off-by-1 错误时,它会让您的生活变得更加轻松。【参考方案2】:

问题是您的索引搞砸了。这意味着你从 1 而不是 0 开始你的弱者的月份和日子。但是在这里

h = (1 + (int)(((month + 1) * 26) / 10.0) + year + (int)(year / 4.0) + 6 * (int)(year / 100.0) + (int)(year / 400.0)) % 7

末尾的 %7 使它从 0 开始!这会导致循环

for (int i = 0; i < h - 1; i++)
  System.out.print("   ");

成为

for (int i = 0; i < -1; i++)
  System.out.print("   ");

因为星期六的 h 为 0。

要解决此问题,您应该在函数中的 所有 索引开始为 0。然后当您将用户输入索引为 1 时,只需减去 1 并将其传递给您的函数。然后你也不会在你的所有数组前面有那个空白条目(顺便说一下,这应该是类顶部的静态决赛)。

【讨论】:

【参考方案3】:

我知道你得到了答案。但这里有一个快速修复(抱歉,它有点笨拙),您可以将其合并到周六更正您的索引,而无需对您的代码进行很多更改。

System.out.println("Su Mo Tu We Th Fr Sa");
        int xx = h == 0 ? 7 : h; // Correct the index for Saturday.
        for (int i = xx; i > 1; i--) // Reversing the loop condition
            System.out.print("   ");
        for (int i = 1; i <= numDays; i++) 
            System.out.printf("%2d ", i);
            if (((i + h - 1) % 7 == 0) || (i == numDays))
                System.out.println();
        

【讨论】:

这很好用,比我想象的要好。如果可以的话,我会为此 +1,但我是新来的。 是的,黑客总是更适合快速修复,但我建议不要这样做。 @Swapnil 给出的答案非常正确,你应该听从他的建议。【参考方案4】:

这将解决闰年问题

if ((((i + h) % 7 == 0) || (i == numDays) && leap(year)))

【讨论】:

以上是关于从给定的月份/年份打印日历的主要内容,如果未能解决你的问题,请参考以下文章

输入年份和月份打印当月日历

JAVA 输入年份月份打印该月的日历

编写万年历:输入一个年份,再输入一个月份,把那个月的日历打印出来(1900年1月1日是星期一)

Java - 在指定的给定月份 - 年份范围内打印每个月的第一个和最后一个日期

仅显示月份和年份的 Django DateField 日历?

Java实现打印日历的功能