JavaScrpt/시간 날짜 달력

JavaScript Date - 주간 달력 만들기 (주간 달력 생성 함수 - 숫자/문자열 배열), Weekly Calendar

carrotweb 2022. 4. 9. 17:53
728x90
반응형

주간 달력은 월간 달력과 달리 일주일(Week) 단위로 처리됩니다.

그리고 월 초에는 이전 달 마지막 주와 합쳐져서 처리되어야 합니다. 그래서 이전 달의 마지막 일을 구해야 합니다.

월 말에는 다음 달 첫 주와 합쳐져 처리되어야 합니다.

// 달력 연도
var calendarYear = date.getFullYear();
// 달력 월
var calendarMonth = date.getMonth() + 1;
// 달력 일
var calendarToday = date.getDate();

var monthLastDate = new Date(calendarYear, calendarMonth, 0);
// 달력 월의 마지막 일
var calendarMonthLastDate = monthLastDate.getDate();

// 달력 이전 월의 마지막 일
var prevMonthLastDate = new Date(calendarYear, calendarMonth - 1, 0);

// 달력 현재 요일
var calendarMonthTodayDay = date.getDay();

console.log(calendarYear);
--> 2022
console.log(calendarMonth);
--> 3
console.log(calendarToday);
--> 20
console.log(calendarMonthLastDate);
--> 31
console.log(prevMonthLastDate.getDate());
--> 28 (2022-02-28)
console.log(calendarMonthTodayDay);
--> 0 (일요일)

 

 

주간 날짜 계산

주간 달력은 배열을 사용합니다. 7개(일주일)로 배열을 초기화합니다.

// 주간 배열
var arWeek = [0, 0, 0, 0, 0, 0, 0];

 

현재 날짜의 요일(일요일 = 0)을 기준으로 이후 날짜를 배열에 추가합니다.

// 현재 요일부터 주간 배열에 날짜를 추가
var weekDay = calendarToday;
for (var index = calendarMonthTodayDay; index < 7; index++) {
	arWeek[index] = weekDay++; --> 날짜가 배열에 추가된 후 날짜가 증가
}

console.log(arWeek);
--> [20, 21, 22, 23, 24, 25, 26]

 

그러나 월의 마지막 일이 포함된 주에서는 날짜가 월의 마지막 일을 초과하게 됩니다.

// 현재 날짜가 2022-03-29 이면

// 현재 요일부터 주간 배열에 날짜를 추가
var weekDay = calendarToday;
for (var index = calendarMonthTodayDay; index < 7; index++) {
	arWeek[index] = weekDay++; --> 날짜가 배열에 추가된 후 날짜가 증가
}

console.log(arWeek);
--> [0, 0, 29, 30, 31, 32, 33]

 

그래서 처리된 날짜가 현재 월의 마지막 일보다 크면 다음 월이 시작되기 때문에 날짜를 1로 변경합니다.

// 현재 날짜가 2022-03-29 이면

// 현재 요일부터 주간 배열에 날짜를 추가
var weekDay = calendarToday;
for (var index = calendarMonthTodayDay; index < 7; index++) {
	arWeek[index] = weekDay++;
	// 날짜가 현재 월의 마지막 일보다 크면 다음 월의 1일로 변경
	if (weekDay > calendarMonthLastDate) {
		weekDay = 1;
	}
}

console.log(arWeek);
--> [0, 0, 29, 30, 31, 1, 2]

 

현재 날짜의 요일(화요일 = 2)을 기준으로 이전 날짜를 배열에 추가합니다.

// 현재 날짜가 2022-03-29 이면

// 현재 요일부터 꺼꾸로 주간 배열에 날짜를 추가
weekDay = calendarToday;
for (var index = calendarMonthTodayDay - 1; index >= 0; index--) {
	weekDay--;
	arWeek[index] = weekDay;
}

console.log(arWeek);
--> [27, 28, 29, 30, 31, 1, 2]

 

 

그러나 월의 1일이 포함된 주에서는 날짜가 음수가 됩니다.

// 현재 날짜가 2022-03-01 이면

// 현재 요일부터 꺼꾸로 주간 배열에 날짜를 추가
weekDay = calendarToday;
for (var index = calendarMonthTodayDay - 1; index >= 0; index--) {
	weekDay--;
	arWeek[index] = weekDay;
}

console.log(arWeek);
--> [-1, 0, 1, 2, 3, 4, 5]

 

그래서 처리된 날짜가 현재 월의 1일보다 작으면 이전 월이 마지막 주가 되기 때문에 날짜를 이전 월의 마지막 일로 변경합니다.

// 현재 날짜가 2022-03-01 이면

// 현재 요일부터 꺼꾸로 주간 배열에 날짜를 추가
weekDay = calendarToday;
for (var index = calendarMonthTodayDay - 1; index >= 0; index--) {
	weekDay--;
	// 날짜가 현재 월의 1일이면 작으면 이전 월의 마지막 일로 변경
	if (weekDay == 0) {
		weekDay = prevMonthLastDate.getDate();
	}
	arWeek[index] = weekDay;
}

console.log(arWeek);
--> [27, 28, 1, 2, 3, 4, 5]

 

주간 배열을 사용하면 날짜를 표시하는 데는 문제가 없습니다.

 

그러나 날짜 클릭 이벤트 사용하여 처리하는 로직이 있다면 클릭 날짜의 연도와 월을 알아야 합니다.

주간 달력은 월간 달력과 다르게 월의 1일에는 이전 달과 월의 마지막 일에는 다음 달이 포함되어서 처리됩니다.

예를 들어, 현재 날짜가 2022년 1월 1일이면 이전 달은 2021년 12월이고 현재 날짜가 2022년 12월 31일이면 다음 달은 2023년 1월이 됩니다. 그래서 연도와 월을 같이 포함해야 합니다.

이전 월은 위에 포함되어 있으니 다음 월을 추가합니다.

// 달력 다음 월의 시작 일
var nextMonthStartDate = new Date(calendarYear, calendarMonth, 1);

 

주간 배열을 문자열 배열을 초기화합니다.

// 주간 배열
var arWeek = ["", "", "", "", "", "", ""];

 

주간 달력 계산에서 날짜가 현재 월의 마지막 일보다 크면 다음 달로 연도와 월을 변경합니다. 그리고 날짜가 현재 월의 1일보다 작으면 이전 달로 연도와 월을 변경합니다.

var weekYear = calendarYear;
var weekMonth = calendarMonth;
var weekDay = calendarToday;
// 현재 요일부터 주간 배열에 날짜를 추가
for (var index = calendarMonthTodayDay; index < 7; index++) {
	arWeek[index] = weekYear +"-" + weekMonth + "-" + weekDay;
	weekDay++;
	// 날짜가 현재 월의 마지막 일보다 크면 다음 월의 1일로 변경
	if (weekDay > calendarMonthLastDate) {
		weekYear = nextMonthStartDate.getFullYear();
		weekMonth = nextMonthStartDate.getMonth() + 1;
		weekDay = 1;
	}
}

weekYear = calendarYear;
weekMonth = calendarMonth;
weekDay = calendarToday;
// 현재 요일부터 꺼꾸로 주간 배열에 날짜를 추가
for (var index = calendarMonthTodayDay - 1; index >= 0; index--) {
	weekDay--;
	// 날짜가 현재 월의 1일이면 작으면 이전 월의 마지막 일로 변경
	if (weekDay == 0) {
		weekYear = prevMonthLastDate.getFullYear();
		weekMonth = prevMonthLastDate.getMonth() + 1;
		weekDay = calendarPrevMonthLastDate;
	}
	arWeek[index] = weekYear +"-" + weekMonth + "-" + weekDay;
}

// 현재 날짜가 2022-03-29 이면
console.log(arWeek);
--> ['2022-3-27', '2022-3-28', '2022-3-29', '2022-3-30', '2022-3-31', '2022-4-1', '2022-4-2']

// 현재 날짜가 2022-03-01 이면
console.log(arWeek);
--> ['2022-2-27', '2022-2-28', '2022-3-1', '2022-3-2', '2022-3-3', '2022-3-4', '2022-3-5']

 

이제 주간 달력에서 이전 달의 연도와 월, 다음 달의 연도와 월을 고민하지 않아도 됩니다.

주간 달력 함수를 생성하기 전에 월간이나 주간에서 공동으로 사용될 공휴일 배열, 요일 배열, 기본값 처리 로직, 요일 HTML 생성 로직, 공휴일 검색 로직 등을 분리합니다.

 

calendar.js 파일을 오픈하여 수정합니다.

// 달력 요일
var calendarDays = ["일", "월", "화", "수", "목", "금", "토"];

// 달력 요일 HTML
function calendarWeekHTML(options) {
	var html = "<thead><tr>";
	for (var index = 0; index < calendarDays.length; index++) {
		html += "<th";
		if (index == 0) {
			html += " class=\"sunday\"";
		} else if (index == 6) {
			html += " class=\"saturday\"";
		}
		html += ">" + calendarDays[index];
		if (options.showFullDayName) {
			html += "요일";
		}
		html += "</th>";
	}
	html += "</tr></thead>";
	return html;
}

// 달력 공휴일
var hashmapCalendarHoliday = [];
hashmapCalendarHoliday["1-1"] = {"title" : "새해"};
hashmapCalendarHoliday["3-1"] = {"title" : "삼일절"};
hashmapCalendarHoliday["5-5"] = {"title" : "어린이날"};
hashmapCalendarHoliday["6-6"] = {"title" : "현충일"};
hashmapCalendarHoliday["8-15"] = {"title" : "광복절"};
hashmapCalendarHoliday["10-3"] = {"title" : "개천절"};
hashmapCalendarHoliday["10-9"] = {"title" : "한글날"};
hashmapCalendarHoliday["12-25"] = {"title" : "성탄절"};

// 달력 공휴일 함수
function getCalendarHoliday(calendarYear, calendarMonth, calendarDay) {
	if (Object.keys(hashmapCalendarHoliday).length == 0) {
		return null;
	}
	
	// 공휴일(임시 공휴일 포함)
	var holidayInfo = hashmapCalendarHoliday[calendarYear + "-" + calendarMonth + "-" + calendarDay];
	if (holidayInfo == undefined || holidayInfo == null) {
		holidayInfo = hashmapCalendarHoliday[calendarMonth + "-" + calendarDay];
	}
	return holidayInfo ;
}

// 기본값 처리
function setCalendarOptions(options) {
	// 기본값 처리
	if (options.showDay == undefined || options.showDay == null || typeof options.showDay != "boolean") {
		options.showDay = true;
	}
	if (options.showFullDayName == undefined || options.showFullDayName == null || typeof options.showFullDayName != "boolean") {
		options.showFullDayName = false;
	}
	if (options.showToday == undefined || options.showToday == null || typeof options.showToday != "boolean") {
		options.showToday = true;
	}
	
	// 공휴일 처리
	if (options.arHoliday != undefined && options.arHoliday != null && Array.isArray(options.arHoliday)) {
		Object.assign(hashmapCalendarHoliday, options.arHoliday);
	}
}

 

월간 달력 생성 함수에 적용합니다.

// 월간 달력 생성 함수
function calendarHTML(date, options) {
	// 데이터 검증
	if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
		return "";
	}
	
	setCalendarOptions(options);
	
	// 달력 연도
	var calendarYear = date.getFullYear();
	// 달력 월
	var calendarMonth = date.getMonth() + 1;
	// 달력 일
	var calendarToday = date.getDate();
	
	var monthLastDate = new Date(calendarYear, calendarMonth, 0);
	// 달력 월의 마지막 일
	var calendarMonthLastDate = monthLastDate.getDate();
	
	var monthStartDay = new Date(calendarYear, date.getMonth(), 1);
	// 달력 월의 시작 요일
	var calendarMonthStartDay = monthStartDay.getDay();
	
	// 주 카운트
	var calendarWeekCount = Math.ceil((calendarMonthStartDay + calendarMonthLastDate) / 7);
	
	// 오늘
	var today = new Date();
	
	var html = "";
	html += "<table>";
	if (options.showDay) {
		html += calendarWeekHTML(options);
	}
	html += "<tbody>";
	// 위치
	var calendarPos = 0;
	// 날짜
	var calendarDay = 0;
	for (var index1 = 0; index1 < calendarWeekCount; index1++) {
		html += "<tr>";
		for (var index2 = 0; index2 < 7; index2++) {
			html += "<td";
			if (calendarMonthStartDay <= calendarPos && calendarDay < calendarMonthLastDate) {
				calendarDay++;
				html += " data-date=\"" + calendarYear + "-" + (calendarMonth < 10 ? "0" : "") + calendarMonth + "-" + (calendarDay < 10 ? "0" : "") + calendarDay +  "\">";
				html += "<span";
				if (options.showToday && calendarYear == today.getFullYear() && calendarMonth == today.getMonth() + 1
					&& calendarDay == today.getDate()) {
					html += " class=\"today\"";
				} else {
					var holiday = false;
					var holidayInfo = getCalendarHoliday(calendarYear, calendarMonth, calendarDay);
					if (holidayInfo != undefined && holidayInfo != null) {
						html += " class=\"holiday\"";
						holiday = true;
					}
					if (!holiday) {
						if (index2 == 0) {
							html += " class=\"sunday\"";
						} else if (index2 == 6) {
							html += " class=\"saturday\"";
						}
					}
				}
				var holidayInfo = getCalendarHoliday(calendarYear, calendarMonth, calendarDay);
				if (holidayInfo != undefined && holidayInfo != null) {
					html += " title=\"" + holidayInfo.title + "\"";
				}
				html += ">" + calendarDay + "</span>";
			} else {
				html += ">";
			}
			html += "</td>";
			calendarPos++;
		}
		html += "</tr>";
	}
	html += "</tbody>";
	html += "</table>";
	return html;
}

 

 

 

주간 달력 함수 생성

주간 배열을 사용하여 주간 달력 함수를 생성합니다. 달력의 UI는 월간 달력과 동일한 구조입니다.

calendar.js 파일을 오픈하여 주간 달력 함수를 추가합니다.

// 주간 달력 생성 함수
function weekHTML(date, options) {
	// 데이터 검증
	if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
		return "";
	}
	
	setCalendarOptions(options);
	
	// 달력 연도
	var calendarYear = date.getFullYear();
	// 달력 월
	var calendarMonth = date.getMonth() + 1;
	// 달력 일
	var calendarToday = date.getDate();
	
	var monthLastDate = new Date(calendarYear, calendarMonth, 0);
	// 달력 월의 마지막 일
	var calendarMonthLastDate = monthLastDate.getDate();

	// 달력 이전 월의 마지막 일
	var prevMonthLastDate = new Date(calendarYear, calendarMonth - 1, 0);

	// 달력 다음 월의 시작 일
	var nextMonthStartDate = new Date(calendarYear, calendarMonth, 1);
	
	// 달력 현재 요일
	var calendarMonthTodayDay = date.getDay();
	
	// 주간 배열
	var arWeek = ["", "", "", "", "", "", ""];
	
	var weekYear = calendarYear;
	var weekMonth = calendarMonth;
	var weekDay = calendarToday;
	// 현재 요일부터 주간 배열에 날짜를 추가
	for (var index = calendarMonthTodayDay; index < 7; index++) {
		arWeek[index] = weekYear +"-" + weekMonth + "-" + weekDay;
		weekDay++;
		// 날짜가 현재 월의 마지막 일보다 크면 다음 월의 1일로 변경
		if (weekDay > calendarMonthLastDate) {
			weekYear = nextMonthStartDate.getFullYear();
			weekMonth = nextMonthStartDate.getMonth() + 1;
			weekDay = 1;
		}
	}
	
	weekYear = calendarYear;
	weekMonth = calendarMonth;
	weekDay = calendarToday;
	// 현재 요일부터 꺼꾸로 주간 배열에 날짜를 추가
	for (var index = calendarMonthTodayDay - 1; index >= 0; index--) {
		weekDay--;
		// 날짜가 현재 월의 1일이면 작으면 이전 월의 마지막 일로 변경
		if (weekDay == 0) {
			weekYear = prevMonthLastDate.getFullYear();
			weekMonth = prevMonthLastDate.getMonth() + 1;
			weekDay = prevMonthLastDate.getDate();
		}
		arWeek[index] = weekYear +"-" + weekMonth + "-" + weekDay;
	}
		
	// 오늘
	var today = new Date();
	
	var html = "";
	html += "<table>";
	if (options.showDay) {
		html += calendarWeekHTML(options);
	}
	html += "<tbody>";
	html += "<tr>";
	for (var index = 0; index < 7; index++) {
		var arWeekDate = arWeek[index].split("-");
		var year = arWeekDate[0];
		var month = arWeekDate[1];
		var day = arWeekDate[2];
		html += "<td data-date=\"" + year + "-" + (month < 10 ? "0" : "") + month + "-" + (day < 10 ? "0" : "") + day +  "\">";
		html += "<span";
		if (options.showToday && year == today.getFullYear() && month == today.getMonth() + 1
			&& day == today.getDate()) {
			html += " class=\"today\"";
		} else {
			var holiday = false;
			var holidayInfo = getCalendarHoliday(year, month, day);
			if (holidayInfo != undefined && holidayInfo != null) {
				html += " class=\"holiday\"";
				holiday = true;
			}
			if (!holiday) {
				if (index == 0) {
					html += " class=\"sunday\"";
				} else if (index == 6) {
					html += " class=\"saturday\"";
				}
			}
		}
		var holidayInfo = getCalendarHoliday(year, month, day);
		if (holidayInfo != undefined && holidayInfo != null) {
			html += " title=\"" + holidayInfo.title + "\"";
		}
		html += ">" + day + "</span>";
		html += "</td>";
	}
	html += "</tbody>";
	html += "</table>";
	return html;
}

 

주간 달력 생성 함수를 사용하여 주간 달력을 만들겠습니다.

<!DOCTYPE html>
<html>
	<head>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<title>주간 달력 만들기</title>
		<link rel="stylesheet" type="text/css" href="calendar.css" />
		<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
		<script src="calendar.js"></script>
	</head>
	<body>
		<div class="calendar month">
			<div class="calendar-header">
				<span class="calendar-yearmonth"></span>
			</div>
			<div id="calendar"></div>
		</div>
		<script>
			var options = {
				showDay : true,
				showFullDayName : true,
				showToday : true
			};
			
			var date = new Date();
			var html = weekHTML(date, options);
			$(".calendar-yearmonth").html(date.getFullYear() + "년 " + (date.getMonth() + 1) + "월");
			$("#calendar").html(html);
		</script>
	</body>
</html>

 

월간 달력과 동일하게 <td> 태그의 data-date 속성으로 연월일이 있는 것을 확인할 수 있습니다.

728x90
반응형