@simplysm/core-common 13.0.0-beta.2 → 13.0.0-beta.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/dist/common.types.js +4 -4
  2. package/dist/errors/argument-error.js +1 -1
  3. package/dist/errors/not-implemented-error.js +1 -1
  4. package/dist/errors/timeout-error.js +1 -1
  5. package/dist/extensions/arr-ext.helpers.js +4 -4
  6. package/dist/extensions/arr-ext.js +9 -9
  7. package/dist/features/debounce-queue.js +2 -2
  8. package/dist/features/serial-queue.js +3 -3
  9. package/dist/index.js +30 -30
  10. package/dist/types/date-only.js +2 -2
  11. package/dist/types/date-time.js +2 -2
  12. package/dist/types/time.js +2 -2
  13. package/dist/types/uuid.js +1 -1
  14. package/dist/utils/bytes.js +1 -1
  15. package/dist/utils/json.js +8 -8
  16. package/dist/utils/obj.js +5 -5
  17. package/dist/utils/primitive.js +5 -5
  18. package/dist/utils/transferable.js +4 -4
  19. package/dist/utils/wait.js +1 -1
  20. package/package.json +7 -4
  21. package/.cache/typecheck-browser.tsbuildinfo +0 -1
  22. package/.cache/typecheck-node.tsbuildinfo +0 -1
  23. package/.cache/typecheck-tests-browser.tsbuildinfo +0 -1
  24. package/.cache/typecheck-tests-node.tsbuildinfo +0 -1
  25. package/src/common.types.ts +0 -91
  26. package/src/env.ts +0 -11
  27. package/src/errors/argument-error.ts +0 -40
  28. package/src/errors/not-implemented-error.ts +0 -32
  29. package/src/errors/sd-error.ts +0 -53
  30. package/src/errors/timeout-error.ts +0 -36
  31. package/src/extensions/arr-ext.helpers.ts +0 -53
  32. package/src/extensions/arr-ext.ts +0 -777
  33. package/src/extensions/arr-ext.types.ts +0 -258
  34. package/src/extensions/map-ext.ts +0 -86
  35. package/src/extensions/set-ext.ts +0 -68
  36. package/src/features/debounce-queue.ts +0 -116
  37. package/src/features/event-emitter.ts +0 -112
  38. package/src/features/serial-queue.ts +0 -94
  39. package/src/globals.ts +0 -12
  40. package/src/index.ts +0 -55
  41. package/src/types/date-only.ts +0 -329
  42. package/src/types/date-time.ts +0 -294
  43. package/src/types/lazy-gc-map.ts +0 -244
  44. package/src/types/time.ts +0 -210
  45. package/src/types/uuid.ts +0 -113
  46. package/src/utils/bytes.ts +0 -160
  47. package/src/utils/date-format.ts +0 -239
  48. package/src/utils/json.ts +0 -230
  49. package/src/utils/num.ts +0 -97
  50. package/src/utils/obj.ts +0 -956
  51. package/src/utils/path.ts +0 -40
  52. package/src/utils/primitive.ts +0 -33
  53. package/src/utils/str.ts +0 -252
  54. package/src/utils/template-strings.ts +0 -132
  55. package/src/utils/transferable.ts +0 -269
  56. package/src/utils/wait.ts +0 -40
  57. package/src/utils/xml.ts +0 -105
  58. package/src/zip/sd-zip.ts +0 -218
  59. package/tests/errors/errors.spec.ts +0 -196
  60. package/tests/extensions/array-extension.spec.ts +0 -790
  61. package/tests/extensions/map-extension.spec.ts +0 -147
  62. package/tests/extensions/set-extension.spec.ts +0 -74
  63. package/tests/types/date-only.spec.ts +0 -636
  64. package/tests/types/date-time.spec.ts +0 -391
  65. package/tests/types/lazy-gc-map.spec.ts +0 -692
  66. package/tests/types/time.spec.ts +0 -559
  67. package/tests/types/types.spec.ts +0 -55
  68. package/tests/types/uuid.spec.ts +0 -91
  69. package/tests/utils/bytes-utils.spec.ts +0 -230
  70. package/tests/utils/date-format.spec.ts +0 -371
  71. package/tests/utils/debounce-queue.spec.ts +0 -272
  72. package/tests/utils/json.spec.ts +0 -475
  73. package/tests/utils/number.spec.ts +0 -184
  74. package/tests/utils/object.spec.ts +0 -827
  75. package/tests/utils/path.spec.ts +0 -78
  76. package/tests/utils/primitive.spec.ts +0 -55
  77. package/tests/utils/sd-event-emitter.spec.ts +0 -216
  78. package/tests/utils/serial-queue.spec.ts +0 -365
  79. package/tests/utils/string.spec.ts +0 -294
  80. package/tests/utils/template-strings.spec.ts +0 -96
  81. package/tests/utils/transferable.spec.ts +0 -698
  82. package/tests/utils/wait.spec.ts +0 -145
  83. package/tests/utils/xml.spec.ts +0 -146
  84. package/tests/zip/sd-zip.spec.ts +0 -234
@@ -1,94 +0,0 @@
1
- /**
2
- * 비동기 함수 직렬 큐
3
- *
4
- * 큐에 추가된 함수들을 순서대로 실행합니다.
5
- * 한 작업이 완료되어야 다음 작업이 시작됩니다.
6
- * 에러가 발생해도 후속 작업은 계속 실행됩니다.
7
- *
8
- * @example
9
- * const queue = new SerialQueue();
10
- * queue.run(async () => { await fetch("/api/1"); });
11
- * queue.run(async () => { await fetch("/api/2"); }); // 1번 완료 후 실행
12
- * queue.run(async () => { await fetch("/api/3"); }); // 2번 완료 후 실행
13
- *
14
- * @example
15
- * // 에러 처리
16
- * queue.on("error", (err) => console.error(err));
17
- */
18
- import { SdError } from "../errors/sd-error";
19
- import { EventEmitter } from "./event-emitter";
20
- import { createConsola } from "consola";
21
- import { waitTime } from "../utils/wait";
22
-
23
- interface SerialQueueEvents {
24
- error: SdError;
25
- }
26
-
27
- export class SerialQueue extends EventEmitter<SerialQueueEvents> {
28
- private static readonly _logger = createConsola().withTag("SerialQueue");
29
-
30
- private readonly _queue: (() => void | Promise<void>)[] = [];
31
- private _isQueueRunning = false;
32
-
33
- /**
34
- * @param _gap 각 작업 사이의 간격 (ms)
35
- */
36
- constructor(private readonly _gap: number = 0) {
37
- super();
38
- }
39
-
40
- /**
41
- * 대기 중인 큐 비우기 (현재 실행 중인 작업은 완료됨)
42
- */
43
- override dispose(): void {
44
- this._queue.length = 0;
45
- super.dispose();
46
- }
47
-
48
- /**
49
- * using 문 지원
50
- */
51
- override [Symbol.dispose](): void {
52
- this.dispose();
53
- }
54
-
55
- /**
56
- * 함수를 큐에 추가하고 실행
57
- */
58
- run(fn: () => void | Promise<void>): void {
59
- this._queue.push(fn);
60
- void this._process();
61
- }
62
-
63
- private async _process(): Promise<void> {
64
- if (this._isQueueRunning) return;
65
- this._isQueueRunning = true;
66
-
67
- try {
68
- while (this._queue.length > 0) {
69
- const fn = this._queue.shift();
70
- if (!fn) break;
71
-
72
- try {
73
- await fn();
74
- } catch (err) {
75
- const error = err instanceof Error ? err : new Error(String(err));
76
- const sdError = new SdError(error, "큐 작업 실행 중 오류 발생");
77
-
78
- // 리스너가 있으면 이벤트로 전달, 없으면 로깅
79
- if (this.listenerCount("error") > 0) {
80
- this.emit("error", sdError);
81
- } else {
82
- SerialQueue._logger.error(sdError);
83
- }
84
- }
85
-
86
- if (this._gap > 0 && this._queue.length > 0) {
87
- await waitTime(this._gap);
88
- }
89
- }
90
- } finally {
91
- this._isQueueRunning = false;
92
- }
93
- }
94
- }
package/src/globals.ts DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * 개발 모드 여부
3
- *
4
- * 빌드 시점에 치환됨:
5
- * - 라이브러리 빌드: 치환하지 않음 (그대로 유지)
6
- * - client/server 빌드: `define: { '__DEV__': 'true/false' }`로 치환
7
- */
8
- export {};
9
-
10
- declare global {
11
- const __DEV__: boolean;
12
- }
package/src/index.ts DELETED
@@ -1,55 +0,0 @@
1
- // @simplysm/core-common
2
- // 공통 유틸리티 패키지
3
-
4
- import "./extensions/arr-ext";
5
- import "./extensions/set-ext";
6
- import "./extensions/map-ext";
7
-
8
- export * from "./env";
9
-
10
- // arr-extension에서 타입만 re-export
11
- export type { ArrayDiffsResult, ArrayDiffs2Result, TreeArray } from "./extensions/arr-ext";
12
-
13
- //#region errors
14
- export * from "./errors/sd-error";
15
- export * from "./errors/argument-error";
16
- export * from "./errors/not-implemented-error";
17
- export * from "./errors/timeout-error";
18
- //#endregion
19
-
20
- //#region types
21
- export * from "./types/uuid";
22
- export * from "./types/lazy-gc-map";
23
- export * from "./types/date-time";
24
- export * from "./types/date-only";
25
- export * from "./types/time";
26
- //#endregion
27
-
28
- //#region features
29
- export * from "./features/debounce-queue";
30
- export * from "./features/serial-queue";
31
- export * from "./features/event-emitter";
32
- //#endregion
33
-
34
- //#region utils
35
- export * from "./utils/date-format";
36
- export * from "./utils/bytes";
37
- export * from "./utils/json";
38
- export * from "./utils/num";
39
- export * from "./utils/obj";
40
- export * from "./utils/primitive";
41
- export * from "./utils/str";
42
- export * from "./utils/template-strings";
43
- export * from "./utils/transferable";
44
- export * from "./utils/wait";
45
- export * from "./utils/xml";
46
- export * from "./utils/path";
47
- //#endregion
48
-
49
- //#region zip
50
- export * from "./zip/sd-zip";
51
- //#endregion
52
-
53
- //#region type utilities
54
- export * from "./common.types";
55
- //#endregion
@@ -1,329 +0,0 @@
1
- import { ArgumentError } from "../errors/argument-error";
2
- import { formatDate, normalizeMonth } from "../utils/date-format";
3
-
4
- /**
5
- * 날짜 클래스 (시간제외: yyyy-MM-dd, 불변)
6
- *
7
- * 시간 정보 없이 날짜만 저장하는 불변 클래스이다.
8
- * 로컬 타임존을 기준으로 동작한다.
9
- *
10
- * @example
11
- * const today = new DateOnly();
12
- * const specific = new DateOnly(2025, 1, 15);
13
- * const parsed = DateOnly.parse("2025-01-15");
14
- */
15
- export class DateOnly {
16
- private static readonly MS_PER_DAY = 24 * 60 * 60 * 1000;
17
-
18
- readonly date: Date;
19
-
20
- /** 현재시간 */
21
- constructor();
22
- /** 연월일로 초기화 */
23
- constructor(year: number, month: number, day: number);
24
- /** tick (millisecond)으로 생성 */
25
- constructor(tick: number);
26
- /** Date 타입으로 생성 */
27
- constructor(date: Date);
28
- constructor(arg1?: number | Date, arg2?: number, arg3?: number) {
29
- if (arg1 === undefined) {
30
- const tick = Date.now();
31
- const date = new Date(tick);
32
- this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
33
- } else if (arg2 !== undefined && arg3 !== undefined) {
34
- this.date = new Date(arg1 as number, arg2 - 1, arg3);
35
- } else if (arg1 instanceof Date) {
36
- const date = arg1;
37
- this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
38
- } else {
39
- const date = new Date(arg1);
40
- this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
41
- }
42
- }
43
-
44
- /**
45
- * 문자열을 DateOnly로 파싱
46
- * @param str 날짜 문자열
47
- * @returns DateOnly 인스턴스
48
- *
49
- * 지원 형식:
50
- * - `yyyy-MM-dd` (예: '2024-01-15') - 문자열에서 직접 추출, 타임존 영향 없음
51
- * - `yyyyMMdd` (예: '20240115') - 문자열에서 직접 추출, 타임존 영향 없음
52
- * - ISO 8601 (예: '2024-01-15T00:00:00Z') - UTC로 해석 후 로컬 타임존 변환
53
- *
54
- * @note 서버/클라이언트 타임존이 다른 경우 `yyyy-MM-dd` 형식 사용 권장
55
- * @note DST(일광절약시간) 지역에서 ISO 8601 형식 파싱 시, 파싱 대상 날짜의 오프셋을 사용합니다.
56
- */
57
- static parse(str: string): DateOnly {
58
- // yyyy-MM-dd 형식 (타임존 영향 없음)
59
- const matchYMD = /^(\d{4})-(\d{2})-(\d{2})$/.exec(str);
60
- if (matchYMD != null) {
61
- return new DateOnly(Number(matchYMD[1]), Number(matchYMD[2]), Number(matchYMD[3]));
62
- }
63
-
64
- // yyyyMMdd 형식 (타임존 영향 없음)
65
- const matchCompact = /^(\d{4})(\d{2})(\d{2})$/.exec(str);
66
- if (matchCompact != null) {
67
- return new DateOnly(Number(matchCompact[1]), Number(matchCompact[2]), Number(matchCompact[3]));
68
- }
69
-
70
- // ISO 8601 등 기타 형식 (Date.parse 사용, 타임존 변환 적용)
71
- // Date.parse()는 'Z' 접미사가 있는 ISO 8601을 UTC tick으로 반환
72
- // getTimezoneOffset()은 "로컬에서 UTC로 변환할 때 더할 분"을 반환 (KST는 -540분 = UTC+9)
73
- // 여기서는 "UTC → 로컬" 변환이므로 부호를 반대로 적용 (뺄셈)
74
- // 파싱 대상 날짜의 오프셋을 사용하여 DST 지역에서도 정확한 변환
75
- const utcTick = Date.parse(str);
76
- if (!Number.isNaN(utcTick)) {
77
- const tempDate = new Date(utcTick);
78
- const offsetMinutes = tempDate.getTimezoneOffset();
79
- const localTick = utcTick - offsetMinutes * 60 * 1000;
80
- return new DateOnly(localTick);
81
- }
82
-
83
- throw new ArgumentError(`날짜 형식을 파싱할 수 없습니다. 지원 형식: 'yyyy-MM-dd', 'yyyyMMdd', ISO 8601 날짜`, {
84
- input: str,
85
- });
86
- }
87
-
88
- //#region 주차 계산
89
-
90
- /**
91
- * 기준 연도와 월을 주차 정보를 기반으로 반환
92
- * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
93
- * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
94
- * @returns 해당 날짜가 속한 주차의 기준 연도와 월
95
- *
96
- * @example
97
- * // ISO 8601 표준 (월요일 시작, 첫 주 최소 4일)
98
- * new DateOnly(2024, 1, 1).getBaseYearMonthSeqForWeekSeq(1, 4)
99
- * // 미국식 (일요일 시작, 첫 주 최소 1일)
100
- * new DateOnly(2024, 1, 1).getBaseYearMonthSeqForWeekSeq(0, 1)
101
- */
102
- getBaseYearMonthSeqForWeekSeq(weekStartDay: number = 1, minDaysInFirstWeek: number = 4) {
103
- // 주의 시작 요일 기준으로 현재 날짜의 요일 인덱스 계산 (0 = 주 시작일)
104
- const dayOfWeek = (this.dayOfWeek + 7 - weekStartDay) % 7;
105
- // 현재 주의 남은 일수 (현재 날짜 포함)
106
- const daysInWeek = 7 - dayOfWeek;
107
-
108
- // 현재 주의 남은 일수가 첫 주 최소 일수 미만이면 이전 주로 간주
109
- if (daysInWeek < minDaysInFirstWeek) {
110
- const prevWeek = this.addDays(-7);
111
- return { year: prevWeek.year, monthSeq: prevWeek.month };
112
- } else {
113
- // 월 경계를 고려한 실제 주의 남은 일수 계산
114
- const nextMonthDate = this.addMonths(1).setDay(1);
115
- const remainedDays = (nextMonthDate.tick - this.tick) / DateOnly.MS_PER_DAY;
116
-
117
- // 월 경계까지의 실제 일수와 주의 남은 일수 중 작은 값
118
- const realDaysInWeek = Math.min(daysInWeek, remainedDays);
119
- // 월 경계 고려 시에도 첫 주 최소 일수 미만이면 다음 주로 간주
120
- if (realDaysInWeek < minDaysInFirstWeek) {
121
- const nextWeek = this.addDays(7);
122
- return { year: nextWeek.year, monthSeq: nextWeek.month };
123
- } else {
124
- return { year: this.year, monthSeq: this.month };
125
- }
126
- }
127
- }
128
-
129
- /**
130
- * 주차 정보를 기반으로 해당 주의 시작 날짜 계산
131
- * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
132
- * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
133
- * @returns 해당 날짜가 속한 주의 시작 날짜
134
- */
135
- getWeekSeqStartDate(weekStartDay: number = 1, minDaysInFirstWeek: number = 4) {
136
- const dayOfWeek = (this.dayOfWeek + 7 - weekStartDay) % 7;
137
- const daysInFirstWeek = 7 - dayOfWeek;
138
-
139
- if (daysInFirstWeek < minDaysInFirstWeek) {
140
- return this.addDays(-dayOfWeek + 7);
141
- } else {
142
- return this.addDays(-dayOfWeek);
143
- }
144
- }
145
-
146
- /**
147
- * 연도 및 주차 순서 정보를 반환
148
- * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
149
- * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
150
- * @returns 연도와 해당 연도 기준 주차 번호
151
- *
152
- * @example
153
- * // ISO 8601 표준 (월요일 시작, 첫 주 4일 이상)
154
- * new DateOnly(2025, 1, 6).getWeekSeqOfYear(); // { year: 2025, weekSeq: 2 }
155
- *
156
- * // 미국식 (일요일 시작, 첫 주 1일 이상)
157
- * new DateOnly(2025, 1, 1).getWeekSeqOfYear(0, 1); // { year: 2025, weekSeq: 1 }
158
- */
159
- getWeekSeqOfYear(weekStartDay: number = 1, minDaysInFirstWeek: number = 4): { year: number; weekSeq: number } {
160
- const base = this.getBaseYearMonthSeqForWeekSeq(weekStartDay, minDaysInFirstWeek);
161
-
162
- const firstWeekStart = new DateOnly(base.year, 1, 1).getWeekSeqStartDate(weekStartDay, minDaysInFirstWeek);
163
-
164
- const diffDays = (this.tick - firstWeekStart.tick) / DateOnly.MS_PER_DAY;
165
- return {
166
- year: base.year,
167
- weekSeq: Math.floor(diffDays / 7) + 1,
168
- };
169
- }
170
-
171
- /**
172
- * 해당 날짜의 연도, 월 및 주차(weekSeq) 정보를 반환
173
- * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
174
- * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
175
- * @returns 연도, 월 및 해당 월 기준 주차 번호
176
- *
177
- * @example
178
- * // ISO 8601 표준 (월요일 시작, 첫 주 4일 이상)
179
- * new DateOnly(2025, 1, 15).getWeekSeqOfMonth(); // { year: 2025, monthSeq: 1, weekSeq: 3 }
180
- *
181
- * // 미국식 (일요일 시작, 첫 주 1일 이상)
182
- * new DateOnly(2025, 1, 15).getWeekSeqOfMonth(0, 1); // { year: 2025, monthSeq: 1, weekSeq: 3 }
183
- */
184
- getWeekSeqOfMonth(
185
- weekStartDay: number = 1,
186
- minDaysInFirstWeek: number = 4,
187
- ): { year: number; monthSeq: number; weekSeq: number } {
188
- const base = this.getBaseYearMonthSeqForWeekSeq(weekStartDay, minDaysInFirstWeek);
189
-
190
- const firstWeekStart = new DateOnly(base.year, base.monthSeq, 1).getWeekSeqStartDate(
191
- weekStartDay,
192
- minDaysInFirstWeek,
193
- );
194
-
195
- const diffDays = (this.tick - firstWeekStart.tick) / DateOnly.MS_PER_DAY;
196
- return {
197
- year: base.year,
198
- monthSeq: base.monthSeq,
199
- weekSeq: Math.floor(diffDays / 7) + 1,
200
- };
201
- }
202
-
203
- /**
204
- * 주차 정보를 기반으로 해당 주의 시작 날짜 가져오기
205
- * @param arg 연도, 선택적 월, 주차 번호
206
- * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
207
- * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
208
- * @returns 해당 주차의 시작 날짜
209
- *
210
- * @example
211
- * // 2025년 2주차의 시작일 (ISO 8601 표준)
212
- * DateOnly.getDateByYearWeekSeq({ year: 2025, weekSeq: 2 }); // 2025-01-06 (월요일)
213
- *
214
- * // 2025년 1월 3주차의 시작일
215
- * DateOnly.getDateByYearWeekSeq({ year: 2025, month: 1, weekSeq: 3 }); // 2025-01-13 (월요일)
216
- */
217
- static getDateByYearWeekSeq(
218
- arg: { year: number; month?: number; weekSeq: number },
219
- weekStartDay: number = 1,
220
- minDaysInFirstWeek: number = 4,
221
- ) {
222
- return new DateOnly(arg.year, arg.month ?? 1, (arg.weekSeq - 1) * 7 + 1).getWeekSeqStartDate(
223
- weekStartDay,
224
- minDaysInFirstWeek,
225
- );
226
- }
227
-
228
- //#endregion
229
-
230
- //#region Getters (읽기 전용)
231
-
232
- /** 날짜 세팅이 제대로 되었는지 여부 */
233
- get isValid(): boolean {
234
- return this.date instanceof Date && !Number.isNaN(this.date.getTime());
235
- }
236
-
237
- get year(): number {
238
- return this.date.getFullYear();
239
- }
240
-
241
- get month(): number {
242
- return this.date.getMonth() + 1;
243
- }
244
-
245
- get day(): number {
246
- return this.date.getDate();
247
- }
248
-
249
- get tick(): number {
250
- return this.date.getTime();
251
- }
252
-
253
- /** 요일 (일~토: 0~6) */
254
- get dayOfWeek(): number {
255
- return this.date.getDay();
256
- }
257
-
258
- //#endregion
259
-
260
- //#region 불변 변환 메서드 (새 인스턴스 반환)
261
-
262
- /** 지정된 연도로 새 인스턴스 반환 */
263
- setYear(year: number): DateOnly {
264
- return new DateOnly(year, this.month, this.day);
265
- }
266
-
267
- /**
268
- * 지정된 월로 새 DateOnly 인스턴스를 반환
269
- * @param month 설정할 월 (1-12, 범위 외 값은 연도 조정)
270
- * @note 대상 월의 일수보다 현재 일자가 크면 해당 월의 마지막 날로 조정됨
271
- * (예: 1월 31일에서 setMonth(2) → 2월 28일 또는 29일)
272
- */
273
- setMonth(month: number): DateOnly {
274
- const normalized = normalizeMonth(this.year, month, this.day);
275
- return new DateOnly(normalized.year, normalized.month, normalized.day);
276
- }
277
-
278
- /**
279
- * 지정된 일자로 새 DateOnly 인스턴스를 반환
280
- * @param day 설정할 일자
281
- * @note 해당 월의 유효 범위를 벗어나는 일자는 JavaScript Date 기본 동작에 따라
282
- * 자동으로 다음/이전 달로 조정됨 (예: 1월에 day=32 → 2월 1일)
283
- */
284
- setDay(day: number): DateOnly {
285
- return new DateOnly(this.year, this.month, day);
286
- }
287
-
288
- //#endregion
289
-
290
- //#region 산술 메서드 (새 인스턴스 반환)
291
-
292
- /** 지정된 연수를 더한 새 인스턴스 반환 */
293
- addYears(years: number): DateOnly {
294
- return this.setYear(this.year + years);
295
- }
296
-
297
- /** 지정된 월수를 더한 새 인스턴스 반환 */
298
- addMonths(months: number): DateOnly {
299
- return this.setMonth(this.month + months);
300
- }
301
-
302
- /** 지정된 일수를 더한 새 인스턴스 반환 */
303
- addDays(days: number): DateOnly {
304
- return new DateOnly(this.tick + days * DateOnly.MS_PER_DAY);
305
- }
306
-
307
- //#endregion
308
-
309
- //#region 포맷팅
310
-
311
- /**
312
- * 지정된 포맷으로 문자열 변환
313
- * @param format 포맷 문자열
314
- * @see dtFormat 지원 포맷 문자열 참조
315
- */
316
- toFormatString(formatStr: string): string {
317
- return formatDate(formatStr, {
318
- year: this.year,
319
- month: this.month,
320
- day: this.day,
321
- });
322
- }
323
-
324
- toString(): string {
325
- return this.toFormatString("yyyy-MM-dd");
326
- }
327
-
328
- //#endregion
329
- }