2023년을 얼마 안남긴 11월 즈음, 올해 마지막 목표로 백준 골드티어 찍어보기를 도전하였다.
그래서 자투리 시간이 있을 때마다 백준 문제를 풀곤 했다. (2024년 새해 목표로 넘겨야겠다)
이번 문제는 '이번 해가 몇%지났는지 출력하는 프로그램을 작성하시오' 가 주 목표인 문제였다.
( https://www.acmicpc.net/problem/1340 )
1340번: 연도 진행바
평년일 때, 각 달은 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31일이 있다. 윤년에는 2월이 29일이다. 윤년은 그 해가 400으로 나누어 떨어지는 해 이거나, 4로 나누어 떨어지면서, 100으로 나누어 떨어지지
www.acmicpc.net
쉬운 난이도의 문제였고, 내 코드는 다음과 같았다.
const input = `May 10, 1981 00:31`
const monthArr = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'];
const monthDay = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
let inputData = input.split(" ");
//월에 따라 분을 반환해주는 함수
const monthMin = (month, year) => {
let idx = monthArr.indexOf(month);
let monthDaySum = 0;
for (let i = 0; i < idx; i++) {
monthDaySum += monthDay[i];
}
if (isYun(Number(year)) && idx > 1) monthDaySum += 1;
return monthDaySum * 24 * 60;
};
//받은 일과 시, 분으로 분을 반환해주는 함수
const sumMin = (day, hm) => {
let result = 0;
result += Number((day.slice(0, -1)) - 1) * 24 * 60;
let temp = hm.split(':').map(e => Number(e));
result += Number(temp[0]) * 60;
result += Number(temp[1]);
return result;
};
//윤달 판별
const isYun = year => {
return year % 400 == 0 || (year % 4 == 0 && year % 100 != 0);
};
const sol = inputData => {
let result = monthMin(inputData[0], inputData[2]) + sumMin(inputData[1], inputData[3]);
let yearMin = 365 * 24 * 60;
if (isYun(Number(inputData[2]))) yearMin += 24 * 60;
console.log((result / yearMin) * 100);
};
sol(inputData);
입력받은 날의 %를 입력받은 해가 윤달인지 아닌지에 따라 반환하여 정답을 구하는 코드를 이런식으로 구현하였다. 그런데 문제를 마치고 문득 JavaScript의 Date 객체를 이용하여 날짜 및 시간을 조작하는게 더 간결한 답이 될 것이라고 생각이 들었다. Chat GPT에게 문제를 설명하고 코드를 요구했다.
그리고 다음과 같은 코드를 제시받았다.
const input = `May 10, 1981 00:31`
const parseDate = (input) => {
const [datePart, timePart] = input.split(' '); // 날짜와 시간을 분리합니다.
const [month, day, year] = datePart.split(' '); // 날짜를 구성하는 부분을 분리합니다.
return new Date(`${month} ${day}, ${year} ${timePart}`); // Date 객체 생성
};
const calculatePercentage = (date) => {
const startOfYear = new Date(date.getFullYear(), 0, 1);
const endOfYear = new Date(date.getFullYear() + 1, 0, 1);
const yearDuration = endOfYear - startOfYear;
const elapsed = date - startOfYear;
return (elapsed / yearDuration) * 100;
};
const date = parseDate(input);
console.log(calculatePercentage(date).toFixed(9));
역시나 Date객체를 이용하여 내가 짠 코드보다 간결하고 가독성 있게 풀어낸 걸로 보인다.
그래서 이참에 JS Date객체에 대해 정리해 보려고 한다.
그 전에 JS의 Date객체에는 일부 비판적인 의견이 있는데 그 이유는 다음과 같다.
- 달의 인덱싱: JavaScript에서 월(month)은 0부터 시작한다. 즉, 1월은 0, 2월은 1로 표현된다. 이는 다른 많은 프로그래밍 언어와 달리 직관적이지 않고 혼동을 일으킬 수 있다.
- 타임존 처리의 복잡성: Date 객체는 기본적으로 로컬 타임존을 사용한다. 이로 인해 다른 타임존을 처리할 때 복잡성이 증가하고, UTC 시간과의 변환도 추가적인 작업을 요구한다.
- 윤년과 윤초 처리: JavaScript의 Date 객체는 윤년이나 윤초와 같은 복잡한 날짜 관련 처리를 완벽하게 지원하지 않아 특정 날짜 계산에서 오류를 발생시킬 수 있다.
이밖에도 몇가지 이유가 있어서 실무에서 나는 보통 Moment.js를 이용한다. 하지만 JS에서 제공하는 객체인 만큼 기본적인 부분들은 알아놓는게 맞다고 생각한다.
Date 객체 생성
- new Date(): 현재 날짜와 시간으로 Date 객체를 생성한다.
- new Date(year, month, day, hours, minutes, seconds, milliseconds): 지정된 날짜와 시간으로 Date 객체를 생성. 월은 0부터 시작한다 (0 = 1월, 1 = 2월, ...).
let now = new Date(); let specificDate = new Date(2020, 0, 1, 15, 30, 0); // 2020년 1월 1일 15
날짜 정보 가져오기
- getDate(): 월의 일자를 반환 (1 ~ 31).
- getMonth(): 월을 반환 (0 ~ 11).
- getFullYear(): 연도를 반환.
- getDay(): 요일을 반환 (0 = 일요일, 1 = 월요일, ...).
- getHours(), getMinutes(), getSeconds(), getMilliseconds(): 각각 시, 분, 초, 밀리초를 반환.
let today = new Date();
console.log(`Year: ${today.getFullYear()}, Month: ${today.getMonth() + 1}, Day: ${today.getDate()}`);
//출력 예시 : Year: 2023, Month: 12, Day: 31
날짜 정보 설정하기
- setDate(day): 월의 일자를 설정.
- setMonth(month): 월을 설정.
- setFullYear(year): 연도를 설정.
- setHours(hours), setMinutes(minutes), setSeconds(seconds), setMilliseconds(milliseconds): 각각 시, 분, 초, 밀리초를 설정.
let date = new Date();
date.setFullYear(2023); // 2023년
date.setMonth(11); // 12월
date.setDate(25); // 25일
참고 : getYear()말고 getFullYear()를 사용하기
여러 자바스크립트 엔진이 더는 사용되지 않는(deprecated) 비표준 메서드 getYear()을 구현하고 있습니다. 이 메서드는 두 자릿수 연도를 반환하는 경우가 있기 때문에 절대 사용해선 안 됩니다. 연도 정보를 얻고 싶다면 getFullYear()를 사용하세요.
(https://ko.javascript.info/date 에서 참고하였습니다)
타임스탬프 및 기타 메서드
- getTime(): 1970년 1월 1일 00:00:00 UTC부터 경과된 밀리초를 반환.
- setTime(milliseconds): 특정 타임스탬프로 날짜를 설정.
- toDateString(), toTimeString(): 각각 날짜와 시간을 문자열로 반환.
let date = new Date();
date.setTime(0); // 1970년 1월 1일 00:00:00 UTC
console.log(date.toDateString()); // Thu Jan 01 1970
문자열 날짜 형식
Date.parse는 다음과 같은 형식의 문자열을 인식한다
- "YYYY-MM-DD" (예: "2023-12-25")
- "YYYY-MM-DDTHH:mm:ss.sssZ" (ISO 8601 형식, 예: "2023-12-25T12:00:00.000Z")
- "Month DD, YYYY" (예: "December 25, 2023")
- 기타 여러 형식 (브라우저 및 엔진에 따라 다름)
let timestamp = Date.parse("2023-12-25T00:00:00Z");
console.log(timestamp); // 출력: 1671926400000 (예시 값)
let dateFromTimestamp = new Date(timestamp);
console.log(dateFromTimestamp); // 출력: Sun Dec 25 2023 00:00:00 GMT+0000 (UTC) (예시 값)
let dateString1 = "2023-12-25";
let date1 = new Date(Date.parse(dateString1));
console.log(date1); // 출력: Mon Dec 25 2023 00:00:00 GMT+0000 (UTC) (예시 값)
let dateString2 = "December 25, 2023 15:30:00";
let date2 = new Date(Date.parse(dateString2));
console.log(date2); // 출력: Mon Dec 25 2023 15:30:00 GMT+0000 (UTC) (예시 값)
자동 고침(autocorrection)
개발자가 일부 날짜 구성 요소에 잘못된 값을 지정했을 때 자동으로 수정해 주는 기능이다.
이 기능으로 인하여 범위를 벗어나는 값들을 적절하게 조정하여 유효한 날짜로 변환해준다.
// 2월에는 보통 28일 또는 29일까지 있음
let date = new Date(2023, 1, 30);
console.log(date); // 출력: March 2, 2023 (2월 30일은 없으므로 3월 2일로 자동 조정)
// 시간이 24시를 넘어감
let time = new Date(2023, 11, 31, 25, 0, 0);
console.log(time); // 출력: January 1, 2024 01:00:00 (25시간은 다음 날로 자동 조정)
글을 마무리하며
사실 Chat GPT가 제시한 코드에는 문제가 있어보였다. 그래서 수정된 코드를 요구하였다.
몇가지 수정을 거친 후 Date객체를 이용한 Chat GPT의 코드와 숫자,문자열 파싱을 이용한 내 작성한 코드와의 성능의 차이를 비교해보고 싶어서 Chat GPT가 제시한 코드를 제출해 보았다. 그리고 그 결과는
'JS' 카테고리의 다른 글
브라우저 간 호환성 문제 (0) | 2024.05.09 |
---|---|
네이버 뉴스 크롤링 해보기 (Node.js) + 생성형AI(Gemini)로 글 다듬기 (0) | 2024.04.16 |