JavaScrpt/시간 날짜 달력

JavaScript Date - 달력 생성 함수 모듈화 3 (공휴일 표시, 해시맵(HashMap))

carrotweb 2022. 3. 27. 15:27
728x90
반응형

공휴일 표시 및 툴팁 표시

달력에 공휴일(국가에서 정한 휴일)을 표시하기 위해서 공휴일 정보가 있는 배열을 객체에 추가합니다.

공휴일 정보는 날짜(date)와 공휴일 명(title)으로 구성합니다.

var options = {
	showToday : true,
	arHoliday : [{"date" : "3-1", "title" : "삼일절"}]
};

3월의 공휴일은 삼일절(3월 1일)입니다.

<style>에 공휴일(holiday)의 폰트 컬러를 추가합니다.

.calendar table > tbody > tr > td > span.holiday { color: red; }

 

스크립트의 배열(Array) 객체는 typeof로는 object로 나옵니다. 그래서 instanceof를 사용하여 생성 타입을 확인하거나 Array.isArray() 메서드를 사용하여 배열(Array)인지 확인합니다.

console.log(typeof options.arHoliday); --> object
console.log(options.arHoliday instanceof Array); --> true
console.log(Array.isArray(options.arHoliday)); --> true

 

배열이 전달되지 않거나 타입이 맞지 않으면 배열을 초기화합니다.

arHoliday = [];

 

함수에 공휴일 배열을 이용하여 달력의 날짜가 공휴일과 같으면 표시되도록 추가합니다.

function calendarHTML(date, options) {
	// 데이터 검증
	if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
		return "";
	}
	
	// 기본값 처리
	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)) {
		options.arHoliday = [];
	}
	
	// 요일
	var days = ["일", "월", "화", "수", "목", "금", "토"];
	
	// 달력 연도
	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 += "<thead><tr>";
		for (var index = 0; index < days.length; index++) {
			html += "<th";
			if (index == 0) {
				html += " class=\"sunday\"";
			} else if (index == 6) {
				html += " class=\"saturday\"";
			}
			html += ">" + days[index];
			if (options.showFullDayName) {
				html += "요일";
			}
			html += "</th>";
		}
		html += "</tr></thead>";
	}
	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 += "<span";
				if (options.showToday && calendarYear == today.getFullYear() && calendarMonth == today.getMonth() + 1
					&& calendarDay == today.getDate()) {
					html += " class=\"today\"";
				} else {
					var holiday = false;
					if (options.arHoliday.length > 0) {
						// 공휴일
						for (index3 = 0; index3 < options.arHoliday.length; index3++) {
							var arHolidayDay = options.arHoliday[index3].date.split("-");
							if (arHolidayDay.length == 2) {
								if (parseInt(arHolidayDay[0]) == calendarMonth && parseInt(arHolidayDay[1]) == calendarDay) {
									html += " class=\"holiday\" title=\"" + options.arHoliday[index3].title + "\"";
									holiday = true;
									break;
								}
							}
						}
					}
					if (!holiday) {
						if (index2 == 0) {
							html += " class=\"sunday\"";
						} else if (index2 == 6) {
							html += " class=\"saturday\"";
						}
					}
				}
				html += ">" + calendarDay + "</span>";
			}
			html += "</td>";
			calendarPos++;
		}
		html += "</tr>";
	}
	html += "</tbody>";
	html += "</table>";
	return html;
}

 

 

3월 1일(삼일절)이 붉은색으로 표시되는 것을 확인할 수 있습니다.

 

 

배열의 문제점

배열이 크기가 커지거나 검색 결과 뒤에 있으면 결과가 나올 때까지 배열을 for 문으로 검사하게 되어 속도가 느려지게 됩니다.

그래서 배열(Array)보다는 해시맵(HashMap)을 사용하는 것이 좋습니다.

해시맵(HashMap)이란

해시맵(HashMap)은 키(Key)와 값(Value)로 된 객체로 키(Key)를 해시코드(hashCode - 해시 알고리즘으로 생성된 정수)로 변환하여 해시 테이블(hash table - 키(Key)와 값(Value)으로 된 데이터를 저장하고 빠르게 데이터를 검색할 수 있는 자료 구조)에 저장하고 검색하여 값(Value)을 가져옵니다.

스크립트 내장 객체에는 해시맵(HashMap) 객체가 없습니다.

그렇지만 배열(Array)을 해시맵(HashMap)처럼 사용할 수 있습니다.

// 배열(Array)
var arHoliday = [];
// put
arHoliday[0] = {"date" : "3-1", "title" : "삼일절"}; --> 인덱스 사용
arHoliday.push({"date" : "3-1", "title" : "삼일절"}); --> push 메서드 사용
// get
console.log(arHoliday[0]); --> {date: '3-1', title: '삼일절'}

// 인덱스로 저장
console.log(arHoliday); --> 0: {date: '3-1', title: '삼일절'}

 

배열의 인덱스에 키(Key)를 적용하면 해시맵(HashMap) 객체처럼 사용할 수 있습니다.

// 해시맵(HashMap)
var hashmapHoliday = [];
// put
hashmapHoliday["3-1"] = {"title" : "삼일절"};
// get
console.log(hashmapHoliday["3-1"]); --> {title: '삼일절'}

// 키(Key)로 저장
console.log(hashmapHoliday); --> 3-1: {title: '삼일절'}

 

배열(Array)를 해시맵(HashMap)처럼 사용할 경우 length으로 배열의 크기를 알 수 없습니다.

그래서 Object.keyd() 메서드를 사용하여 키(Key)의 수를 얻을 수 있습니다.

// 배열(Array) 크기
console.log(options.arHoliday.length); --> 0

// 해시맵(HashMap) 크기
console.log(Object.keys(options.arHoliday).length); --> 1

 

함수를 해시맵(HashMap)을 사용하여 공휴일(holiday)을 표시하도록 변경하겠습니다.

// 해시맵(HashMap)
var hashmapHoliday = [];
hashmapHoliday["3-1"] = {"title" : "삼일절"};

var options = {
	showFullDayName : true,
	showToday : false,
	arHoliday : hashmapHoliday
};

 

 

function calendarHTML(date, options) {
	// 데이터 검증
	if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
		return "";
	}
	
	// 기본값 처리
	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)) {
		options.arHoliday = [];
	}
	
	// 요일
	var days = ["일", "월", "화", "수", "목", "금", "토"];
	
	// 달력 연도
	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 += "<thead><tr>";
		for (var index = 0; index < days.length; index++) {
			html += "<th";
			if (index == 0) {
				html += " class=\"sunday\"";
			} else if (index == 6) {
				html += " class=\"saturday\"";
			}
			html += ">" + days[index];
			if (options.showFullDayName) {
				html += "요일";
			}
			html += "</th>";
		}
		html += "</tr></thead>";
	}
	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 += "<span";
				if (options.showToday && calendarYear == today.getFullYear() && calendarMonth == today.getMonth() + 1
					&& calendarDay == today.getDate()) {
					html += " class=\"today\"";
				} else {
					var holiday = false;
					if (Object.keys(options.arHoliday).length > 0) {
						// 공휴일
						var holidayInfo = options.arHoliday[calendarMonth + "-" + calendarDay];
						if (holidayInfo != undefined && holidayInfo != null) {
							html += " class=\"holiday\" title=\"" + holidayInfo.title + "\"";
							holiday = true;
						}
					}
					if (!holiday) {
						if (index2 == 0) {
							html += " class=\"sunday\"";
						} else if (index2 == 6) {
							html += " class=\"saturday\"";
						}
					}
				}
				html += ">" + calendarDay + "</span>";
			}
			html += "</td>";
			calendarPos++;
		}
		html += "</tr>";
	}
	html += "</tbody>";
	html += "</table>";
	return html;
}

 

 

 

공휴일 내장 처리 및 임시 공휴일 처리

변경되지 않는 공휴일(holiday)을 함수에 내장시키고 Object.assign() 메서드를 사용하여 변경되거나 추가되게 처리하겠습니다. 그리고 임시 공휴일은 특정 연도만 있기 때문에 연도까지 포함하여 해시맵에서 검사 되게 처리합니다.

function calendarHTML(date, options) {
	// 데이터 검증
	if (date == undefined || date == null || typeof date != "object" || !date instanceof Date) {
		return "";
	}
	
	// 기본값 처리
	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;
	}

	// 공휴일
	var hashmapHoliday = [];
	hashmapHoliday["1-1"] = {"title" : "신정"};
	hashmapHoliday["3-1"] = {"title" : "삼일절"};
	hashmapHoliday["5-5"] = {"title" : "어린이날"};
	hashmapHoliday["6-6"] = {"title" : "현충일"};
	hashmapHoliday["8-15"] = {"title" : "광복절"};
	hashmapHoliday["10-3"] = {"title" : "개천절"};
	hashmapHoliday["10-9"] = {"title" : "한글날"};
	hashmapHoliday["12-25"] = {"title" : "성탄절"};
	
	if (options.arHoliday != undefined && options.arHoliday != null && Array.isArray(options.arHoliday)) {
		Object.assign(hashmapHoliday, options.arHoliday);
	}
	
	// 요일
	var days = ["일", "월", "화", "수", "목", "금", "토"];
	
	// 달력 연도
	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 += "<thead><tr>";
		for (var index = 0; index < days.length; index++) {
			html += "<th";
			if (index == 0) {
				html += " class=\"sunday\"";
			} else if (index == 6) {
				html += " class=\"saturday\"";
			}
			html += ">" + days[index];
			if (options.showFullDayName) {
				html += "요일";
			}
			html += "</th>";
		}
		html += "</tr></thead>";
	}
	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 += "<span";
				if (options.showToday && calendarYear == today.getFullYear() && calendarMonth == today.getMonth() + 1
					&& calendarDay == today.getDate()) {
					html += " class=\"today\"";
				} else {
					var holiday = false;
					if (Object.keys(hashmapHoliday).length > 0) {
						// 공휴일(임시 공휴일 포함)
						var holidayInfo = hashmapHoliday[calendarYear + "-" + calendarMonth + "-" + calendarDay];
						if (holidayInfo == null) {
							holidayInfo = hashmapHoliday[calendarMonth + "-" + calendarDay];
						}
						if (holidayInfo != undefined && holidayInfo != null) {
							html += " class=\"holiday\" title=\"" + holidayInfo.title + "\"";
							holiday = true;
						}
					}
					if (!holiday) {
						if (index2 == 0) {
							html += " class=\"sunday\"";
						} else if (index2 == 6) {
							html += " class=\"saturday\"";
						}
					}
				}
				html += ">" + calendarDay + "</span>";
			}
			html += "</td>";
			calendarPos++;
		}
		html += "</tr>";
	}
	html += "</tbody>";
	html += "</table>";
	return html;
}

 

2022년 3월 9일은 20대 대통령 선거일이었습니다. 그래서 임시 공휴일로 달력에서 공휴일로 표시되게 추가합니다.

function calendar(date) {
	// 년월
	$(".calendar-yearmonth").html(date.getFullYear() + "." + (date.getMonth() + 1));
	
	// 임시 공휴일
	var hashmapHoliday = [];
	hashmapHoliday["2022-3-9"] = {"title" : "20대 대통령 선거일"};
	
	var options = {
		showFullDayName : true,
		showToday : false,
		arHoliday : hashmapHoliday
	};
	
	var html = calendarHTML(date, options);
	$("#calendar").html(html);
}

728x90
반응형