Распечатайте 12-месячный год и следующие 2 года, используя Java

У меня уже была начальная программа для этого, я сделал код максимально коротким и точным. Но при проверке кажется, что следующие 2 года по-прежнему печатают 2018 год, и я ожидаю 2019 и 2020 годов. Как я могу динамически печатать год, когда он показывает 2018, 2019 и 2020 годы. Возможно, мне не хватает некоторых итераций в моем коде.

Также не стесняйтесь критиковать мой код, вы также можете предлагать более короткие коды, используя 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

Начните с использования более новой версии API даты/времени.

MadProgrammer 20.05.2019 04:07

@MadProgrammer, как я могу применить это к майскому коду? Спасибо

遊星不動 20.05.2019 04:12

Я тоже рекомендую вам не использовать Calendar и GregorianCalendar. Эти классы плохо разработаны и давно устарели. Вместо этого используйте LocalDate из java.time, современный API даты и времени Java.

Ole V.V. 20.05.2019 10:48
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
4
559
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Чтобы исправить код, который вы используете в настоящее время, не повторяйте более 36 месяцев, чтобы получить календари на три года. Невозможно увеличить год для метода Календарь # установить (). Вместо этого добавьте внешний цикл для к существующему циклу для, содержащемуся в методе основной(), чтобы выполнить итерацию через требуемые годы, а теперь внутренний цикл выполняет итерацию только через 12 месяцев (а не 36). Таким образом, год увеличивается внешним циклом для метода Календарь # установить (). Это будет выглядеть примерно так:

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();
    }
}

Ваш метод печатьМесяц() может остаться прежним.

Спасибо за этот хороший подход, ребята! как насчет того, чтобы печатать их вертикально? это возможно?

遊星不動 22.05.2019 08:39

Извините @DevilsHnd, я имею в виду по горизонтали по годам.

遊星不動 23.05.2019 03:01

Поместите создание календарей в многомерный интерфейс ArrayList или List, а затем выполните итерацию по списку и распечатайте его любым удобным для вас способом. Сортируйте его так, как вы хотите, если хотите.

DevilsHnd 23.05.2019 07:12
Ответ принят как подходящий

Современная Ява

Вот совсем другой вариант, для сравнения. Этот код использует возможности современной Java, включая классы Java.время, определенные в JSR 310, потоки, удобный метод List завод и перечисления.

Весь этот код содержится в одном .java файле, чтобы определить наш CalendarMaker класс. См. метод main в качестве демонстрации того, как использовать этот класс.

Класс имеет две переменные-члены, которые вы вводите через конструктор: символ (символы) конец строки (новая строка) для использования в нашем результирующем тексте и Locale, с помощью которого мы (а) определяем порядок дней недели и (б) локализуем название месяца и название дня недели.

Мы используем класс StringBuilder для создания нашего текста, вызывая его метод append.

По возможности используйте определенные типы, чтобы сделать ваш код более самодокументирующийся, обеспечить допустимые значения и предоставить типобезопасность. Итак, мы начинаем со списка объектов Year за текущий год, а также за предыдущие и последующие годы.

Для каждого года мы зацикливаем месяцы. Каждый месяц представлен как объект YearMonth. Мы локализуем название месяца по телефону Month.getDisplayName. Затем мы локализуем заголовки столбца дня недели, сначала локализовав название дня недели, а затем усекая его, чтобы взять только первые две буквы.

Перечисление DayOfWeek предоставляет готовые объекты для представления каждого дня недели.

Обратите внимание, что мы также локализуем порядок дней в неделе. В США в большинстве календарей неделя начинается с воскресенья. Но в Европе и в других местах вы часто сначала увидите понедельник. Наш код допускает любой день недели для начала недели, если в соответствии с некоторыми культурными нормами существуют другие варианты.

TemporalAdjuster, найденный в классе TemporalAdjusters, определяет дату начала в нашей месячной сетке. Затем мы увеличиваем его день за днем ​​еженедельными порциями. При желании мы подавляем отображение дат, которые лежат за пределами нашего целевого месяца.

Чтобы сгенерировать текст для каждого номера дня, используйте DateTimeFormatter. Используйте шаблон форматирования dd, чтобы дополнить однозначные числа нулем. Чтобы добавить ПРОБЕЛ, используйте ppd.

Обновление: я заменил цикл for в этом блоке кода потоком из LocalDate.datesUntil. Внутри мы используем тернарный оператор, чтобы скрыть даты за пределами нашего целевого месяца. Я не говорю, что эта переделка обязательно лучше; Я просто хочу показать элегантный синтаксис с потоком и лямбдой в качестве примера современного программирования на Java.

    // 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_FRENCH на Locale.FRANCE, чтобы увидеть, как мы сохраняем французский язык, но переключаем культурные нормы с североамериканских на европейские, чтобы неделя начиналась с понедельника (lundi), а не с воскресенья (dimanche).

Другие вопросы по теме