Skip to content

Commit

Permalink
feat(utils): getAge, isUnderAge 신규 함수 추가 (#662)
Browse files Browse the repository at this point in the history
* feat(utils): getAge 신규 함수 추가

* feat(utils): isUnderAge 신규 함수 추가
  • Loading branch information
ssi02014 authored Jan 7, 2025
1 parent 6015781 commit c62d822
Show file tree
Hide file tree
Showing 9 changed files with 291 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .changeset/tough-drinks-bathe.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/utils': minor
---

feat(utils): getAge 신규 함수 추가 - @ssi02014
5 changes: 5 additions & 0 deletions .changeset/weak-colts-love.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@modern-kit/utils': minor
---

feat(utils): isUnderAge 신규 함수 추가 - @ssi02014
25 changes: 25 additions & 0 deletions docs/docs/utils/date/getAge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# getAge

주어진 `생년월일`을 기준으로 `현재 나이`를 계산합니다.

<br />

## Code
[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/validator/getAge/index.ts)

## Interface
```ts title="typescript"
function getAge(birthDate: string | number | Date): number
```

## Usage

```ts title="typescript"
import { getAge } from '@modern-kit/utils';
// 현재 날짜가 2025년 1월 1일 00:00:00 일 때
getAge(new Date('2006-01-01')); // 19
// 문자열 포맷도 허용합니다.
getAge('2006-01-01'); // 19
```
52 changes: 52 additions & 0 deletions docs/docs/utils/date/isUnderAge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# isUnderAge

주어진 생년월일을 기준으로 특정 나이보다 어린지 확인합니다.

`inclusive` 값을 기준으로 기준 나이를 포함할지 여부를 결정합니다.

<br />

## Code
[🔗 실제 구현 코드 확인](https://github.com/modern-agile-team/modern-kit/blob/main/packages/utils/src/validator/isUnderAge/index.ts)

## Interface
```ts title="typescript"
interface IsUnderAgeParams {
birthDate: string | number | Date;
targetAge: number;
inclusive?: boolean;
}
```
```ts title="typescript"
function isUnderAge({
birthDate,
targetAge,
inclusive = false,
}: IsUnderAgeParams): boolean;
```

## Usage
### without inclusive
```ts title="typescript"
import { isUnderAge } from '@modern-kit/utils';

// 현재 날짜 2025년 1월 1일 기준
isUnderAge({ birthDate: new Date('2006-01-02'), targetAge: 19 }); // true
isUnderAge({ birthDate: new Date('2006-01-01'), targetAge: 19 }); // false, 정확히 만 19세
isUnderAge({ birthDate: new Date('2005-12-31'), targetAge: 19 }); // false

isUnderAge({ birthDate: '2006-01-02', targetAge: 19 }); // true
isUnderAge({ birthDate: '2006-01-01', targetAge: 19 }); // false, 정확히 만 19세
isUnderAge({ birthDate: '2005-12-31', targetAge: 19 }); // false
```

### with inclusive
- `inclusive` 값을 기준으로 기준 나이를 포함할지 여부를 결정합니다. (기본값: `false`)
- `inclusive` 값이 `true`일 경우, 기준 나이를 포함하며, `false`일 경우, 기준 나이를 포함하지 않습니다.

```ts title="typescript"
// 2025년 01월 01일 기준
// inclusive 값을 기준으로 기준 나이를 포함할지 여부를 결정합니다.
isUnderAge({ birthDate: '2006-01-01', targetAge: 19, inclusive: true }); // true
isUnderAge({ birthDate: '2006-01-01', targetAge: 19, inclusive: false }); // false
```
45 changes: 45 additions & 0 deletions packages/utils/src/date/getAge/getAge.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { describe, expect, it, beforeEach, vi, afterEach } from 'vitest';
import { getAge } from '.';

beforeEach(() => {
/**
* 테스트를 위해 2025년 01월 01일로 날짜 고정
*
* 1. 2005년 01월 01일: 만 20세
* 2. 2006년 01월 01일: 정확히 만 19세 (기대값: false)
* 3. 2007년 01월 01일: 만 18세
*/
vi.setSystemTime(new Date('2025-01-01'));
});

afterEach(() => {
vi.useRealTimers();
});

describe('getAge', () => {
it('Date 객체로 나이를 정확히 계산해야 함', () => {
expect(getAge(new Date('2007-01-01'))).toBe(18);

expect(getAge(new Date('2006-06-01'))).toBe(18); // 생일이 지나지 않은 경우
expect(getAge(new Date('2006-01-01'))).toBe(19);
expect(getAge(new Date('2005-12-31'))).toBe(19); // 생일이 지난 경우

expect(getAge(new Date('2005-01-01'))).toBe(20);
});

it('날짜 문자열로 나이를 정확히 계산해야 함', () => {
expect(getAge('2007-01-01')).toBe(18);

expect(getAge('2006-06-01')).toBe(18); // 생일이 지나지 않은 경우
expect(getAge('2006-01-01')).toBe(19);
expect(getAge('2005-12-31')).toBe(19); // 생일이 지난 경우

expect(getAge('2005-01-01')).toBe(20);
});

it('잘못된 날짜 형식에 대해 에러를 발생시켜야 함', () => {
expect(() => getAge('invalid-date')).toThrow(
'유효하지 않은 날짜 형식입니다.'
);
});
});
35 changes: 35 additions & 0 deletions packages/utils/src/date/getAge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/**
* @description 주어진 생년월일을 기준으로 현재 나이를 계산합니다.
*
* @param {string | number | Date} birthDate - 확인하고자 하는 생년월일
* @returns {number} 현재 나이 (만 나이)
*
* @example
* // 현재 날짜 2025년 01월 01일 기준
* getAge(new Date('2006-01-01')); // 19
*
* @example
* // 2025년 01월 01일 기준
* getAge('2006-01-01'); // 19
*
*/
export function getAge(birthDate: string | number | Date): number {
const birthDateTime = new Date(birthDate);

if (isNaN(birthDateTime.getTime())) {
throw new Error('유효하지 않은 날짜 형식입니다.');
}

const today = new Date();

const age = today.getFullYear() - birthDateTime.getFullYear();
const monthDiff = today.getMonth() - birthDateTime.getMonth();
const dayDiff = today.getDate() - birthDateTime.getDate();

// 만약, 생일이 지나지 않았다면 나이에서 1을 뺀다.
if (monthDiff < 0 || (monthDiff === 0 && dayDiff < 0)) {
return age - 1;
}

return age;
}
5 changes: 5 additions & 0 deletions packages/utils/src/date/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,6 @@
export * from './getAge';
export * from './getDDay';
export * from './isAfterDate';
export * from './isBeforeDate';
export * from './isDateInRange';
export * from './isUnderAge';
48 changes: 48 additions & 0 deletions packages/utils/src/date/isUnderAge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { getAge } from '../getAge';

interface IsUnderAgeParams {
birthDate: string | number | Date;
targetAge: number;
inclusive?: boolean;
}

/**
* @description 주어진 생년월일을 기준으로 특정 나이보다 어린지 확인합니다.
*
* `inclusive` 값을 기준으로 기준 나이를 포함할지 여부를 결정합니다.
*
* @param {IsUnderAgeParams} params - 확인하고자 하는 생년월일
* @param {string | number| Date} params.birthDate - 확인하고자 하는 생년월일
* @param {number} params.targetAge - 비교할 기준 나이
* @param {boolean} params.inclusive - 기준 나이에 포함 여부
* @returns {boolean} 대상이 기준 나이보다 어리면 true, 아니면 false
* @throws {Error} 유효하지 않은 날짜 형식이 입력된 경우
*
* @example
* // 2025년 01월 01일 기준
* isUnderAge({ birthDate: new Date('2006-01-02'), targetAge: 19 }); // true
* isUnderAge({ birthDate: new Date('2006-01-01'), targetAge: 19 }); // false, 정확히 만 19세
* isUnderAge({ birthDate: new Date('2005-12-31'), targetAge: 19 }); // false
*
* isUnderAge({ birthDate: '2006-01-02', targetAge: 19 }); // true
* isUnderAge({ birthDate: '2006-01-01', targetAge: 19 }); // false, 정확히 만 19세
* isUnderAge({ birthDate: '2005-12-31', targetAge: 19 }); // false
*
* @example
* // 2025년 01월 01일 기준
* // inclusive 값을 기준으로 기준 나이를 포함할지 여부를 결정합니다.
* isUnderAge({
* birthDate: '2006-01-01',
* targetAge: 19,
* inclusive: true
* }); // true
*/
export function isUnderAge({
birthDate,
targetAge,
inclusive = false,
}: IsUnderAgeParams): boolean {
const age = getAge(birthDate);

return inclusive ? age <= targetAge : age < targetAge;
}
71 changes: 71 additions & 0 deletions packages/utils/src/date/isUnderAge/isUnderAge.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { isUnderAge } from '.';

beforeEach(() => {
/**
* 테스트를 위해 2025년 01월 01일로 날짜 고정
*
* 1. 2006년 01월 01일: 정확히 만 19세 (기대값: false)
* 2. 2006년 01월 02일: 만 19세보다 어림 (기대값: true)
* 3. 2005년 12월 31일: 만 19세보다 많음 (기대값: false)
*/
vi.setSystemTime(new Date('2025-01-01'));
});

afterEach(() => {
vi.useRealTimers();
});

describe('isUnderAge', () => {
it('만 19세 미만인 경우 true를 반환해야 합니다.', () => {
// Date 객체
expect(
isUnderAge({ birthDate: new Date('2006-01-02'), targetAge: 19 })
).toBeTruthy();

// 문자열
expect(isUnderAge({ birthDate: '2006-01-02', targetAge: 19 })).toBeTruthy();
});

it('정확히 만 19세인 경우 false를 반환해야 합니다.', () => {
// Date 객체
expect(
isUnderAge({ birthDate: new Date('2006-01-01'), targetAge: 19 })
).toBeFalsy();

// 문자열
expect(isUnderAge({ birthDate: '2006-01-01', targetAge: 19 })).toBeFalsy();
});

it('만 19세가 지난 경우 false를 반환해야 합니다.', () => {
// Date 객체
expect(
isUnderAge({ birthDate: new Date('2005-12-31'), targetAge: 19 })
).toBeFalsy();

// 문자열
expect(isUnderAge({ birthDate: '2005-12-31', targetAge: 19 })).toBeFalsy();
});

it('inclusive 값을 기준으로 기준 나이를 포함할지 여부를 결정해야 한다.', () => {
// Date 객체
expect(
isUnderAge({
birthDate: new Date('2006-01-01'),
targetAge: 19,
inclusive: true,
})
).toBeTruthy();

// 문자열
expect(
isUnderAge({ birthDate: '2006-01-01', targetAge: 19, inclusive: false })
).toBeFalsy();
});

it('잘못된 날짜 형식에 대해 에러를 던진다', () => {
expect(() =>
isUnderAge({ birthDate: 'invalid-date', targetAge: 19 })
).toThrow('유효하지 않은 날짜 형식입니다.');
});
});

0 comments on commit c62d822

Please sign in to comment.