2

已经有一个初始程序,我使代码尽可能短和精确。但是经过检查,似乎接下来的 2 年仍然会打印 2018 年,而我期待 2019 年和 2020 年。我怎样才能动态打印显示 2018 年、2019 年和 2020 年的年份。可能是我的代码中缺少一些迭代。

也请随意批评我的代码,您还可以通过尽可能多地使用 Calendar API 或 Java 8 实用程序来建议更短的代码。

请参见下面的代码:

package calendarjava;

import java.util.Calendar;
import java.util.Scanner;
import java.util.GregorianCalendar;
import java.util.Locale;


public class CalendarJava {

   public static void main(String[] args) {

      Scanner sc = new Scanner(System.in);
      System.out.print("Enter a year: ");
      int year = sc.nextInt();

      Calendar cal = new GregorianCalendar();

      int startDay;
      int numberOfDays;
      for (int i=0; i<36; i++){
        cal.set(year, i, 1);
        startDay = cal.get(Calendar.DAY_OF_WEEK);
        numberOfDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        System.out.print(cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.US));
        System.out.println( " " + year);
        printMonth(numberOfDays,startDay);
        System.out.println();
      }
   }

   private static void printMonth(int numberOfDays, int startDay) {

      int weekdayIndex = 0;
      System.out.println("Su  Mo  Tu  We  Th  Fr  Sa");

      for (int day = 1; day < startDay; day++) {
         System.out.print("    ");
         weekdayIndex++;
      }

      for (int day = 1; day <= numberOfDays; day++) {
         System.out.printf("%1$2d", day);
         weekdayIndex++;
         if (weekdayIndex == 7) {
            weekdayIndex = 0;
            System.out.println();
         } else { 
            System.out.print("  ");
         }
      }
      System.out.println();
   }
}
Enter a year: 2018
January 2018
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  

February 2018
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  

March 2018
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


April 2018
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  

May 2018
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  

June 2018
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


July 2018
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  

August 2018
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  

September 2018
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  

October 2018
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  

November 2018
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  

December 2018
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  

January 2018
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  

February 2018
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  

March 2018
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  

April 2018
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  

May 2018
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  

June 2018
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  

July 2018
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  

August 2018
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


September 2018
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  

October 2018
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  

November 2018
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


December 2018
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  

January 2018
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  

February 2018
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


March 2018
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  

April 2018
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  

May 2018
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  

June 2018
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  

July 2018
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  

August 2018
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  

September 2018
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  

October 2018
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


November 2018
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  

December 2018
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
4

2 回答 2

4

现代Java

这是一个完全不同的看法,供您比较。此代码使用现代 Java 的特性,包括JSR 310中定义的java.time类、、方便的工厂方法和枚举List

所有这些代码都包含在一个.java文件中,用于定义我们的CalendarMaker类。请参阅该main方法作为演示,了解如何使用此类。

该类有两个通过构造函数注入的成员变量:在我们的结果文本中使用的行尾(换行符)Locale字符,以及我们(a)确定星期几的顺序, 和 (b) 本地化月份名称和星期几的名称。

我们使用类通过调用它的方法StringBuilder来构建我们的文本。append

尽可能使用特定类型,以使您的代码更具自记录性,确保有效值并提供类型安全性。因此,我们从一个Year对象列表开始,包括当前年份以及之前和之后的年份。

对于每一年,我们循环月份。每个月都表示为一个YearMonth对象。我们通过调用本地化月份名称Month.getDisplayName。然后我们通过首先本地化星期几的名称来本地化星期几列标题,然后截断只取前两个字母。

DayOfWeek枚举提供了现成的对象来表示一周中的每一天。

请注意,我们还本地化了一周中的天数顺序。在美国,星期日是大多数日历上一周的开始。但在欧洲和其他地方,你经常会先看到星期一。我们的代码允许在一周中的任何一天开始一周,以防某些文化规范有其他选择。

TemporalAdjuster在班级中找到的ATemporalAdjusters确定了我们每月网格中的开始日期。然后我们每天以每周为单位递增。或者,我们禁止显示位于目标月份之外的日期。

要为每天的数字生成文本,请使用DateTimeFormatter. 使用格式模式dd用零填充单个数字。要使用空格填充,请使用ppd.

更新:我将for这段代码中的循环替换为来自LocalDate.datesUntil. 在内部,我们使用三元运算符来抑制目标月份之外的日期。我并不是说这种重写一定更好。我只是想以现代 Java 编程的一个例子来展示带有流和 lambda 的漂亮语法。

    // Rows (each week)
    LocalDate localDate = yearMonth.atDay( 1 ).with( TemporalAdjusters.previousOrSame( firstDayOfWeek ) );
    while ( ! localDate.isAfter( yearMonth.atEndOfMonth() ) )  // "Not after" is a shorter way of saying "is equal to or sooner than".
    {
        for ( int i = 0 ; i < 7 ; i++ )
        {
            // If we want to suppress the out-of-month dates that may exist in first and last rows.
            if ( ! YearMonth.from( localDate ).equals( yearMonth ) )
            {
                sb.append( "  " );  // Use 2 spaces rather than 2 digits of day-of-month number.
            } else  // Else the date is inside our target year-month.
            {
                sb.append( localDate.format( CalendarMaker.DAY_FORMATTER ) );
            }
            if ( i < 6 )
            {
                sb.append( " " ); // Pad with a SPACE between columns.
            }
            localDate = localDate.plusDays( 1 );  // Increment one day at a time.
        }
        sb.append( this.eol );
    }

…变成:

    // Rows (each week)
    LocalDate localDate = yearMonth.atDay( 1 ).with( TemporalAdjusters.previousOrSame( firstDayOfWeek ) ); // Get the first date of the month, then move backwards in time to determine the first date that fits our calendar grid. May be the same as the first, or may be earlier date from the previous month.
    while ( ! localDate.isAfter( yearMonth.atEndOfMonth() ) )  // "Not after" is a shorter way of saying "is equal to or sooner than".
    {
        String week =
                localDate
                        .datesUntil( localDate.plusWeeks( 1 ) )  // Get a stream of dates via `LocalDate::datesUntil`. The ending date is exclusive (half-open).
                        .map( ld -> ( YearMonth.from( ld ).equals( yearMonth ) ? ld.format( CalendarMaker.DAY_FORMATTER ) : "  " ) ) // Display the day-of-month number if within the target month, otherwise display a pair of SPACE characters.
                        .collect( Collectors.joining( " " ) );  // Separate columns with a SPACE in our calendar grid.
        sb.append( week ).append( this.eol ); // Add this row of text for the week, and wrap to next line for next loop.
        localDate = localDate.plusWeeks( 1 );  // Increment one week at a time to set up our next loop.
    }

CalendarMaker.java

package work.basil.example;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.format.TextStyle;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.EnumSet;
import java.util.List;
import java.util.Locale;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

public class CalendarMaker
{
    // Member variables.
    private String eol;
    private Locale locale;
    static private DateTimeFormatter DAY_FORMATTER = DateTimeFormatter.ofPattern( "ppd" ); // Use `dd` to pad single-digits values with a leading zero. Use `ppd` to pad with a SPACE.

    // Constructor

    public CalendarMaker ( String eol , Locale locale )
    {
        this.eol = eol;
        this.locale = locale;
    }

    private CharSequence generateYear ( final Year year )
    {
        // Year header.
        StringBuilder sb = new StringBuilder();
        sb.append( "|------  " + year + "  ------|" ).append( this.eol ).append( this.eol );

        // Each month.
        for ( Month month : EnumSet.allOf( Month.class ) )
        {
            YearMonth ym = YearMonth.of( year.getValue() , month );
            CharSequence monthCalendar = this.generateMonth( ym );
            sb.append( monthCalendar );
        }
        return sb;
    }

    private CharSequence generateMonth ( final YearMonth yearMonth )
    {
        // Title
        StringBuilder sb = new StringBuilder();
        String monthName = yearMonth.getMonth().getDisplayName( TextStyle.FULL , this.locale );
        sb.append( yearMonth.getYear() ).append( " " ).append( monthName ).append( this.eol );

        // Column headers.
        DayOfWeek firstDayOfWeek = WeekFields.of( this.locale ).getFirstDayOfWeek();
        List < DayOfWeek > dows =
                IntStream
                        .range( 0 , 7 )
                        .mapToObj( firstDayOfWeek :: plus )
                        .collect( Collectors.toList() );
        String columnHeaders =
                dows
                        .stream()
                        .map( dayOfWeek -> dayOfWeek.getDisplayName( TextStyle.SHORT_STANDALONE , this.locale ).substring( 0 , 2 ) )
                        .collect( Collectors.joining( " " ) );
        sb.append( columnHeaders ).append( this.eol );

        // Rows (each week)
        LocalDate localDate = yearMonth.atDay( 1 ).with( TemporalAdjusters.previousOrSame( firstDayOfWeek ) ); // Get the first date of the month, then move backwards in time to determine the first date that fits our calendar grid. May be the same as the first, or may be earlier date from the previous month.
        while ( ! localDate.isAfter( yearMonth.atEndOfMonth() ) )  // "Not after" is a shorter way of saying "is equal to or sooner than".
        {
            String week =
                    localDate
                            .datesUntil( localDate.plusWeeks( 1 ) )  // Get a stream of dates via `LocalDate::datesUntil`. The ending date is exclusive (half-open).
                            .map( ld -> ( YearMonth.from( ld ).equals( yearMonth ) ? ld.format( CalendarMaker.DAY_FORMATTER ) : "  " ) ) // Display the day-of-month number if within the target month, otherwise display a pair of SPACE characters.
                            .collect( Collectors.joining( " " ) );  // Separate columns with a SPACE in our calendar grid.
            sb.append( week ).append( this.eol ); // Add this row of text for the week, and wrap to next line for next loop.
            localDate = localDate.plusWeeks( 1 );  // Increment one week at a time to set up our next loop.
        }

        // Footer (for the month)
        sb.append( this.eol );  // Put a blank line after every month.
        return sb;
    }

    // Demonstrate this class with a psvm method.
    public static void main ( String[] args )
    {

        CalendarMaker calendarMaker = new CalendarMaker( "\n" , Locale.CANADA_FRENCH );

        // Demonstrate 3 years: previous year, current, and next year.
        Year currentYear = Year.now( ZoneId.of( "America/Boise" ) );
        List < Year > years = List.of( currentYear.minusYears( 1 ) , currentYear , currentYear.plusYears( 1 ) );
        for ( Year year : years )
        {
            CharSequence calendar = calendarMaker.generateYear( year );
            System.out.println( "" );
            System.out.println( calendar );
        }
    }

}

跑的时候。

|------  2018  ------|

2018 janvier
di lu ma me je ve 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         

2018 février
di lu ma me je ve 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      
…

将语言环境从 切换Locale.CANADA_FRENCHLocale.FRANCE,看看我们如何保留法语,但将文化规范从北美切换到欧洲,以星期一 (lundi) 而不是星期日 (dimanche) 开始一周。

于 2019-05-20T04:55:57.107 回答
0

要更正您当前使用的代码,请不要迭代超过 36 个月以获得三年的日历。没有办法为Calendar#set()方法增加年份。而是在main()方法中包含的现有for循环中添加一个外部for循环,以便迭代所需的年份,而现在的内部循环仅迭代12个月(不是 36 个月)。这样,日历#set()方法的外部循环会增加年份。它看起来像这样:

Scanner sc = new Scanner(System.in);
System.out.print("Enter a year: ");
int year = sc.nextInt();

Calendar cal = new GregorianCalendar();

int startDay;
int numberOfDays;

// Display Calendars for 3 years only!
for (int yr = year; yr <= (year + 2); yr++) {
    // The Months for current year determined by yr...
    for (int i = 0; i < 12; i++) {
        cal.set(yr, i, 1);
        startDay = cal.get(Calendar.DAY_OF_WEEK);
        numberOfDays = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
        String month = cal.getDisplayName(Calendar.MONTH, Calendar.LONG, Locale.US);
        // A Ternary Operator is used below to append an asterisks (**) 
        // the end of the month display for February on leap years.
        System.out.println(month + " " + yr + (numberOfDays == 29 ? " **" : ""));
        printMonth(numberOfDays, startDay);
        System.out.println();
    }
}

您的printMonth()方法可以保持不变。

于 2019-05-20T03:58:53.063 回答