Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(utils): getAge, isUnderAge 신규 함수 추가 #662

Merged
merged 2 commits into from
Jan 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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('유효하지 않은 날짜 형식입니다.');
});
});
Loading