У меня уже была начальная программа для этого, я сделал код максимально коротким и точным. Но при проверке кажется, что следующие 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
@MadProgrammer, как я могу применить это к майскому коду? Спасибо
Я тоже рекомендую вам не использовать Calendar
и GregorianCalendar
. Эти классы плохо разработаны и давно устарели. Вместо этого используйте LocalDate
из java.time, современный API даты и времени Java.
Чтобы исправить код, который вы используете в настоящее время, не повторяйте более 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();
}
}
Ваш метод печатьМесяц() может остаться прежним.
Спасибо за этот хороший подход, ребята! как насчет того, чтобы печатать их вертикально? это возможно?
Извините @DevilsHnd, я имею в виду по горизонтали по годам.
Поместите создание календарей в многомерный интерфейс ArrayList или List, а затем выполните итерацию по списку и распечатайте его любым удобным для вас способом. Сортируйте его так, как вы хотите, если хотите.
Вот совсем другой вариант, для сравнения. Этот код использует возможности современной 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).
Начните с использования более новой версии API даты/времени.