javascript Date() 현재 날짜, 오늘, 어제, 전월 말일 날짜 계산과 출력 포매팅

자바스크립트에서 날짜를 처리하는 객체인 Date객체를 이용해서 다양한 형태의 날짜 문자열을 출력하고, 오늘 날짜, 어제, 내일, 지난달 말일과 같은 자주 쓰는 날짜로 빠르게 변경하는 방법을 소개합니다.

자바스크립트에서 날짜를 처리하는 객체는 Date객체입니다. Date 객체를 통해 모든 날짜 표현을 하고, 특정 날짜로 변경하거나, 날짜를 문자열로 표현하는 포매팅을 하게 됩니다.

Date 객체 생성

Date 객체 생성은 객체 생성자로 하게 됩니다. 다음처럼 선언을 하면 변수 d에 Date 객체가 할당됩니다.

let d = new Date();

생성한 객체 내부에는 1970년 1월 1일 0시를 시작으로 계산된 밀리세컨드 단위의 정수값을 가지고 있습니다. 이 값을 기준으로 경과한 시간만큼을 계산해서 실제로 우리가 보게되는 날짜 포맷으로 된 출력 내용이 정해지게 됩니다.

Date() 생성자로 객체를 생성할 때 인자 값으로 원하는 날짜를 지정할 수 있습니다.

new Date('2024-06-25') 로 생성자에 날짜 문자열을 넣으면 해당 날짜를 가리키는 있는 Date 객체가 만들어집니다. 인자값 문자열은 시간 표시가 생략된 것으로 정확하게는 로케일 시간인 "2024-06-25 09:00:000"이 됩니다.

로케일(대한민국) 시간으로 자정을 Date 객체의 현재 시각으로 설정하려면 new Date('2024-06-25 00:00:00.000')처럼 명시적으로 시간까지 표시를 해야 합니다.

"new Date(null)"로 객체를 생성하면 생성된 Date 객체가 가리키는 시각은 1970-01-01 00:00:00 이 됩니다. 자바스크립트의 Date 객체의 기본 설정이 현재 로케일(지역) 설정 시각이 되므로 실제 시간을 출력하면 1970-01-01 09:00:00으로 표시됩니다.

날짜를 Y-M-D H:M:S 순서로 출력

생성한 Date 객체를 문자열로 출력하려면 toString() 함수로 변환해야 합니다.

Date 객체의 시각을 문자열로 콘솔에 출력하면 다음과 같이 표시됩니다. 실제로는 객체 자체를 콘솔 출력 인자로 넣어도 되지만(console.log(d)) javascript 이건 어디까지만 console.log가 Date 객체의 값을 변환 처리해주기 때문에 그런 것이고 실제로 코딩을 할 때는 toString()과 같은 함수를 사용해서 변환해서 사용해야 합니다.

let d = new Date();
console.log(d.toString())
-----------------------------
> Wed Jun 05 2024 15:35:02 GMT+0900 (한국 표준시)

콘솔 출력 내용을 보면 알겠지만 우리가 일반적으로 사용하는 날짜/시간 표현과는 전혀 다른 영어권 날짜/시간으로 표시됩니다.

Date 객체에는 "년월일시분초" 순서로 표현을 하는 문화권을 위한 내장 함수가 미리 마련되어 있습니다. toLocaleString() 함수를 사용하면 우리가 사용하는 시간 표시 순서로 된 문자열이 출력됩니다.

let d = new Date();
console.log(d.toLocaleString())
-----------------------------
> 2024. 5. 31. 오후 11:47:51

출력 결과를 보면 "오전/오후"로 구분되는 12시간 표시 방식을 사용합니다. toLocaleString() 함수에 옵션 인자를 넣으면 24시간 표시로 출력을 변경할 수 있습니다.

let d = new Date();
var options = { hour12: false };
console.log(d.toLocaleString('ko-KR',options))
-----------------------------
> 2024. 5. 31. 23시 50분 7초

toLocaleString() 함수를 사용하면 가독성이 좋은 출력 문자열을 만들지만 문자열 길기가 가변이 되면서 개발용으로 사용하기에는 부적합하게 됩니다.

앞서의 날짜 문자열 출력은 년월일 표시부분이 날짜 뒤 마침표까지 12자리지만 10월이 되면 13자리로 바뀌게 됩니다. 시분초 표현도 마찬가지로 길이가 가변이 되면서 길이에 따른 보정을 해야하는 불편함이 생기게 됩니다.

대부분의 개발 환경에서 원하는 것은 "2024-06-12 23:08:12" 처럼 길이가 고정된 문자열 표현이고 년월일 구분자가 "-"인 형태입니다.

정확하게 이 포맷으로 출력 문자열을 만들어주는 Date 객체의 내장 함수인 toISOString() 이 있습니다.

let d = new Date();
console.log(d.toISOString())
-----------------------------
> 2024-06-05T14:59:05.152Z

단, 이 함수는 UTC/GMT 시간 값을 문자열로 반환합니다. 우리나라의 시간보다 9시간 느린 시간이 됩니다.

toISOString() 함수가 반환하는 UTC/GMT 시간에 대해서 간단하게 알아보겠습니다.

UTC/GMT 시간 얻기

세계 협정시는 위도 0도를 기준으로하는 기준 시각으로 기준 시각에 오프셋을 더 하거나 빼서 로케일(지역) 시간으로 사용하는 전세계 표준 시간 표현 방법입니다. GMT로 표현하기도 합니다.

우리나라는 9시간이 더 빨라서 UTC+9시간이 됩니다. 우리나라가 오후 10시면 UTC 시간은 오후 1시가 됩니다.

Date 객체에서 얻는 현재 시간은 UTC+9시간입니다. UTC 표준시간을 얻으려면 날짜 객체의 내장 함수인 toUTCString(), 또는 toISOString() 함수를 사용합니다. 같은 UTC 시간을 출력하며, 출력하는 문자열의 포맷만 다릅니다.

toUTCString()은 RFC 7231 포맷 문자열을 toISOString은 ISO 8601 포맷 문자열을 반환합니다.

UTC 시간을 우리가 사용하는 YYYY-MM-DD 포맷으로 출력하려면 다음처럼 Date 객체를 사용해 생성할 수 있습니다.

let d = new Date();
console.log(d.toISOString())
console.log(d.toUTCString())
-----------------------------
2024-06-05T15:05:29.625Z
Wed, 05 Jun 2024 15:05:29 GMT

toISOString()을 이용해서 우리나라 시간으로 포매팅 하는 방법은 뒤에서 설명하고, 커스텀 출력 문자열을 만드는 함수를 구현해서 "YYYY-MM-DD"처럼 우리가 원하는 출력문을 만들어보겠습니다.

원하는 포맷으로 커스텀 날짜 표현 구현하기

toISOString() 함수를 사용하면 우리가 주로 사용하는 "YYYY-MM-DD" 10자리 문자열을 쉽게 얻을 수 있습니다. 다만 UTC 시간이기 때문에 시간 보정을 하거나 우리가 원하는 출력 문자열을 생성하는 함수를 만들어야 합니다.

내장 함수가 출력하는 기본 포맷이 아닌 다른 포맷으로 임의의 날짜 표현을 하려면 다음처럼 Date 객체에서 년, 월, 일 값을 각각 얻어서 원하는 포맷으로 문자열을 만들 수 있습니다.

간단하게 formatDate() 함수를 하나 만들어서 구현해 보겠습니다. 연결자와 순서를 바꾸면 원하는 포맷으로 된 날짜 문자열을 얻는 함수를 만들 수 있습니다.

function formatDate(){
    let d = new Date();
    return d.getFullYear() + '-' + (d.getMonth()+1).toString().padStart(2,'0') + '-' + d.getDate().toString().padStart(2,'0');
}
console.log(formatDate())
-----------------------------
> 2024-06-05

padStart()가 지원되지 않는 레거시 환경에서는 ('0' + (today.getMonth() + 1)).slice(-2) 처럼 왼쪽에 '0'을 붙인 후, 오른쪽에서 2글자를 자르는 방식으로 구현할 수도 있습니다.

"시:분:초" 커스텀 문자열 또한 앞서와 같은 방식으로 문자열을 생성할 수 있습니다.

function formatTime(){
    let d = new Date();
    return d.getHours().toString().padStart(2,'0') + ':' + d.getMinutes().toString().padStart(2,'0') + ':' + d.getSeconds().toString().padStart(2,'0');
}
console.log(formatTime())
-----------------------------
> 20:16:04

두 함수의 출력 기능을 조합하면 "YYYY-MM-DD HH:MM:SS" 출력 문자열을 만들 수 있습니다.

로케일 시간을 UTC/GMT 시간으로 변경하기

평소에는 UTC 시간으로 변경할 일이 없겠지만, " YYYY-MM-DD HH:MM:SS"로 포매팅한 문자열을 얻기 위해 toISOString()이 반환하는 문자열을 우리나라 현재 시간으로 출력되도록 시간을 보정해야 할 필요가 있습니다.

getTimezoneOffset() 함수는 현재 로케일 시간과 UTC 시간 사이의 차이를 "분"으로 출력하는 함수입니다. 우리나라는 UCT 시간보다 9시간 빠르므로 -540이 반환됩니다.(UCT-우리나라)

다음 날짜 변환 식이 반환하는 최종 Date 객체인 d에 저장되는 시간은 UTC 시간이 됩니다.

let d = new Date();
d = new Date(d.getTime() + (d.getTimezoneOffset() * 60 * 1000));

국내 환경만 고려해도 된다면 편하게 540 * 60 * 1000처럼 상수를 정의해서 사용해도 됩니다.

toISOString()으로 시간 문자열 포매팅

앞서 UTC 시간을 구하는 방법과 반대로 9시간을 현재 로케일 시간에서 더하면 toISOString() 함수에서 9시간을 빼고 계산하기 때문에 현재 우리나라 현재 시간이 " YYYY-MM-DDTHH:MM:SSZ"로 포매팅되어 출력됩니다.

let d = new Date();
console.log(d.toISOString());
d = new Date(d.getTime() - (d.getTimezoneOffset() * 60 * 1000));
console.log(d.toISOString());
-----------------------------
2024-06-05T15:20:12.364Z // UTC 시간
2024-06-06T00:20:12.364Z // 우리나라 시간 UTC+9

앞서처럼 함수를 구현해서 복잡하게 구현하는 방식보다 훨씬 간결하고 이해하기가 쉬워집니다.

출력 문자열의 앞부분 10자리 "년-월-일 " 문자열을 구하고 싶으면 다음처럼 split() 함수를 사용합니다.

let d = new Date();
d = new Date(d.getTime() - (d.getTimezoneOffset() * 60 * 1000));
console.log(d.toISOString().split('T')[0]) // 'T'로 나눠서 만들어진 배열의 첫 번째 요소
-----------------------------
> 2024-06-05

10자리 년-월-일 문자열만 필요하면 다음 처럼 조금 더 짧은 한줄 코드로 구현해서 사용하는 방법도 있습니다.

const today10 = new Date(d.getTime() - (d.getTimezoneOffset() * 60 * 1000)).toISOString().substring(0,10)
-----------------------------
> 2024-06-05

"YYYY-MM-DD HH:MM:SS" 포맷으로 출력하려면 toISOString()에서 "T", "Z" 문자를 제거해야 합니다. 다음처럼 간결하게 생성할 수 있습니다.

let d = new Date();
d = new Date(d.getTime() - (d.getTimezoneOffset() * 60 * 1000));
d.toISOString().replace(/[A-Z]/g, ' ').trim()
-----------------------------
> 2024-06-05 20:05:55.324

밀리세컨드 단위는 표시하지 않는게 일반적이므로 함수 체인을 조금 바꿔서 밀리세컨드 단위 표시는 잘라서 버립니다.

d.toISOString().replace(/[A-Z]/g, ' ').split('.')[0]
-----------------------------
> 2024-06-05 20:05:55

현재 시각의 밀리세컨드 정수값을 얻는 now()

Date 객체에는 Date 객체를 생성자로 생성하지 않고 사용할 수 있는 정적 함수가 구현되어 있습니다. 그중에서 내장 함수 now()는 현재 시각의 밀리세컨드 정수 값을 반환합니다.

날짜 연산을 할 때 자주 사용하는 함수입니다.

console.log(Date.now());
-----------------------------
> 1717572723261

new 생성자로 생성한 객체에서는 내장 함수인 getTime() 함수로 Date.now()와 같은 정수값 출력을 얻을 수 있습니다.

let d = new Date();
console.log(d.getTime());
console.log(Date.now());
-----------------------------
> 1717585911199
> 1717585911209

요일 문자열 얻기

Date 객체에서 요일을 얻는 함수는 getDay() 입니다. 단, 함수가 반환하는 값이 0~6까지의 숫자 표현이며, 일요일부터 시작하고 일요일이 0이 됩니다. 요일을 한글 문자열로 표현하려면 다음처럼 요일 문자열을 사용해서 얻을 수 있습니다.

'일월화수목금토'.charAt(d.getDay()+'요일')
-----------------------------
> 수요일

영문일 경우 표현의 한계 때문에 배열로 요일 문자열을 만들어서 인덱스로 접근해야 하지만, 한글의 경우 공통이 아닌 문자를 한 글자로 구분할 수 있어 구현할 때 편리한 점이 있습니다.

어제 날짜, 내일 날짜, 전월 말일로 변경하기

어제 날짜로 날짜 객체의 시간을 변경하는 것은 생각보다 단순합니다.

Date 객체의 setDate() 함수를 사용하면 날짜를 변경할 수 있습니다. 인자 값으로 넣는 정수 값은 Date 객체의 현재 날짜에서 +/-를 하는 상대 날짜가 아니고 절대 날짜라는 점을 주의해야 합니다.

setDate(5)는 현재 월의 5일로 설정됩니다.

그리고 setDate() 함수로 날짜를 변경하면 Date 객체의 날짜가 변경되고, 리턴 값으로 변경된 날짜의 밀리세컨드 값을 반환합니다.

따라서 변경된 Date 객체를 사용할지, 반환받은 값을 다시 날짜 객체로 변경해서 사용할지 구분해야 합니다.

let d = new Date()
console.log(d.setDate(d.getDate()-1))
console.log(d)
-----------------------------
1717511092925 //setDate() 함수의 반환값
test1.js:46 Tue Jun 04 2024 23:24:52 GMT+0900 (한국 표준시) // 어제 날짜로 변경된 Date객체의 날짜

setDate() 함수의 인자 값으로 음수, 또는 월의 최대일인 31보다 큰 값을 넣을 수 있습니다. 1보다 작으면 전월 말일 부터 하루씩 뒤로 가며, 현재 월의 말일보다 크면 익월 1일부터 하루씩 앞으로 이동합니다.

Date 객체의 현재 날짜가 1일이면, 앞서의 d.getDate()-1 값은 정수 0이 되고 d.setDate(0)과 같습니다. 변경된 날짜는 이달 1일의 전날인 전월 말일이 됩니다. 따라서 오늘 날짜와 상관 없이 setDate(0)을 하면 전월 말일이 됩니다.

let d = new Date()
d.setDate(0)
console.log(d)
-----------------------------
Fri May 31 2024 23:35:12 GMT+0900 (한국 표준시) // 전월 말일

같은 방식으로 내일 날짜는 d.getDate()+1 이 됩니다. 오늘이 말일일 경우 변경된 날짜는 다음 달 1일이 됩니다.

getDate()가 반환하는 밀리세컨드 값을 이용해서 앞서의 두 줄로 구현하는 코드를 다음처럼 한 줄로 구현할 수 있습니다.

let d = new Date(new Date().setDate(0)) // 전월 말일 날짜 객체 반환