diff --git a/README.md b/README.md
index 572a180..51f03f9 100644
--- a/README.md
+++ b/README.md
@@ -12,3 +12,363 @@
+
+
+# 주의 사항 리마인더
+
+- 출석 확인은 크루가 캠퍼스에 들어 온 후 시스템에 출석 데이터가 저장된 시간 기준 →
+- 시간 형식 24시간 제
+- 캠퍼스 운영 시간 08:00 ~ 23:00
+- 월 13:00~18:00
+- 화~ 금 10:00 18:00
+- 5분 : 지각, 30분 : 결석
+- 출석 기록 없음 : 결석
+ - 출석을 18:00 이후에 하는 경우는?
+- 주말, 공휴일은 출석 기능 자체가 불가
+- 크루, 출석 기록 → csv로 제공
+- 기능 선택 후 기능 선택해주세요 안내 메시지로 계속 돌아감
+- 종료 조건 : 기능에서 종료 선택
+
+지각 및 결석 누적 조회
+
+- 지각 3회 → 결석 1회
+- 결석 2회 : 경고
+- 결석 3회 : 면담
+- 결석 5회 : 제적
+
+예상 필요 기능
+
+캠퍼스 운영 시간, 근무 시간 기능
+
+지각, 결석 누적 계산 기능
+
+회원별 출석 기록 저장 기능
+
+갑자기 든 생각
+
+사람 마다 저장을 할 것인가
+
+날짜 마다 저장을 할 것인가?
+
+캘린더니까 날짜마다가 맞지 않을 까?
+
+날짜마다 저장을 해주면
+
+날짜 → 출석한 사람이름, 시간 만 저장하면 됨
+
+- 출석 확인
+ - 멤버 데이터 확인
+ - 해당 날짜에 사람 이름, 시간, 출결 여부 저장
+- 출석 수정
+ - 멤버 데이터 확인
+ - 해당 날짜에 사람 이름, 시간, 출결 여부 덮어쓰기
+- 출석 기록 확인
+ - 날짜 전체 순회
+ - 사람이름이 입력 받은 값만 출력
+ - 출격 여부 저장해가면서 출력
+- 제적 위험자 확인
+ - 날짜 전체 순회
+ - 결석,지각 이 있는 경우를 조회
+ - 이름마다 누적시켜서 저장
+ -
+
+# 서비스 흐름 구성
+
+- 1차 설계
+ - **파일 읽어오기**
+
+ string, dateTIme- 날짜 시간 합친 형태
+
+ 1. 파일 한 줄 씩 읽기
+ 2. 이름, 날짜 구분
+ 3. 날짜에서 날짜, 출석 시간 구분
+ 4. 날짜에서 요일 구별
+ 5. 요일에 해당하는 출근 시간과 출석 시간을 비교
+ 6. 출석, 결석, 지각 여부 판별
+ 7. 출근 기록 데이터에 날짜, 요일, 시간, 출결 여부 저장
+ - **출석 확인**
+ 1. 시스템 날짜와 요일 비교
+ 1. 주말 및 공휴일 일 경우 에러
+ 2. 이름 입력 받기(String)
+ 1. 이름이 멤버 데이터에 없으면 에러
+ 2. 이름이 출석 기록 데이터에 있으면 에러
+ 3. 형식 에러
+ 3. 시간 입력 받기(String → DateTime)
+ 1. 시간이 캠퍼스 운영시간이 아닌 경우 에러
+ 2. 형식 에러
+ 4. 출석 기록 데이터에 날짜, 요일, 시간, 출결 여부 저장
+ - **출석 수정**
+ 1. 이름 입력 받기(String)
+ 1. 이름이 멤버 데이터에 없으면 에러
+ 2. 형식 에러
+ 2. 날짜 입력 받기(String : 단일 날짜 → Integer → DateTime)
+ 1. 현재 날짜를 넘어가면 에러
+ 2. 주말 및 공휴일 일 경우 에러
+ 3. 형식 에러
+ 3. 시간 입력 받기(String : 시간제 ex)09:58 → DateTime)
+ 1. 캠퍼스 운영시간이 아닌 경우 에러
+ 4. 출석 기록 데이터에 날짜, 요일, 시간, 출결 여부 저장
+
+ - **크루별 출석 기록 확인**
+ 1. 이름 입력 받기(String)
+ 1. 이름이 멤버 데이터에 없으면 에러
+ 2. 형식 에러
+ 2. 출석 기록 데이터를 출력
+ 1. 현재 날짜 전날 까지 출력
+ 1. 날짜, 요일, 시간, 출결 여부 출력
+ 2. 날짜 오름차순으로 출력
+ 2. 총 출석, 지각, 결석 여부 출력
+ 3. (옵션) 면담 대상자일 경우 출력
+ - **제적 위험자 확인**
+ 1. 제적 위험자 출력
+
+ 출력 데이터
+
+ 1. 이름
+ 2. 결석 횟수
+ 3. 지각 횟수
+ 4. 제적, 면담, 경고 여부
+ 2. 정렬 기준
+ 1. 제적, 면담, 경고
+ 2. 결석, 지각 많은 순
+ 3. 이름 순
+
+- 2차 설계
+
+ **캘린더 List 생성하기**
+
+ 1. 12월 1일 부터 12월 31일 까지 List로 빈 List<날짜, List> 생성하기
+
+ **파일 읽어오기**
+
+ 1. 파일 한 줄 씩 읽기
+ 2. 이름, 날짜, 요일, 시간 구분
+ 3. 날짜에서 요일 구별
+ 4. 요일에 해당하는 출근 시간과 입력 받은 출근 시간 비교
+ 5. 출석,결석,지각 여부 판별
+ 6. 해당 날짜에 이름, 시간, 출결 여부 저장
+
+ **출석 확인**
+
+ 1. 출석 확인 진입 시
+ 1. 현재 시간을 로컬로 계산 (반환)
+ 2. 캘린더에서 날짜를 조회(반환)
+ 3. 요일 조회 (반환)
+ 1. 요일이 (토-일, 공휴일) 인 경우 에러 발생
+ 2. 이름 입력 받기
+ 1. 형식 에러
+ 2. 이름이 멤버 데이터에 없으면 에러
+ 3. 캘린더에서 이름이 조회 되면 에러
+ 3. 시간 입력 받기
+ 1. 요일에 맞는 출석 시간이 아니면 에러
+ 4. 캘린더 List에 새로운 데이터로 저장
+
+ **출석 수정**
+
+ 1. 출석 수정 진입 시
+ 1. 현재 시간을 로컬로 계산 (저장)
+ 2. 캘린더에서 날자 조회 (저장)
+ 3. 요일 조회 (저장)
+ 1. 요일이 (토-일, 공휴일) 인 경우 에러 발생
+ 2. 이름 입력 받기
+ 1. 형식 에러
+ 2. 이름이 멤버 데이터에 없으면 에러
+ 3. 날짜 입력 받기
+ 1. 형식 에러
+ 2. 로컬 날짜 이후인 경우 에러
+ 4. 시간 입력 받기
+ 1. 형식 에러
+ 2. 캠퍼스 운영시간보다 이르거나 느리면 에러 발생
+ 5. 캘린더 List에 새로운 데이터로 저장
+
+ **크루별 출석 기록 확인**
+
+ 1. 크루별 출석 기록 확인 진입 시
+ 1. 현재 시간을 로컬로 계산
+ 2. 변수 저장
+ 1. 총 출석
+ 2. 총 지각
+ 3. 총 결석
+ 2. 이름 입력 받기
+ 1. 형식 에러
+ 2. 이름이 멤버 데이터에 없으면 에러
+ 3. List 전체 순회
+ 1. 현재 시간 전날 까지 List 조회
+ 2. 이름을 fileter로 List Stream
+ 3. (옵션) 출석 있을 경우 출석에 저장
+ 4. (옵션) 지각 있을 경우 지각에 저장
+ 5. (옵션) 결석 있을 경우 결석에 저장
+ 4. List 출력하기
+ 5. 출결 기록 출력
+ 6. (옵션) 면담 대상자 여부 출력
+
+ **제적 위험자 확인**
+
+ 1. 제적 위험자 확인 진입 시
+ 1. 현재 시간을 로컬로 계산(저장)
+ 2. 캘린더 List 전체 조회
+ 1. 면담, 경고를 filter로 List Stream
+ 2. 정렬
+ 1. 제적, 면담, 경고
+ 2. 결석, 지각
+ 3. 이름
+ 3. List 출력하기
+
+### 필요 데이터
+
+- 1차 설계
+
+ **멤버 데이터**
+
+ → 데이터 자료 구조 : List
+
+ 필요한 데이터
+
+ - 이름
+
+ **출석 기록 데이터**
+
+ → 데이터 자료 구조 :
+
+ 추가(put)과 수정(update)가 쉬운 자료형일 것
+
+ 후보군
+
+ - Map
+
+ → 이름을 key, 나머지 값들 객채로서 value로 저장하는 Map
+
+ 이때 어떻게 할 것인가?
+
+ - 추가 할 때
+ 1. 이름 입력 받고
+
+ 예상 되는 단점
+
+ 출력할 때 정렬이 힘들 것
+
+ - List>
+
+ → 이름을 하나로 갖는 이중 리스트
+
+ → 제일 가능성 있어보이긴함
+
+ - 추가할 때
+
+ 조회: 이름이 name인 자료로 fileter 스트림해서 list 반환
+
+
+
+ 필요한 데이터
+
+ - 이름 (대표)
+ - 출석 기록
+ - 날짜
+ - 요일
+ - 시간
+ - 출석, 지각, 결석 여부
+ - 총 출석
+ - 총 지각
+ - 총 결석
+- 2차 설계
+
+ **멤버 데이터**
+
+ → 데이터 자료 구조 : List
+
+ 필요한 데이터
+
+ - 이름
+
+ **날짜별 출근 여부 데이터**
+
+ → 데이터 자료 구조 : enum? list?
+
+ 필요한 데이터
+
+ - 요일(월, 화-금, 토-일, 공휴일)
+ - 출근시간
+ - 퇴근시간
+
+ **캘린더 데이터**
+
+ → 데이터 자료 구조
+
+ List<날짜(dateTime), List<출석자(attendance)Object>>
+
+ → hashmap으로 변경
+
+ 필요한 데이터
+
+ - 날짜(id)
+ - 요일
+ - 출석자
+ - 출석한 사람 이름
+ - 출석 시간
+ - 출결 여부
+
+**개별 출석 데이터**
+
+→ 데이터 자료 구조 : Object
+
+필요한 데이터
+
+- 이름
+- 출석 시간
+- 출결 여부
+
+### 출력 형식
+
+**기본 메시지**
+
+오늘은 {날짜 = 월, 일 요일} 입니다. 기능을 선택해주세요
+
+1. 출석 확인
+2. 출석 수정
+3. 크루별 출석 기록 확인
+4. 제적 위험자 확인
+
+Q. 종료
+
+**출석 확인 메시지**
+
+- 닉네임을 입력해 주세요.
+- 등교 시간을 입력해 주세요.
+- {날짜 = 월, 일, 요일, 시간}, {출결 여부}
+
+**출석 수정 메시지**
+
+- 출석을 수정하려는 크루의 닉네임을 입력해 주세요.
+- 수정하려는 날짜(일)를 입력해 주세요.
+- 언제로 변경하겠습니까?
+- {날짜 = 월, 일, 요일, 시간}, {출결 여부} → {날짜 = 월, 일, 요일, 시간}, {출결 여부}
+
+**크루별 출석 기록 확인 메시지**
+
+- 닉네임을 입력해주세요.
+- 이번 달 {이름}의 출석 기록입니다.
+- {날짜 = 월, 일, 요일, 시간}, {출결 여부}
+- 출석 : {총 출석} 회
+- 지각 : {총 지각} 회
+- 결석: {총 결석} 회
+- (옵션) 면담 대상자 입니다. 경고 대상자 입니다.
+
+**제적 위험자 확인 메시지**
+
+- {이름} : 결석 {총 결석}회, 지각 {총 지각}회, {면담,경고 여부}
+
+### 에러 메시지
+
+잘못된 형식을 입력하였습니다.
+
+등록되지 않은 닉네임입니다.
+
+{날짜 = 월, 일, 요일}은 등교일이 아닙니다.
+
+아직 수정할 수 없습니다.
+
+캠퍼스 운영 시간에만 출석이 가능합니다.
+
+이미 출석을 확인하였습니다. 필요한 경우 수정 기능을 이용해 주세요.
+
+# 기능 구성 (입,출력)
\ No newline at end of file
diff --git a/src/main/java/attendance/Application.java b/src/main/java/attendance/Application.java
index e9b866e..a2c34fd 100644
--- a/src/main/java/attendance/Application.java
+++ b/src/main/java/attendance/Application.java
@@ -1,7 +1,408 @@
package attendance;
+import attendance.domain.Attendance;
+import attendance.util.ErrorMessage;
+import camp.nextstep.edu.missionutils.Console;
+import camp.nextstep.edu.missionutils.DateTimes;
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.text.ParseException;
+import java.time.Duration;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.format.TextStyle;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.TreeMap;
+
public class Application {
public static void main(String[] args) {
- // TODO: 프로그램 구현
+
+ // 캘린더 생성 (출석 기록)
+ HashMap> myCalender = new HashMap<>();
+ TreeMap> sortedCalender = new TreeMap<>();
+
+ LocalTime mondayClassStartTime = null;
+ LocalTime classStartTime = null;
+ LocalTime classEndTime = null;
+ LocalTime campusStartTime = null;
+ LocalTime campusEndTime = null;
+
+ DateTimeFormatter format = DateTimeFormatter.ofPattern("HH:mm");
+ mondayClassStartTime = LocalTime.parse("13:00",format);
+ classStartTime =LocalTime.parse("10:00", format);
+ classEndTime = LocalTime.parse("18:00", format);
+ campusStartTime = LocalTime.parse("08:00", format);
+ campusEndTime = LocalTime.parse("23:00", format);
+
+ // 멤버 데이터 저장
+ Set memberSet = new HashSet<>();
+
+ // 파일 입력 받고 저장하기
+ try {
+ String fileName = "src/main/resources/attendances.csv";
+ FileReader file = new FileReader(fileName);
+ BufferedReader bufferedReader = new BufferedReader(file);
+
+ bufferedReader.readLine();
+ DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
+ while (true) {
+// 1. 파일 한 줄 씩 읽기
+ String line = bufferedReader.readLine();
+ if (line == null) {
+ break;
+ }
+ // 2. 이름, 날짜, 요일, 시간 구분
+ String[] input = line.split(",");
+
+ // 이름
+ String nickNameInput = input[0];
+
+ // 날짜만 yyyy-mm-dd
+ LocalDateTime dateTimeInput = LocalDateTime.parse(input[1], dateTimeFormatter);
+ // 날짜
+ LocalDate date = dateTimeInput.toLocalDate();
+ // 시간
+ LocalTime time = dateTimeInput.toLocalTime();
+
+ // 디버깅 코드
+// System.out.println("Nickname: " + nickNameInput + " attendance time : " + dateTimeInput + " local date: " + date + " time: " + time2);
+
+
+ //3. 날짜에서 요일 구별
+ String dateOfInput = dateTimeInput.getDayOfWeek().toString();
+
+ // 4. 요일에 해당하는 출근 시간과 입력 받은 출근 시간 비교
+ Duration timeDiff = null;
+ if ( dateOfInput.equals("MONDAY") ) {
+ timeDiff = Duration.between(mondayClassStartTime,time);
+ }else{
+ timeDiff = Duration.between(classStartTime,time);
+ }
+
+ // 5. 출석,결석,지각 여부 판별
+ String roll = "";
+
+ if(timeDiff.getSeconds() <= 5 * 60){
+ roll = "출석";
+ }else if(timeDiff.getSeconds() <= 30 * 60){
+ roll = "지각";
+ }else
+ {
+ roll = "결석";
+ }
+
+ // 6. 해당 날짜에 이름, 시간, 출결 여부 저장
+
+ Attendance attendance = new Attendance(nickNameInput,time,roll);
+
+ //일단 조회
+ List attendances = myCalender.get(date);
+ if (attendances == null || attendances.size() == 0) {
+ List newAttendances = new ArrayList<>();
+ newAttendances.add(attendance);
+ myCalender.put(date,newAttendances);
+ }else{
+ attendances.add(attendance);
+ myCalender.put(date,attendances);
+ }
+ memberSet.add(nickNameInput);
+ }
+
+
+ // 정렬
+ sortedCalender = new TreeMap<>(myCalender);
+
+ // 파일 끝
+ bufferedReader.close();
+ } catch (IOException e) {
+ System.out.println("[ERROR] 파일 불러오기에 실패했습니다.");
+ }
+
+ // 로컬 시간 계산
+ LocalDateTime systemTime = DateTimes.now();
+// LocalDateTime systemTime = LocalDateTime.of(2024,12,12,10,10);
+ LocalDate currentDateAndTime = systemTime.toLocalDate();
+ int currentMonth = systemTime.getMonthValue();
+ int currentDay = systemTime.getDayOfMonth();
+ String currentDate = systemTime.getDayOfWeek().toString();
+ String currentDateDisplay = systemTime.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.KOREAN);
+
+ // 디버깅 코드
+ Iterator>> iterator = sortedCalender.entrySet().iterator();
+ while (iterator.hasNext()){
+ Entry> entry = iterator.next();
+ LocalDate localDate = entry.getKey();
+ List attendances = entry.getValue();
+ for(Attendance attendance : attendances){
+ System.out.println("날짜 : " + localDate + "/ 출석자 이름 : " + attendance.getName() + "/ 출석 시간 : " + attendance.getAttendanceTime().toString() + "/ 출결 : " + attendance.getRoll());
+
+ }
+ }
+
+ // 서비스 실행 (루프 시작)
+ while (true) {
+
+ // 기본 안내 메시지
+ System.out.printf("오늘은 %d월 %d일 %s입니다. 기능을 선택해주세요.\n", currentMonth, currentDay, currentDateDisplay);
+ System.out.println("1. 출석 확인\n"
+ + "2. 출석 수정\n"
+ + "3. 크루별 출석 기록 확인\n"
+ + "4. 제적 위험자 확인\n"
+ + "Q. 종료");
+
+ // 입력 받기
+
+ String command = Console.readLine();
+ if(command.equals("1")){
+// 1. 출석 확인 진입 시
+// 1. 현재 시간을 로컬로 계산 (반환)
+// 2. 캘린더에서 날짜를 조회(반환)
+// 3. 요일 조회 (반환)
+// 1. 요일이 (토-일, 공휴일) 인 경우 에러 발생
+ if (currentDate.equals("SUNDAY") || currentDate.equals("SATURDAY")) {
+ String errorMessage = String.format("[ERROR] %d월 %d일 %s은 등교일이 아닙니다.\n ", currentMonth, currentDay, currentDateDisplay);
+ throw new IllegalArgumentException(errorMessage);
+ }
+
+// 2. 이름 입력 받기
+ System.out.println("닉네임을 입력해 주세요.");
+ String nickNameInput = Console.readLine();;
+// 1. 형식 에러
+// 2. 이름이 멤버 데이터에 없으면 에러
+ if(!memberSet.contains(nickNameInput)){
+ throw new IllegalArgumentException(ErrorMessage.NO_NICKNAME_MATCH_FOUND);
+ }
+// 3. 캘린더에서 이름이 조회 되면 에러
+ System.out.println("조회 날짜 형식 " + currentDateAndTime);
+
+ //현재 날짜로 조회한 출석 부
+ List attendancesResult = sortedCalender.get(currentDateAndTime);
+
+ boolean isAlreadyAttendance = attendancesResult.stream()
+ .filter(attendance -> attendance.getName() == nickNameInput).findFirst().isPresent();
+
+ if(isAlreadyAttendance){
+ throw new IllegalArgumentException(ErrorMessage.ALREADY_ATTENDACNED);
+ }
+
+// 3. 시간 입력 받기
+ System.out.println("등교 시간을 입력해 주세요.");
+ String attendanceTimeInput = Console.readLine();
+// 0. 형식 에러
+ checkTimeInputType(attendanceTimeInput);
+ LocalTime attendanceTime = LocalTime.parse(attendanceTimeInput, DateTimeFormatter.ofPattern("HH:mm"));
+// 1. 캠퍼스 운영시간이 아니면 에러
+ if(attendanceTime.isBefore(campusStartTime) || attendanceTime.isAfter(campusEndTime)){
+ throw new IllegalArgumentException(ErrorMessage.NO_CAMPUS_RUNNINGTIME);
+ }
+
+ String roll = checkRoll(currentDate,mondayClassStartTime,classStartTime,attendanceTime);
+
+// 4. 캘린더 List에 새로운 데이터로 저장
+ Attendance newAttendance = new Attendance(nickNameInput,attendanceTime, roll);
+ attendancesResult.add(newAttendance);
+ sortedCalender.put(currentDateAndTime,attendancesResult);
+ System.out.printf("%d월 %d일 %s %s (%s)\n ", currentMonth, currentDay, currentDateDisplay, attendanceTimeInput, roll);
+ }
+
+
+// 1. 출석 수정 진입 시
+ if(command.equals("2")){
+
+// 1. 현재 시간을 로컬로 계산 (저장)
+// 2. 캘린더에서 날자 조회 (저장)
+// 3. 요일 조회 (저장)
+// 1. 요일이 (토-일, 공휴일) 인 경우 에러 발생
+// 2. 이름 입력 받기
+ System.out.println("출석을 수정하려는 크루의 닉네임을 입력해 주세요.");
+ String nickNameInput = Console.readLine();
+// 1. 형식 에러
+// 2. 이름이 멤버 데이터에 없으면 에러
+ if(!memberSet.contains(nickNameInput)){
+ throw new IllegalArgumentException(ErrorMessage.NO_NICKNAME_MATCH_FOUND);
+ }
+// 3. 날짜 입력 받기
+ System.out.println("수정하려는 날짜(일) 을 입력해 주세요.");
+ String fixDateInput = Console.readLine();
+ if(fixDateInput.length() == 1){
+ fixDateInput = "0" +fixDateInput;
+ }
+ String prefixDateInput = "2024-12-"+fixDateInput;
+ LocalDate fixDate = LocalDate.parse(prefixDateInput, DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+ String dateOfFixDate = fixDate.getDayOfWeek().toString();
+// 1. 형식 에러
+// 2. 로컬 날짜 이후인 경우 에러
+ if(fixDate.isAfter(currentDateAndTime)){
+ throw new IllegalArgumentException(ErrorMessage.CANNOT_FIX_TIME);
+ }
+// 3. 공휴일 일 경우 에러
+ if (dateOfFixDate.equals("SUNDAY") || dateOfFixDate.equals("SATURDAY")) {
+ String errorMessage = String.format("%d월 %d일 %s은 등교일이 아닙니다.\n ", currentMonth, currentDay, currentDateDisplay);
+ throw new IllegalArgumentException(errorMessage);
+ }
+// 4. 시간 입력 받기
+ System.out.println("언제로 변경하겠습니까?");
+ String fixTimeInput = Console.readLine();
+// 1. 형식 에러
+ checkTimeInputType(fixTimeInput);
+ LocalTime fixTime = LocalTime.parse(fixTimeInput, DateTimeFormatter.ofPattern("HH:mm"));
+// 2. 캠퍼스 운영시간보다 이르거나 느리면 에러 발생
+ if(fixTime.isBefore(campusStartTime) || fixTime.isAfter(campusEndTime)){
+ throw new IllegalArgumentException(ErrorMessage.NO_CAMPUS_RUNNINGTIME);
+ }
+
+ String roll = checkRoll(dateOfFixDate,mondayClassStartTime,classStartTime,fixTime);
+// 5. 캘린더 List에 새로운 데이터로 저장
+ List attendancesResult = sortedCalender.get(fixDate);
+ System.out.println("수정 목표 날짜" + fixDate + "수정 목표 이름 " + nickNameInput);
+// for(Attendance attendance : attendancesResult){
+// System.out.println(attendance.getName() + " 이름 " );
+// }
+ Attendance oldAttendance = attendancesResult.stream()
+ .filter(attendance -> attendance.getName().equals(nickNameInput))
+ .findFirst()
+ .orElse(null);
+
+ LocalTime oldTime = oldAttendance.getAttendanceTime();
+ String oldRoll = oldAttendance.getRoll();
+
+ int newMonth = fixDate.getMonthValue();
+ int newDay = fixDate.getDayOfMonth();
+ String newDate = fixDate.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.KOREAN);
+
+ attendancesResult.remove(oldAttendance);
+ Attendance newAttendance = new Attendance(nickNameInput,fixTime, roll);
+ attendancesResult.add(newAttendance);
+ sortedCalender.put(fixDate,attendancesResult);
+ System.out.printf("%d월 %d일 %s %s (%s) -> %s (%s) 수정 완료!\n",
+ newMonth, newDay,newDate, oldTime.toString(),oldRoll,
+ fixTime.toString(), roll);
+
+ }
+
+ if(command.equals("3")){
+ System.out.println("닉네임을 입력해 주세요.");
+ String nickNameInput = Console.readLine();
+ if(!memberSet.contains(nickNameInput)){
+ throw new IllegalArgumentException(ErrorMessage.NO_NICKNAME_MATCH_FOUND);
+ }
+ System.out.println("이번 달 " + nickNameInput +"의 출석 기록 입니다.");
+
+ int attendanceCount = 0;
+ int lateCount = 0;
+ int absenceCount = 0;
+
+ Iterator>> entries = sortedCalender.entrySet().iterator();
+ while(entries.hasNext()){
+ Entry> entry = entries.next();
+ LocalDate currDate = entry.getKey();
+ if(currDate.isEqual(currentDateAndTime)){
+ continue;
+ }
+ List attendancesList = entry.getValue();
+ Attendance attendanceResult = attendancesList.stream()
+ .filter(attendance -> attendance.getName().equals(nickNameInput))
+ .findFirst()
+ .orElse(null);
+ String time = "";
+ String roll = "";
+ if(attendanceResult == null){
+ time = "--:--";
+ roll = "결석";
+ }else{
+ time = attendanceResult.getAttendanceTime().toString();
+ roll = attendanceResult.getRoll();
+ }
+
+ if(roll == "출석"){
+ attendanceCount++;
+ }else if(roll == "지각"){
+ lateCount++;
+ }else{
+ absenceCount++;
+ }
+
+ int currMonth = currDate.getMonthValue();
+ int currDay = currDate.getDayOfMonth();
+ String formattedDay = String.format("%02d",currDay);
+ String currDateDisplay = currDate.getDayOfWeek().getDisplayName(TextStyle.FULL, Locale.KOREAN);
+
+ System.out.println(currMonth + "월 " +formattedDay + "일 " + currDateDisplay +" " + time + " (" + roll + ")");
+
+ }
+ System.out.println("출석: " + attendanceCount + "회");
+ System.out.println("지각: " + lateCount + "회");
+ System.out.println("결석: " + absenceCount + "회");
+
+ if(lateCount >3){
+ absenceCount += lateCount/3;
+ }
+ if(absenceCount >5){
+ System.out.println("제적 대상자입니다.");
+ }else if(absenceCount >=3){
+ System.out.println("면담 대상자입니다.");
+ }else if(absenceCount >=2){
+ System.out.println("경고 대상자입니다.");
+ }
+ }
+
+ if(command.equals("4")){
+ System.out.println("제적 위험자 조회 결과");
+
+ }
+
+ if(command.equals("Q")){
+ return;
+ }
+
+
+ }
+
+
+ }
+ public static void checkTimeInputType(String timeInput){
+ String[] times = timeInput.split(":");
+ if(times.length != 2){
+ throw new IllegalArgumentException(ErrorMessage.TYPE_ERROR);
+ }
+ int hour = Integer.parseInt(times[0]);
+ int minute = Integer.parseInt(times[1]);
+ if(hour < 0 || hour > 23 || minute < 0 || minute > 59){
+ throw new IllegalArgumentException(ErrorMessage.TYPE_ERROR);
+ }
+
+ }
+ public static String checkRoll(String dateOfInput, LocalTime mondayStartTime, LocalTime startTime, LocalTime time){
+ // 4. 요일에 해당하는 출근 시간과 입력 받은 출근 시간 비교
+ Duration timeDiff = null;
+ if ( dateOfInput.equals("MONDAY") ) {
+ timeDiff = Duration.between(mondayStartTime,time);
+ }else{
+ timeDiff = Duration.between(startTime,time);
+ }
+
+ // 5. 출석,결석,지각 여부 판별
+ String roll = "";
+
+ if(timeDiff.getSeconds() <= 5 * 60){
+ roll = "출석";
+ }else if(timeDiff.getSeconds() <= 30 * 60){
+ roll = "지각";
+ }else
+ {
+ roll = "결석";
+ }
+ return roll;
}
}
diff --git a/src/main/java/attendance/domain/Attendance.java b/src/main/java/attendance/domain/Attendance.java
new file mode 100644
index 0000000..c68b1bd
--- /dev/null
+++ b/src/main/java/attendance/domain/Attendance.java
@@ -0,0 +1,37 @@
+package attendance.domain;
+
+import java.time.LocalDate;
+import java.time.LocalTime;
+import java.util.Date;
+
+public class Attendance {
+
+ private String name;
+ private LocalTime attendanceTime;
+ private String roll;
+
+ /*
+ * 출결 결과 저장 객체
+ * 이름, 출석 시간, 출결*/
+ public Attendance(String name, LocalTime attendanceTime, String roll) {
+ this.name = name;
+ this.attendanceTime = attendanceTime;
+ this.roll = roll;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public void setTime(LocalTime attendanceTime) {
+ this.attendanceTime = attendanceTime;
+ }
+
+ public LocalTime getAttendanceTime() {
+ return attendanceTime;
+ }
+
+ public String getRoll() {
+ return roll;
+ }
+}
diff --git a/src/main/java/attendance/util/ErrorMessage.java b/src/main/java/attendance/util/ErrorMessage.java
new file mode 100644
index 0000000..89644dc
--- /dev/null
+++ b/src/main/java/attendance/util/ErrorMessage.java
@@ -0,0 +1,9 @@
+package attendance.util;
+
+public class ErrorMessage {
+ public static String NO_NICKNAME_MATCH_FOUND = "[ERROR] 등록되지 않은 닉네임입니다.";
+ public static String TYPE_ERROR = "[ERROR] 잘못된 형식을 입력하였습니다.";
+ public static String CANNOT_FIX_TIME = "[ERROR] 아직 수정할 수 없습니다.";
+ public static String NO_CAMPUS_RUNNINGTIME = "[ERROR] 캠퍼스 운영 시간에만 출석이 가능합니다.";
+ public static String ALREADY_ATTENDACNED = "[ERROR] 이미 출석을 확인하였습니다. 필요한 경우 수정 기능을 이용해 주세요.";
+}