如何在终端上正确打印月历

How to Properly print Month Calendar on Terminal

您好,在此先感谢您的帮助。我有一个程序应该根据用户输入的月份和年份打印当前月份的日历。该程序大部分工作,但我遇到格式问题,并且该月的第一天未在正确的日期开始。

示例输出:

    October 2020
------------------------------
 Sun Mon Tue Wed Thu Fri Sat
      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 

2020 年 10 月将从星期四开始,但 1 印在 Mon 下。 10 月 4 日是星期日,因此新行应该从星期日开始。

请参阅附件中的代码。再次感谢

import java.util.*;

public class CalendarMonthDisplay {

        public static void main(String[] args) {
            Scanner input = new Scanner(System.in); //Scan for user input
            System.out.print("Please enter a month between 1 and 12 (e.g. 5): "); //Prompt user to enter month
            int m = input.nextInt();

            System.out.print("Please enter a full year (e.g. 2018): "); //Prompt user to enter year
            int y = input.nextInt();

             //Print calendar for the month of the year
            if ( m < 1 || m > 12)
                System.out.print("Wrong input! Please try again.");
            else
                printMonthCalendar(m, y);
        }

        static void printMonthCalendar (int m, int y) { //Display calendar in format above
            int startDay = getStartDay(m, y);
            int numDaysInMonths = getNumDaysInMonth(m, y);

            printMonthHeader(m, y);
            printMonthBody(startDay, numDaysInMonths);
        }

        static void printMonthBody (int startDay, int numDaysInMonths) { //Display the days in the calendar

            int i;

            for (i = 0; i <= startDay; i++)
                System.out.print(" ");

            for (i = 1; i <= numDaysInMonths; i++) {
                if ( i < 10 )
                    System.out.print("   " + i );
                else
                    System.out.print("  " + i + " ");

                if ((startDay + i) % 7 == 0)
                    System.out.println();
            }
            System.out.println();
        }

        static void printMonthHeader (int m, int y) { //Display the header information
            System.out.println("\t" + getMonthName(m) + " " + y);
            System.out.println("------------------------------");
            System.out.println(" Sun Mon Tue Wed Thu Fri Sat");
        }

        static  String getMonthName (int m) {
            String monthName = null;
            switch (m) {
                case 1: monthName = "January";
                break;
                case 2: monthName = "February";
                break;
                case 3: monthName = "March";
                break;
                case 4: monthName = "April";
                break;
                case 5: monthName = "May";
                break;
                case 6: monthName = "June";
                break;
                case 7: monthName = "July";
                break;
                case 8: monthName = "August";
                break;
                case 9: monthName = "September";
                break;
                case 10: monthName = "October";
                break;
                case 11: monthName = "November";
                break;
                case 12: monthName = "December";
            }
            return monthName;
        }


        static int getNumDaysInMonth (int m, int y) {
            int numDaysInMonths= 0;
            switch (m) {
                case 1: case 3: case 5: case 7: case 8: case 10: case 12:
                    numDaysInMonths= 31;
                    break;
                case 4: case 6: case 9: case 11:
                    numDaysInMonths = 30;
                    break;
                case 2:
                    if (isLeapYear(y))
                        numDaysInMonths = 29;
                    else
                        numDaysInMonths = 28;
                    break;
            }
            return numDaysInMonths;
        }

        static boolean isLeapYear (int y) {
            return  (y % 400 == 0) || (y % 4 == 0 && y % 100 != 0);
//                return  true;
//            return false;
        }

        static int getStartDay (int m, int y) {
            // Adjust month number & year to fit Zeller's numbering system
            if (m < 3)
                m = m + 12;
                y = y - 1;

            int d = 1; //Set day parameter to 1
            int k = y % 100;      // Calculate year within century
            int j = y / 100;      // Calculate century term
            int h = 0;            // Day number of first day in month 'm'

            h = ( d + ( 13 * ( m + 1 ) / 5 ) + k + ( k / 4 ) + ( j / 4 ) + ( 5 * j ) ) % 7;

            // Convert Zeller's value to ISO value (1 = Mon, ... , 7 = Sun )
            int dayNum = ( ( h + 5 ) % 7 ) + 1;
            return dayNum;
        }


}

我建议您使用 modern date-time API. Learn more about the modern date-time API from Trail: Date Time

import java.time.LocalDate;
import java.time.YearMonth;
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in); // Scan for user input
        System.out.print("Please enter a month between 1 and 12 (e.g. 5): "); // Prompt user to enter month
        int m = input.nextInt();

        System.out.print("Please enter a full year (e.g. 2018): "); // Prompt user to enter year
        int y = input.nextInt();
        printMonth(y, m);
    }

    static void printMonth(int year, int month) {
        YearMonth ym = YearMonth.of(year, month);
        System.out.println("Sun Mon Tue Wed Thu Fri Sat");
        int counter = 1;

        // Get day of week of 1st date of the month and print space for as many days as
        // distant from SUN
        int dayValue = LocalDate.of(year, month, 1).getDayOfWeek().getValue();
        for (int i = 0; i < dayValue; i++, counter++) {
            System.out.printf("%-4s", "");
        }

        for (int i = 1; i <= ym.getMonth().length(ym.isLeapYear()); i++, counter++) {
            System.out.printf("%-4d", i);

            // Break the line if the value of the counter is multiple of 7
            if (counter % 7 == 0) {
                System.out.println();
            }
        }
    }
}

样本运行:

Please enter a month between 1 and 12 (e.g. 5): 9
Please enter a full year (e.g. 2018): 2020
Sun Mon Tue Wed Thu Fri Sat
        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  

注意:Formatter 了解格式化打印。

我不认为你的 getStartDay 方法 returns 是你期望的星期几。它似乎从星期三返回 1 到星期二返回 7。示例:

Month           Start day of week  getStartDay()
------------------------------------------------
July 2020       Wednesday          1
August 2020     Saturday           4
September 2020  Tuesday            7
October 2020    Thursday           2

您的代码中可能还有一两个问题,但我认为您应该首先解决这个基本问题。

这是一个很好的练习,你一定会学到的。对于生产代码,永远不会实现 Zeller 算法或任何其他算法来查找月份和星期几的长度。如 Arvind Kumar Avinash 的回答所示,标准库可以更可靠地完成此操作。