오늘의 만들어볼까요?
자바스크립트의 date객체를 이용해 달력을 만들어보자.
만들기 조건
- table이 아니라 flex 레이아웃을 이용
- 클래스를 활용해 css로 스타일 지정
- 달력은 월요일부터 시작
- 이전달의 월요일부터 마지막 날까지 표기
- 다음 달의 1일부터 일요일까지 표기
- 선택자 등등은 JQuery 이용
1. 날짜 가져오기
날짜 정보를 가져오기 위해서 자바스크립트의 date 객체를 이용할 예정이다.
date 객체는 세계표준시(UTC) 1970년 1월 1일 00시 00분 00초를 기준으로 현재와 얼마나 시간 차가 얼마나 되는지 밀리초 단위로 나타낸다. 이 시간 차이를 조정하여 원하는 날짜를 표기할 수 있다.
기본적으로 아래와 같이 사용한다.
console.log(new Date()); // 현재 날짜(로컬 기준) 객체 만들기
console.log(new Date(2021, 11, 6); // 지정한 날짜 객체 만들기
console.log(new Date('2021-12-06T03:24:00'); // 지정한 날짜 객체 만들기
한국 시간 기준으로 날짜 표기하기
기본적으로 date 객체는 로컬의 시간대를 이용해 현재 날짜를 출력한다. 컴퓨터의 시간대를 다르게 설정한 후 date 객체를 출력해보면 각자 다른 시간을 출력한다.
Mon Dec 06 2021 14:00:23 GMT+0900 (한국 표준시)
Mon Dec 06 2021 15:30:23 GMT+1030 (호주 중부 하계 표준시)
Mon Dec 06 2021 15:00:23 GMT+1000 (블라디보스토크 표준시)
전 세계에서 동일하게 출력하고 싶다면, getTimezoneOffset()
메서드를 이용해 UTC와 현재 로컬 시간의 차이를 계산하여 UTC 기준 시를 구하고 여기에 UTC와 KST의 차이를 더해주어 한국 기준으로 시간을 표기할 수 있도록 한다.
사실 getTime()
으로 가져오는 밀리세컨드는 이미 UTC 기준이다. 다만 표기할 때 사용하는 메서드들은 로컬 기준으로 출력하기 때문에 타임존에 관계없이 동일한 시각을 표기하기 위해 실제 데이터를 변경하여 보여주는 것이다.
var date = new Date(); // 현재 날짜(로컬 기준) 가져오기
var utc = date.getTime() + (date.getTimezoneOffset() * 60 * 1000); // utc 표준시 도출
var kstGap = 9 * 60 * 60 * 1000; // 한국 kst 기준시간 더하기
var today = new Date(utc + kstGap); // 한국 시간으로 date 객체 만들기(오늘)
2. 달력 날짜 계산하기
달력 렌더링을 위해 아래의 정보가 필요하다.
- 지난달 마지막 날의 날짜와 요일
- 이번 달의 마지막 날의 날짜와 요일
시작일은 어차피 1일부터이므로 시작 날짜는 필요 없지만, 마지막 날 날짜는 매달 다르므로 따로 가져와야 한다. 또한 달력에 요일도 표시해야 하므로 첫날과 마지막 날의 요일도 가져오기로 한다.
getMonth()
현재 date 객체의 월을 0~11 사이의 숫자로 반환한다.
getDate()
현재 date객체의 날짜를 1~31 사이의 숫자로 반환한다.
// 이전 달의 마지막 날 날짜와 요일 구하기
var startDay = new Date(currentYear, currentMonth, 0);
var prevDate = startDay.getDate();
var prevDay = startDay.getDay();
// 이번 달의 마지막날 날짜와 요일 구하기
var endDay = new Date(currentYear, currentMonth + 1, 0);
var nextDate = endDay.getDate();
var nextDay = endDay.getDay();
// console.log(prevDate, prevDay, nextDate, nextDay);
재밌는 건 새로운 date객체를 만들 때 날짜를 0으로 지정하면 저번 달의 마지막 날짜를 가진 date 객체가 반환된다. month는 0부터 시작하고 date는 1부터 시작하는 이유가 이것일까?
3. 달력 렌더링
// 렌더링 html 요소 생성
calendar = document.querySelector('.dates')
calendar.innerHTML = '';
지난달 렌더링
// 지난달
for (var i = prevDate - prevDay + 1; i <= prevDate; i++) {
calendar.innerHTML = calendar.innerHTML + '<div class="day prev disable">' + i + '</div>'
}
만약 이번 달 1일이 수요일부터 시작했다면 지난달의 월요일, 화요일 이 2개가 렌더링 되어야 한다.
getDay()
로 계산한 prevDay는 일요일 기준이므로 +1을 해서 월요일부터 시작하도록 맞춰준다.
저번 달의 마지막 날짜에 도달하면 루프를 멈춘다.
이번 달 렌더링
// 이번달
for (var i = 1; i <= nextDate; i++) {
calendar.innerHTML = calendar.innerHTML + '<div class="day current">' + i + '</div>'
}
1부터 이번 달의 마지막 날까지 렌더링.
current와 disable 클래스를 통해 이번달 날짜를 따로 구분하기로 했다.
다음 달 렌더링
// 다음달
for (var i = 1; i <= (7 - nextDay == 7 ? 0 : 7 - nextDay); i++) {
calendar.innerHTML = calendar.innerHTML + '<div class="day next disable">' + i + '</div>'
}
만약 이번 달의 마지막 날의 요일이 금요일이라면 nextDay
는 5를 반환한다. 이때 렌더링 해야 하는 날짜의 개수는 토요일과 일요일을 2개, 7-5이다.
만약 nextDay
가 0이라면(마지막 날이 일요일) 7-0으로 7개가 렌더링 된다. 그러나 의미없는 1줄이 출력할 필요가 없으므로 마지막 날짜가 일요일인 경우만 따로 분기해 3항 연산자를 활용해 0으로 고정한다.
4. 기능 추가하기
현재 월 표기하기
currentYear = thisMonth.getFullYear();
currentMonth = thisMonth.getMonth();
currentDate = thisMonth.getDate();
// ...중략...
// 현재 월 표기
$('.year-month').text(currentYear + '.' + (currentMonth + 1));
getMonth()
메서드로 가져온 값은 0부터 시작하므로 +1을 해 준다.
오늘 날짜 표시하기
// 오늘 날짜 표기
if (today.getMonth() == currentMonth) {
todayDate = today.getDate();
var currentMonthDate = document.querySelectorAll('.dates .current');
currentMonthDate[todayDate -1].classList.add('today');
}
오늘 날짜와 달력의 현재 표시 월 구분하기 위해 thisMonth
라는 이름의 date객체와 today
객체를 따로 분리해서 사용하고 있다.
이전달 & 다음 달 이동
// 이전달로 이동
$('.go-prev').on('click', function() {
thisMonth = new Date(currentYear, currentMonth - 1, 1);
renderCalender(thisMonth);
});
// 다음달로 이동
$('.go-next').on('click', function() {
thisMonth = new Date(currentYear, currentMonth + 1, 1);
renderCalender(thisMonth);
});
버튼을 만들고 누를 때마다 thisMonth
값을 바꿔서 달력을 다시 렌더링 하도록 했다.
나름 풀어서 써 보려고 했는데, 더 어려운 것 같기도 하다.
실제 전체 코드는 다음과 같다.
See the Pen JQuery Calendar by ylem76 (@ylem76) on CodePen.
참고자료
date 객체 :
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Date
달력 렌더링 :
https://jerryjerryjerry.tistory.com/26
https://codepen.io/andyydna/pen/VwYRVQE?editors=0010
한국 기준 시로 표기하기 :
https://hianna.tistory.com/451
https://meetup.toast.com/posts/130
https://stackoverflow.com/questions/9756120/how-do-i-get-a-utc-timestamp-in-javascript