Intl 개체는 ECMAScript 국제화 API의 네임스페이스로, 언어 구분 문자열 비교, 숫자 형식, 날짜 및 시간 형식을 제공합니다.
출처: [MDN] Intl
Intl API를 사용하면 각 나라의 언어와 표현에 맞게 날짜 혹은 시간 등을 표시해줄 수 있다.
RelativeTimeFormat
를 이용하면 각 나라의 언어에 맞게 N일 전
N days age
이렇게 시간을 나타낼 수 있다.
// 인스턴스 생성할 때 언어 설정
const formatter = new Intl.RelativeTimeFormat('ko');
// 오늘과 1년 전 날짜의 차이를 구한다.
// month는 index로 설정해야해서 12월 달의 index인 11을 넣어줘야한다.
const passed = new Date() - new Date(2021, 11, 16);
// passed를 하루 단위로 나눔
const passedForDay = Math.floor(passed / (1000 * 60 * 60 * 24));
const diff = formatter.format(
-passedForDay, // 음수는 지난 날짜, 양수는 남은 날짜로 표현한다.
'day', // 포맷을 'day'로 설정한다.
);
console.log(diff); // 365일 전
지금과 1년 전의 날짜 차이를 콘솔에 한국어로 출력하도록 했다.
// 언어를 영어로 설정
const formatter = new Intl.RelativeTimeFormat('en-US'); // 365 days ago
// 날짜를 양수로 설정
const diff = formatter.format(passedForDay, 'day'); // 365일 후
이렇게 간단하게 옵션을 변경해보면서 출력되는 결과를 확인해볼 수 있다.
라이브러리를 사용하지 않고 RelativeTimeFormat
를 사용해서 지나간 날짜를 똑똑하게 나타내는 함수를 만들어보자!
참고로 날짜 관련된 라이브러리는 Moment.js
Day.js
등이 있으며 Moment.js
는 더 이상 업데이트가 이루어지지 않을 것이라고 한다.
const generateTimeString = (time, lang = 'ko') => {
const formatter = new Intl.RelativeTimeFormat(lang, {
numeric: 'always',
});
const passed = new Date() - new Date(time);
}
generateTimeString
함수는 시간과 언어를 파라미터로 받는다. 언어는 한국어를 기본 값으로 설정했다.
nemeric
옵션은 날짜 형식을 어떻게 표현할지 설정할 수 있다.
nemeric 옵션 설정에 따른 결과
auto
: 어제
, 그저께
always
: 1일 전
, 2일 전
시간을 어떻게 표현할지 형식을 정해서 해당 구간에 맞는 결과를 줘야한다.
구간 | 표현 |
---|---|
1분 미만 | s 초 전 |
1분 이상 ~ 1시간 미만 | m 분 전 |
1시간 이상 ~ 1일 미만 | h 시간 전 |
1일 이상 ~ 1달 미만 | d 일 전 |
1달 이상 | yyyy 년 mm 월 dd 일 |
한 달의 기준이 29일, 30일, 31일 이렇게 다양하니, 한 달이 지나가면 연월일로 표시하도록 했다.
시간 표현 형식에 맞게 날짜를 표현하려면 각 시간의 단위를 체크해야 한다.
JavaScript는 시간의 단위가 millisecond
인 점을 유의해야 한다.
시간 | millisecond로 계산 | 결과 |
---|---|---|
1초 | 1000 | 1000 |
1분 | 1000 * 60 | 60000 |
1시간 | 1000 * 60 * 60 | 3600000 |
1일 | 1000 * 60 * 60 * 24 | 86400000 |
우선 1달은 30이라고 가정했으며, 구간의 조건을 파악해보자.
구간 | 표현 | 조건1 | 조건2 |
---|---|---|---|
1분 미만 | s 초 전 | 60000(1분) 미만 | - |
1분 이상 ~ 1시간 미만 | m 분 전 | 60000(1분) 이상 | 3600000(1시간) 미만 |
1시간 이상 ~ 1일 미만 | h 시간 전 | 3600000(1시간) 이상 | 86400000(1일) 미만 |
1일 이상 ~ 1달 미만 | d 일 전 | 86400000(1일) 이상 | 2592000000(1달) 미만 |
1달 이상 | yyyy 년 mm 월 dd 일 | 2592000000(1달) 이상 | - |
시간 단위를 체크하기 위해 객체를 만들고, 객체 안에 함수를 선언했다.
const checkTime = {
isSecond: (time) => time < 60000,
isMinute: (time) => 60000 <= time && time < 3600000,
isHour: (time) => 3600000 <= time && time < 86400000,
isDay: (time) => 86400000 <= time && time < 2592000000,
isOverOneMonth: (time) => 2592000000 <= time,
};
그리고 각 조건을 체크해서 각 시간대에 맞는 문자열을 return 해도록 했다.
const generateTimeString = (time, lang = 'ko') => {
const formatter = new Intl.RelativeTimeFormat(lang, {
numeric: 'always',
});
const passed = new Date() - new Date(time);
// 조건 추가
if (checkTime.isSecond(passed)) {
return '1분 미만';
}
if (checkTime.isMinute(passed)) {
return '1시간 미만';
}
if (checkTime.isHour(passed)) {
return '1일 미만';
}
if (checkTime.isDay(passed)) {
return '1달 미만';
}
if (checkTime.isOverOneMonth(passed)) {
return '1달 이상';
}
};
const second = new Date();
second.setSeconds(second.getSeconds() - 1);
console.log(generateTimeString(second)); // 1분 미만
const minute = new Date();
minute.setMinutes(minute.getMinutes() - 1);
console.log(generateTimeString(minute)); // 1시간 미만
const hour = new Date();
hour.setHours(hour.getHours() - 1);
console.log(generateTimeString(hour)); // 1일 미만
const yesterday = new Date();
yesterday.setHours(yesterday.getHours() - 24);
console.log(generateTimeString(yesterday)); // 1달 미만
const dayBeforYesterday = new Date();
dayBeforYesterday.setHours(dayBeforYesterday.getHours() - 48);
console.log(generateTimeString(dayBeforYesterday)); // 1달 미만
const month = new Date();
month.setMonth(month.getMonth() - 1);
console.log(generateTimeString(month)); // 1달 이상
이제는 시간대에 맞게 계산을 해줘야한다.
시간 차이가 1초대인데, 1시간 단위로 시간을 계산해서 출력하면 안되기 때문이다.
이번에도 객체를 선언하고, 객체 안에 시간단위에 맞게 계산해주는 함수들을 선언했다.
const calcTime = {
second: (time) => Math.floor(time / 1000),
minute: (time) => Math.floor(time / 60000),
hour: (time) => Math.floor(time / 3600000),
day: (time) => Math.floor(time / 86400000),
};
이제 각 단위에 맞게 시간을 계산한 결과를 return 해주면 끝이다!
const generateTimeString = (time, lang = 'ko') => {
const formatter = new Intl.RelativeTimeFormat(lang, {
numeric: 'always',
});
const passed = new Date() - new Date(time);
if (checkTime.isSecond(passed)) {
// 초 단위
return formatter.format(-calcTime.second(passed), 'second');
}
if (checkTime.isMinute(passed)) {
// 분 단위
return formatter.format(-calcTime.minute(passed), 'minute');
}
if (checkTime.isHour(passed)) {
// 시간 단위
return formatter.format(-calcTime.hour(passed), 'hour');
}
if (checkTime.isDay(passed)) {
// 일 단위
return formatter.format(-calcTime.day(passed), 'day');
}
if (checkTime.isOverOneMonth(passed)) {
// yyyy년 mm월 dd일
return new Intl.DateTimeFormat(lang, {
year: 'numeric',
month: 'short',
day: 'numeric',
}).format(new Date(time));
}
};
테스트 해보기에 있는 코드를 실행시켜보자!
1초 전
1분 전
1시간 전
1일 전
2일 전
2022년 11월 16일
콘솔 출력 결과다. 의도한 대로 시간대에 맞게 잘 출력해주고 있다.
const formatter = new Intl.RelativeTimeFormat(lang, {
numeric: 'auto',
});
numeric
을 auto
로 바꿔보고 다시 실행해보자.
1초 전
1분 전
1시간 전
어제
그저께
2022년 11월 16일
1일 전을 어제
, 2일 전을 그저께
로 표현해주고 있다.