사용자가 입력한 연도와 월을 기준으로 이전 월과 다음 월을 포함하는 3개월 달력을 출력하도록 코드를 작성합니다. LocalDate
클래스를 활용해 아래와 같은 포맷으로 만듭니다.
먼저 사용자에게 연도와 월을 입력받습니다. Main 메소드에서 Scanner를 이용해 사용자에게 연도와 월을 입력받고, createCalendar라는 메소드를 별도로 생성해 달력 정보를 출력하도록 셋팅했습니다.
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("[달력 출력 프로그램]");
System.out.print("달력의 년도를 입력해 주세요.(yyyy): ");
int yyyy = sc.nextInt();
sc.nextLine();
System.out.print("달력의 월을 입력해 주세요.(mm): ");
int mm = sc.nextInt();
createCalendar(yyyy, mm);
}
달력 정보를 가져올 메소드를 만듭니다. 먼저, 입력받은 연도와 월을 사용해 이전과 다음의 월과 연도를 계산합니다. 그리고 3개의 LocalDate 객체를 만들어서 앞뒤로 출력해야 하는 달의 정보를 가져옵니다. 반복 출력에 사용하기 위해 해당 정보를 배열에 담아주었습니다.
public static void createCalendar(int yyyy, int mm) {
// 매개변수 기준으로 앞뒤 연도와 월 선언하기
int previousMonth = (mm == 1) ? 12 : mm - 1;
int previousYear = (mm == 1) ? yyyy - 1 : yyyy;
int nextMonth = (mm == 12) ? 1 : mm + 1;
int nextYear = (mm == 12) ? yyyy + 1 : yyyy;
// 세 달의 LocalDate 객체 생성하기
LocalDate cal1 = LocalDate.of(previousYear, previousMonth, 1);
LocalDate cal2 = LocalDate.of(yyyy, mm, 1);
LocalDate cal3 = LocalDate.of(nextYear, nextMonth, 1);
// 세 달의 시작 요일과 마지막 날짜 가져오기
int firstDay1 = cal1.getDayOfWeek().getValue();
int lastDate1 = cal1.lengthOfMonth();
int firstDay2 = cal2.getDayOfWeek().getValue();
int lastDate2 = cal2.lengthOfMonth();
int firstDay3 = cal3.getDayOfWeek().getValue();
int lastDate3 = cal3.lengthOfMonth();
// 배열에 담기
int[] months = {previousMonth, mm, nextMonth};
int[] dates = {1, 1, 1};
int[] lastDates = {lastDate1, lastDate2, lastDate3};
int[] days = {firstDay1, firstDay2, firstDay3};
세 달치의 정보가 모두 준비되면, 달력의 첫 줄부터 출력합니다. 세 달을 가로로 연결해서 출력하기 위해 한 달을 한 개의 열로 설정했습니다. 또한, 한 달은 최대 6번의 주를 출력할 수 있기 때문에, 한 주를 한 개의 행으로 설정해 반복문에 넣어 주었습니다.
달력 모양의 특징을 생각했을 때, 매월 첫 날짜가 시작하는 요일이 모두 다르기 때문에 시작 요일이 되기 전까지는 날짜대신 공백을 빈 요일 개수만큼 반복해서 출력합니다.
// 달력 첫 줄 만들기
System.out.print("[" + previousYear + "년 " + String.format("%02d", (previousMonth)) + "월]" + "\t\t\t\t\t");
System.out.print("[" + yyyy + "년 " + String.format("%02d", mm) + "월]" + "\t\t\t\t\t");
System.out.println("[" + nextYear + "년 " + String.format("%02d", (nextMonth)) + "월]");
System.out.print("일\t월\t화\t수\t목\t금\t토\t\t");
System.out.print("일\t월\t화\t수\t목\t금\t토\t\t");
System.out.println("일\t월\t화\t수\t목\t금\t토");
for (int j = 0; j < 3; j++) { // 세 달 모두 할 때까지
int i = 0;
if (days[j] > 6) { // 해당 달의 시작 요일 값이 7 이상인 경우
days[j] = days[j] - 7; // 줄바꿈 없이 바로 첫 번째 줄에서 시작하도록 값 조정
}
while (i < days[j]) { // 1. 시작 요일까지 공백 넣기
System.out.print("\t");
i++;
}
for (i = 0; i < lastDates[j]; dates[j]++, i++) {
System.out.printf("%02d\t", dates[j]); // 2. 날짜 넣기
days[j]++;
if (days[j] % 7 == 0) {
System.out.print("\t"); // 3. 다음 달과 간격두기
dates[j]++;
break;
}
}
}
System.out.println(); // 첫 줄 완성
둘째 줄부터는 첫 요일부터 날짜가 이어지고, 해당 월의 마지막 날짜가 될 때까지 출력을 반복합니다. 이때 마지막 날짜를 먼저 출력한 달은 다음 달 출력으로 넘어가기 위해 공백을 계산해서 넣어 줍니다.
// 달력 둘째 줄 ~ 나머지 줄 만들기
for (int k = 0; k < 5; k++) { // 아래로 몇 번 (행)
for (int j = 0; j < 3; j++) { // 옆으로 몇 번 (열)
for (int i = 0; i < lastDates[j]; i++) { // 해당 월 마지막 날짜까지
if (dates[j] == 0) { // 이미 날짜 표기가 끝났는지 먼저 확인
System.out.print("\t\t\t\t\t\t\t\t");
break;
} else if (dates[j] <= lastDates[j]) {
System.out.printf("%02d\t", dates[j]); // 날짜 넣기
dates[j]++; // 날짜 증가
days[j]++; // 요일 증가
}
if (dates[j] > lastDates[j]) { // 날짜를 넣다가 -> 마지막 날짜를 표기할 차례라면
for (int n = 0; n <= (35 - days[j]); n++) { // 5주차 일요일에서 해당 요일까지 차이 계산
System.out.print("\t"); // 빈 요일에 공백 추가
}
dates[j] = 0;
break; // 다음 열로
}
if (days[j] % 7 == 0) { // 날짜를 넣다가 -> 토요일이면
System.out.print("\t"); // 공백 하나만 추가
break; // 다음 열로
}
}
}
System.out.println(); // 나머지 줄 완성
}
✅ LocalDate 클래스 정리
LocalDate란?
날짜 정보를 표현
하는 데 사용됩니다. ISO-8601 달력 시스템에 기반하여 날짜 정보를 저장하고 다룰 수 있도록 Java 8부터 추가된 java.time 패키지 소속 클래스입니다.사용법
주의점
LocalDateTime
또는 ZonedDateTime
을 사용합니다.✅ 문제에서 LocalDate를 활용했던 코드를 정리해 보았습니다.
LocalDate cal = LocalDate.of(연도, 월, 일)
: LocalDate 객체를 생성한 후 of()
메소드를 사용해 특정 일자 정보를 불러오기int day = cal.getDayOfWeek().getValue()
: getDayOfWeek()
메소드로 cal 날짜의 요일을 나타내는 열거형 DayOfWeek 데이터를 받은 후, getValue()
메소드를 이용해 열거형의 숫자 표현인 int형 값으로 반환 (일요일을 시작으로 정수 0부터 카운트)int length = cal.lengthOfMonth()
: cal 날짜가 속하는 달의 총 일 수를 int형 값으로 반환 참고
https://docs.oracle.com/javase/8/docs/api/java/time/LocalDate.html (LocalDate)
https://velog.io/@kkatalchae/Java8-Time-API-LocalDate-%EC%A0%95%EB%A6%AC (LocalDate)