@simplysm/core-common 13.0.0-beta.1

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 (202) hide show
  1. package/.cache/typecheck-browser.tsbuildinfo +1 -0
  2. package/.cache/typecheck-node.tsbuildinfo +1 -0
  3. package/.cache/typecheck-tests-browser.tsbuildinfo +1 -0
  4. package/.cache/typecheck-tests-node.tsbuildinfo +1 -0
  5. package/README.md +887 -0
  6. package/dist/common.types.d.ts +74 -0
  7. package/dist/common.types.d.ts.map +1 -0
  8. package/dist/common.types.js +5 -0
  9. package/dist/common.types.js.map +7 -0
  10. package/dist/env.d.ts +6 -0
  11. package/dist/env.d.ts.map +1 -0
  12. package/dist/env.js +9 -0
  13. package/dist/env.js.map +7 -0
  14. package/dist/errors/argument-error.d.ts +25 -0
  15. package/dist/errors/argument-error.d.ts.map +1 -0
  16. package/dist/errors/argument-error.js +18 -0
  17. package/dist/errors/argument-error.js.map +7 -0
  18. package/dist/errors/not-implemented-error.d.ts +29 -0
  19. package/dist/errors/not-implemented-error.d.ts.map +1 -0
  20. package/dist/errors/not-implemented-error.js +14 -0
  21. package/dist/errors/not-implemented-error.js.map +7 -0
  22. package/dist/errors/sd-error.d.ts +27 -0
  23. package/dist/errors/sd-error.d.ts.map +1 -0
  24. package/dist/errors/sd-error.js +23 -0
  25. package/dist/errors/sd-error.js.map +7 -0
  26. package/dist/errors/timeout-error.d.ts +31 -0
  27. package/dist/errors/timeout-error.d.ts.map +1 -0
  28. package/dist/errors/timeout-error.js +17 -0
  29. package/dist/errors/timeout-error.js.map +7 -0
  30. package/dist/extensions/arr-ext.d.ts +15 -0
  31. package/dist/extensions/arr-ext.d.ts.map +1 -0
  32. package/dist/extensions/arr-ext.helpers.d.ts +19 -0
  33. package/dist/extensions/arr-ext.helpers.d.ts.map +1 -0
  34. package/dist/extensions/arr-ext.helpers.js +35 -0
  35. package/dist/extensions/arr-ext.helpers.js.map +7 -0
  36. package/dist/extensions/arr-ext.js +546 -0
  37. package/dist/extensions/arr-ext.js.map +7 -0
  38. package/dist/extensions/arr-ext.types.d.ts +215 -0
  39. package/dist/extensions/arr-ext.types.d.ts.map +1 -0
  40. package/dist/extensions/arr-ext.types.js +1 -0
  41. package/dist/extensions/arr-ext.types.js.map +7 -0
  42. package/dist/extensions/map-ext.d.ts +57 -0
  43. package/dist/extensions/map-ext.d.ts.map +1 -0
  44. package/dist/extensions/map-ext.js +26 -0
  45. package/dist/extensions/map-ext.js.map +7 -0
  46. package/dist/extensions/set-ext.d.ts +36 -0
  47. package/dist/extensions/set-ext.d.ts.map +1 -0
  48. package/dist/extensions/set-ext.js +29 -0
  49. package/dist/extensions/set-ext.js.map +7 -0
  50. package/dist/features/debounce-queue.d.ts +53 -0
  51. package/dist/features/debounce-queue.d.ts.map +1 -0
  52. package/dist/features/debounce-queue.js +80 -0
  53. package/dist/features/debounce-queue.js.map +7 -0
  54. package/dist/features/event-emitter.d.ts +66 -0
  55. package/dist/features/event-emitter.d.ts.map +1 -0
  56. package/dist/features/event-emitter.js +82 -0
  57. package/dist/features/event-emitter.js.map +7 -0
  58. package/dist/features/serial-queue.d.ts +47 -0
  59. package/dist/features/serial-queue.d.ts.map +1 -0
  60. package/dist/features/serial-queue.js +66 -0
  61. package/dist/features/serial-queue.js.map +7 -0
  62. package/dist/globals.d.ts +12 -0
  63. package/dist/globals.d.ts.map +1 -0
  64. package/dist/globals.js +1 -0
  65. package/dist/globals.js.map +7 -0
  66. package/dist/index.d.ts +32 -0
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +31 -0
  69. package/dist/index.js.map +7 -0
  70. package/dist/types/date-only.d.ts +152 -0
  71. package/dist/types/date-only.d.ts.map +1 -0
  72. package/dist/types/date-only.js +251 -0
  73. package/dist/types/date-only.js.map +7 -0
  74. package/dist/types/date-time.d.ts +96 -0
  75. package/dist/types/date-time.d.ts.map +1 -0
  76. package/dist/types/date-time.js +220 -0
  77. package/dist/types/date-time.js.map +7 -0
  78. package/dist/types/lazy-gc-map.d.ts +80 -0
  79. package/dist/types/lazy-gc-map.d.ts.map +1 -0
  80. package/dist/types/lazy-gc-map.js +179 -0
  81. package/dist/types/lazy-gc-map.js.map +7 -0
  82. package/dist/types/time.d.ts +68 -0
  83. package/dist/types/time.d.ts.map +1 -0
  84. package/dist/types/time.js +151 -0
  85. package/dist/types/time.js.map +7 -0
  86. package/dist/types/uuid.d.ts +35 -0
  87. package/dist/types/uuid.d.ts.map +1 -0
  88. package/dist/types/uuid.js +71 -0
  89. package/dist/types/uuid.js.map +7 -0
  90. package/dist/utils/bytes.d.ts +51 -0
  91. package/dist/utils/bytes.d.ts.map +1 -0
  92. package/dist/utils/bytes.js +89 -0
  93. package/dist/utils/bytes.js.map +7 -0
  94. package/dist/utils/date-format.d.ts +90 -0
  95. package/dist/utils/date-format.d.ts.map +1 -0
  96. package/dist/utils/date-format.js +106 -0
  97. package/dist/utils/date-format.js.map +7 -0
  98. package/dist/utils/json.d.ts +34 -0
  99. package/dist/utils/json.d.ts.map +1 -0
  100. package/dist/utils/json.js +152 -0
  101. package/dist/utils/json.js.map +7 -0
  102. package/dist/utils/num.d.ts +60 -0
  103. package/dist/utils/num.d.ts.map +1 -0
  104. package/dist/utils/num.js +39 -0
  105. package/dist/utils/num.js.map +7 -0
  106. package/dist/utils/obj.d.ts +258 -0
  107. package/dist/utils/obj.d.ts.map +1 -0
  108. package/dist/utils/obj.js +538 -0
  109. package/dist/utils/obj.js.map +7 -0
  110. package/dist/utils/path.d.ts +23 -0
  111. package/dist/utils/path.d.ts.map +1 -0
  112. package/dist/utils/path.js +21 -0
  113. package/dist/utils/path.js.map +7 -0
  114. package/dist/utils/primitive.d.ts +18 -0
  115. package/dist/utils/primitive.d.ts.map +1 -0
  116. package/dist/utils/primitive.js +20 -0
  117. package/dist/utils/primitive.js.map +7 -0
  118. package/dist/utils/str.d.ts +103 -0
  119. package/dist/utils/str.d.ts.map +1 -0
  120. package/dist/utils/str.js +128 -0
  121. package/dist/utils/str.js.map +7 -0
  122. package/dist/utils/template-strings.d.ts +84 -0
  123. package/dist/utils/template-strings.d.ts.map +1 -0
  124. package/dist/utils/template-strings.js +49 -0
  125. package/dist/utils/template-strings.js.map +7 -0
  126. package/dist/utils/transferable.d.ts +47 -0
  127. package/dist/utils/transferable.d.ts.map +1 -0
  128. package/dist/utils/transferable.js +153 -0
  129. package/dist/utils/transferable.js.map +7 -0
  130. package/dist/utils/wait.d.ts +19 -0
  131. package/dist/utils/wait.d.ts.map +1 -0
  132. package/dist/utils/wait.js +19 -0
  133. package/dist/utils/wait.js.map +7 -0
  134. package/dist/utils/xml.d.ts +36 -0
  135. package/dist/utils/xml.d.ts.map +1 -0
  136. package/dist/utils/xml.js +51 -0
  137. package/dist/utils/xml.js.map +7 -0
  138. package/dist/zip/sd-zip.d.ts +80 -0
  139. package/dist/zip/sd-zip.d.ts.map +1 -0
  140. package/dist/zip/sd-zip.js +153 -0
  141. package/dist/zip/sd-zip.js.map +7 -0
  142. package/package.json +31 -0
  143. package/src/common.types.ts +91 -0
  144. package/src/env.ts +11 -0
  145. package/src/errors/argument-error.ts +40 -0
  146. package/src/errors/not-implemented-error.ts +32 -0
  147. package/src/errors/sd-error.ts +53 -0
  148. package/src/errors/timeout-error.ts +36 -0
  149. package/src/extensions/arr-ext.helpers.ts +53 -0
  150. package/src/extensions/arr-ext.ts +777 -0
  151. package/src/extensions/arr-ext.types.ts +258 -0
  152. package/src/extensions/map-ext.ts +86 -0
  153. package/src/extensions/set-ext.ts +68 -0
  154. package/src/features/debounce-queue.ts +116 -0
  155. package/src/features/event-emitter.ts +112 -0
  156. package/src/features/serial-queue.ts +94 -0
  157. package/src/globals.ts +12 -0
  158. package/src/index.ts +55 -0
  159. package/src/types/date-only.ts +329 -0
  160. package/src/types/date-time.ts +294 -0
  161. package/src/types/lazy-gc-map.ts +244 -0
  162. package/src/types/time.ts +210 -0
  163. package/src/types/uuid.ts +113 -0
  164. package/src/utils/bytes.ts +160 -0
  165. package/src/utils/date-format.ts +239 -0
  166. package/src/utils/json.ts +230 -0
  167. package/src/utils/num.ts +97 -0
  168. package/src/utils/obj.ts +956 -0
  169. package/src/utils/path.ts +40 -0
  170. package/src/utils/primitive.ts +33 -0
  171. package/src/utils/str.ts +252 -0
  172. package/src/utils/template-strings.ts +132 -0
  173. package/src/utils/transferable.ts +269 -0
  174. package/src/utils/wait.ts +40 -0
  175. package/src/utils/xml.ts +105 -0
  176. package/src/zip/sd-zip.ts +218 -0
  177. package/tests/errors/errors.spec.ts +196 -0
  178. package/tests/extensions/array-extension.spec.ts +790 -0
  179. package/tests/extensions/map-extension.spec.ts +147 -0
  180. package/tests/extensions/set-extension.spec.ts +74 -0
  181. package/tests/types/date-only.spec.ts +636 -0
  182. package/tests/types/date-time.spec.ts +391 -0
  183. package/tests/types/lazy-gc-map.spec.ts +692 -0
  184. package/tests/types/time.spec.ts +559 -0
  185. package/tests/types/types.spec.ts +55 -0
  186. package/tests/types/uuid.spec.ts +91 -0
  187. package/tests/utils/bytes-utils.spec.ts +230 -0
  188. package/tests/utils/date-format.spec.ts +371 -0
  189. package/tests/utils/debounce-queue.spec.ts +272 -0
  190. package/tests/utils/json.spec.ts +475 -0
  191. package/tests/utils/number.spec.ts +184 -0
  192. package/tests/utils/object.spec.ts +827 -0
  193. package/tests/utils/path.spec.ts +78 -0
  194. package/tests/utils/primitive.spec.ts +55 -0
  195. package/tests/utils/sd-event-emitter.spec.ts +216 -0
  196. package/tests/utils/serial-queue.spec.ts +365 -0
  197. package/tests/utils/string.spec.ts +294 -0
  198. package/tests/utils/template-strings.spec.ts +96 -0
  199. package/tests/utils/transferable.spec.ts +698 -0
  200. package/tests/utils/wait.spec.ts +145 -0
  201. package/tests/utils/xml.spec.ts +146 -0
  202. package/tests/zip/sd-zip.spec.ts +234 -0
@@ -0,0 +1,251 @@
1
+ import { ArgumentError } from "../errors/argument-error";
2
+ import { formatDate, normalizeMonth } from "../utils/date-format";
3
+ class DateOnly {
4
+ static MS_PER_DAY = 24 * 60 * 60 * 1e3;
5
+ date;
6
+ constructor(arg1, arg2, arg3) {
7
+ if (arg1 === void 0) {
8
+ const tick = Date.now();
9
+ const date = new Date(tick);
10
+ this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
11
+ } else if (arg2 !== void 0 && arg3 !== void 0) {
12
+ this.date = new Date(arg1, arg2 - 1, arg3);
13
+ } else if (arg1 instanceof Date) {
14
+ const date = arg1;
15
+ this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
16
+ } else {
17
+ const date = new Date(arg1);
18
+ this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
19
+ }
20
+ }
21
+ /**
22
+ * 문자열을 DateOnly로 파싱
23
+ * @param str 날짜 문자열
24
+ * @returns DateOnly 인스턴스
25
+ *
26
+ * 지원 형식:
27
+ * - `yyyy-MM-dd` (예: '2024-01-15') - 문자열에서 직접 추출, 타임존 영향 없음
28
+ * - `yyyyMMdd` (예: '20240115') - 문자열에서 직접 추출, 타임존 영향 없음
29
+ * - ISO 8601 (예: '2024-01-15T00:00:00Z') - UTC로 해석 후 로컬 타임존 변환
30
+ *
31
+ * @note 서버/클라이언트 타임존이 다른 경우 `yyyy-MM-dd` 형식 사용 권장
32
+ * @note DST(일광절약시간) 지역에서 ISO 8601 형식 파싱 시, 파싱 대상 날짜의 오프셋을 사용합니다.
33
+ */
34
+ static parse(str) {
35
+ const matchYMD = /^(\d{4})-(\d{2})-(\d{2})$/.exec(str);
36
+ if (matchYMD != null) {
37
+ return new DateOnly(Number(matchYMD[1]), Number(matchYMD[2]), Number(matchYMD[3]));
38
+ }
39
+ const matchCompact = /^(\d{4})(\d{2})(\d{2})$/.exec(str);
40
+ if (matchCompact != null) {
41
+ return new DateOnly(Number(matchCompact[1]), Number(matchCompact[2]), Number(matchCompact[3]));
42
+ }
43
+ const utcTick = Date.parse(str);
44
+ if (!Number.isNaN(utcTick)) {
45
+ const tempDate = new Date(utcTick);
46
+ const offsetMinutes = tempDate.getTimezoneOffset();
47
+ const localTick = utcTick - offsetMinutes * 60 * 1e3;
48
+ return new DateOnly(localTick);
49
+ }
50
+ throw new ArgumentError(`\uB0A0\uC9DC \uD615\uC2DD\uC744 \uD30C\uC2F1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC9C0\uC6D0 \uD615\uC2DD: 'yyyy-MM-dd', 'yyyyMMdd', ISO 8601 \uB0A0\uC9DC`, {
51
+ input: str
52
+ });
53
+ }
54
+ //#region 주차 계산
55
+ /**
56
+ * 기준 연도와 월을 주차 정보를 기반으로 반환
57
+ * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
58
+ * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
59
+ * @returns 해당 날짜가 속한 주차의 기준 연도와 월
60
+ *
61
+ * @example
62
+ * // ISO 8601 표준 (월요일 시작, 첫 주 최소 4일)
63
+ * new DateOnly(2024, 1, 1).getBaseYearMonthSeqForWeekSeq(1, 4)
64
+ * // 미국식 (일요일 시작, 첫 주 최소 1일)
65
+ * new DateOnly(2024, 1, 1).getBaseYearMonthSeqForWeekSeq(0, 1)
66
+ */
67
+ getBaseYearMonthSeqForWeekSeq(weekStartDay = 1, minDaysInFirstWeek = 4) {
68
+ const dayOfWeek = (this.dayOfWeek + 7 - weekStartDay) % 7;
69
+ const daysInWeek = 7 - dayOfWeek;
70
+ if (daysInWeek < minDaysInFirstWeek) {
71
+ const prevWeek = this.addDays(-7);
72
+ return { year: prevWeek.year, monthSeq: prevWeek.month };
73
+ } else {
74
+ const nextMonthDate = this.addMonths(1).setDay(1);
75
+ const remainedDays = (nextMonthDate.tick - this.tick) / DateOnly.MS_PER_DAY;
76
+ const realDaysInWeek = Math.min(daysInWeek, remainedDays);
77
+ if (realDaysInWeek < minDaysInFirstWeek) {
78
+ const nextWeek = this.addDays(7);
79
+ return { year: nextWeek.year, monthSeq: nextWeek.month };
80
+ } else {
81
+ return { year: this.year, monthSeq: this.month };
82
+ }
83
+ }
84
+ }
85
+ /**
86
+ * 주차 정보를 기반으로 해당 주의 시작 날짜 계산
87
+ * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
88
+ * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
89
+ * @returns 해당 날짜가 속한 주의 시작 날짜
90
+ */
91
+ getWeekSeqStartDate(weekStartDay = 1, minDaysInFirstWeek = 4) {
92
+ const dayOfWeek = (this.dayOfWeek + 7 - weekStartDay) % 7;
93
+ const daysInFirstWeek = 7 - dayOfWeek;
94
+ if (daysInFirstWeek < minDaysInFirstWeek) {
95
+ return this.addDays(-dayOfWeek + 7);
96
+ } else {
97
+ return this.addDays(-dayOfWeek);
98
+ }
99
+ }
100
+ /**
101
+ * 연도 및 주차 순서 정보를 반환
102
+ * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
103
+ * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
104
+ * @returns 연도와 해당 연도 기준 주차 번호
105
+ *
106
+ * @example
107
+ * // ISO 8601 표준 (월요일 시작, 첫 주 4일 이상)
108
+ * new DateOnly(2025, 1, 6).getWeekSeqOfYear(); // { year: 2025, weekSeq: 2 }
109
+ *
110
+ * // 미국식 (일요일 시작, 첫 주 1일 이상)
111
+ * new DateOnly(2025, 1, 1).getWeekSeqOfYear(0, 1); // { year: 2025, weekSeq: 1 }
112
+ */
113
+ getWeekSeqOfYear(weekStartDay = 1, minDaysInFirstWeek = 4) {
114
+ const base = this.getBaseYearMonthSeqForWeekSeq(weekStartDay, minDaysInFirstWeek);
115
+ const firstWeekStart = new DateOnly(base.year, 1, 1).getWeekSeqStartDate(weekStartDay, minDaysInFirstWeek);
116
+ const diffDays = (this.tick - firstWeekStart.tick) / DateOnly.MS_PER_DAY;
117
+ return {
118
+ year: base.year,
119
+ weekSeq: Math.floor(diffDays / 7) + 1
120
+ };
121
+ }
122
+ /**
123
+ * 해당 날짜의 연도, 월 및 주차(weekSeq) 정보를 반환
124
+ * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
125
+ * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
126
+ * @returns 연도, 월 및 해당 월 기준 주차 번호
127
+ *
128
+ * @example
129
+ * // ISO 8601 표준 (월요일 시작, 첫 주 4일 이상)
130
+ * new DateOnly(2025, 1, 15).getWeekSeqOfMonth(); // { year: 2025, monthSeq: 1, weekSeq: 3 }
131
+ *
132
+ * // 미국식 (일요일 시작, 첫 주 1일 이상)
133
+ * new DateOnly(2025, 1, 15).getWeekSeqOfMonth(0, 1); // { year: 2025, monthSeq: 1, weekSeq: 3 }
134
+ */
135
+ getWeekSeqOfMonth(weekStartDay = 1, minDaysInFirstWeek = 4) {
136
+ const base = this.getBaseYearMonthSeqForWeekSeq(weekStartDay, minDaysInFirstWeek);
137
+ const firstWeekStart = new DateOnly(base.year, base.monthSeq, 1).getWeekSeqStartDate(
138
+ weekStartDay,
139
+ minDaysInFirstWeek
140
+ );
141
+ const diffDays = (this.tick - firstWeekStart.tick) / DateOnly.MS_PER_DAY;
142
+ return {
143
+ year: base.year,
144
+ monthSeq: base.monthSeq,
145
+ weekSeq: Math.floor(diffDays / 7) + 1
146
+ };
147
+ }
148
+ /**
149
+ * 주차 정보를 기반으로 해당 주의 시작 날짜 가져오기
150
+ * @param arg 연도, 선택적 월, 주차 번호
151
+ * @param weekStartDay 주의 시작 요일 (0=일요일, 1=월요일, ..., 6=토요일). 기본값: 1(월요일)
152
+ * @param minDaysInFirstWeek 첫 주로 간주할 최소 일수 (1~7). 기본값: 4 (ISO 8601 표준)
153
+ * @returns 해당 주차의 시작 날짜
154
+ *
155
+ * @example
156
+ * // 2025년 2주차의 시작일 (ISO 8601 표준)
157
+ * DateOnly.getDateByYearWeekSeq({ year: 2025, weekSeq: 2 }); // 2025-01-06 (월요일)
158
+ *
159
+ * // 2025년 1월 3주차의 시작일
160
+ * DateOnly.getDateByYearWeekSeq({ year: 2025, month: 1, weekSeq: 3 }); // 2025-01-13 (월요일)
161
+ */
162
+ static getDateByYearWeekSeq(arg, weekStartDay = 1, minDaysInFirstWeek = 4) {
163
+ return new DateOnly(arg.year, arg.month ?? 1, (arg.weekSeq - 1) * 7 + 1).getWeekSeqStartDate(
164
+ weekStartDay,
165
+ minDaysInFirstWeek
166
+ );
167
+ }
168
+ //#endregion
169
+ //#region Getters (읽기 전용)
170
+ /** 날짜 세팅이 제대로 되었는지 여부 */
171
+ get isValid() {
172
+ return this.date instanceof Date && !Number.isNaN(this.date.getTime());
173
+ }
174
+ get year() {
175
+ return this.date.getFullYear();
176
+ }
177
+ get month() {
178
+ return this.date.getMonth() + 1;
179
+ }
180
+ get day() {
181
+ return this.date.getDate();
182
+ }
183
+ get tick() {
184
+ return this.date.getTime();
185
+ }
186
+ /** 요일 (일~토: 0~6) */
187
+ get dayOfWeek() {
188
+ return this.date.getDay();
189
+ }
190
+ //#endregion
191
+ //#region 불변 변환 메서드 (새 인스턴스 반환)
192
+ /** 지정된 연도로 새 인스턴스 반환 */
193
+ setYear(year) {
194
+ return new DateOnly(year, this.month, this.day);
195
+ }
196
+ /**
197
+ * 지정된 월로 새 DateOnly 인스턴스를 반환
198
+ * @param month 설정할 월 (1-12, 범위 외 값은 연도 조정)
199
+ * @note 대상 월의 일수보다 현재 일자가 크면 해당 월의 마지막 날로 조정됨
200
+ * (예: 1월 31일에서 setMonth(2) → 2월 28일 또는 29일)
201
+ */
202
+ setMonth(month) {
203
+ const normalized = normalizeMonth(this.year, month, this.day);
204
+ return new DateOnly(normalized.year, normalized.month, normalized.day);
205
+ }
206
+ /**
207
+ * 지정된 일자로 새 DateOnly 인스턴스를 반환
208
+ * @param day 설정할 일자
209
+ * @note 해당 월의 유효 범위를 벗어나는 일자는 JavaScript Date 기본 동작에 따라
210
+ * 자동으로 다음/이전 달로 조정됨 (예: 1월에 day=32 → 2월 1일)
211
+ */
212
+ setDay(day) {
213
+ return new DateOnly(this.year, this.month, day);
214
+ }
215
+ //#endregion
216
+ //#region 산술 메서드 (새 인스턴스 반환)
217
+ /** 지정된 연수를 더한 새 인스턴스 반환 */
218
+ addYears(years) {
219
+ return this.setYear(this.year + years);
220
+ }
221
+ /** 지정된 월수를 더한 새 인스턴스 반환 */
222
+ addMonths(months) {
223
+ return this.setMonth(this.month + months);
224
+ }
225
+ /** 지정된 일수를 더한 새 인스턴스 반환 */
226
+ addDays(days) {
227
+ return new DateOnly(this.tick + days * DateOnly.MS_PER_DAY);
228
+ }
229
+ //#endregion
230
+ //#region 포맷팅
231
+ /**
232
+ * 지정된 포맷으로 문자열 변환
233
+ * @param format 포맷 문자열
234
+ * @see dtFormat 지원 포맷 문자열 참조
235
+ */
236
+ toFormatString(formatStr) {
237
+ return formatDate(formatStr, {
238
+ year: this.year,
239
+ month: this.month,
240
+ day: this.day
241
+ });
242
+ }
243
+ toString() {
244
+ return this.toFormatString("yyyy-MM-dd");
245
+ }
246
+ //#endregion
247
+ }
248
+ export {
249
+ DateOnly
250
+ };
251
+ //# sourceMappingURL=date-only.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/types/date-only.ts"],
4
+ "sourcesContent": ["import { ArgumentError } from \"../errors/argument-error\";\nimport { formatDate, normalizeMonth } from \"../utils/date-format\";\n\n/**\n * \uB0A0\uC9DC \uD074\uB798\uC2A4 (\uC2DC\uAC04\uC81C\uC678: yyyy-MM-dd, \uBD88\uBCC0)\n *\n * \uC2DC\uAC04 \uC815\uBCF4 \uC5C6\uC774 \uB0A0\uC9DC\uB9CC \uC800\uC7A5\uD558\uB294 \uBD88\uBCC0 \uD074\uB798\uC2A4\uC774\uB2E4.\n * \uB85C\uCEEC \uD0C0\uC784\uC874\uC744 \uAE30\uC900\uC73C\uB85C \uB3D9\uC791\uD55C\uB2E4.\n *\n * @example\n * const today = new DateOnly();\n * const specific = new DateOnly(2025, 1, 15);\n * const parsed = DateOnly.parse(\"2025-01-15\");\n */\nexport class DateOnly {\n private static readonly MS_PER_DAY = 24 * 60 * 60 * 1000;\n\n readonly date: Date;\n\n /** \uD604\uC7AC\uC2DC\uAC04 */\n constructor();\n /** \uC5F0\uC6D4\uC77C\uB85C \uCD08\uAE30\uD654 */\n constructor(year: number, month: number, day: number);\n /** tick (millisecond)\uC73C\uB85C \uC0DD\uC131 */\n constructor(tick: number);\n /** Date \uD0C0\uC785\uC73C\uB85C \uC0DD\uC131 */\n constructor(date: Date);\n constructor(arg1?: number | Date, arg2?: number, arg3?: number) {\n if (arg1 === undefined) {\n const tick = Date.now();\n const date = new Date(tick);\n this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n } else if (arg2 !== undefined && arg3 !== undefined) {\n this.date = new Date(arg1 as number, arg2 - 1, arg3);\n } else if (arg1 instanceof Date) {\n const date = arg1;\n this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n } else {\n const date = new Date(arg1);\n this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());\n }\n }\n\n /**\n * \uBB38\uC790\uC5F4\uC744 DateOnly\uB85C \uD30C\uC2F1\n * @param str \uB0A0\uC9DC \uBB38\uC790\uC5F4\n * @returns DateOnly \uC778\uC2A4\uD134\uC2A4\n *\n * \uC9C0\uC6D0 \uD615\uC2DD:\n * - `yyyy-MM-dd` (\uC608: '2024-01-15') - \uBB38\uC790\uC5F4\uC5D0\uC11C \uC9C1\uC811 \uCD94\uCD9C, \uD0C0\uC784\uC874 \uC601\uD5A5 \uC5C6\uC74C\n * - `yyyyMMdd` (\uC608: '20240115') - \uBB38\uC790\uC5F4\uC5D0\uC11C \uC9C1\uC811 \uCD94\uCD9C, \uD0C0\uC784\uC874 \uC601\uD5A5 \uC5C6\uC74C\n * - ISO 8601 (\uC608: '2024-01-15T00:00:00Z') - UTC\uB85C \uD574\uC11D \uD6C4 \uB85C\uCEEC \uD0C0\uC784\uC874 \uBCC0\uD658\n *\n * @note \uC11C\uBC84/\uD074\uB77C\uC774\uC5B8\uD2B8 \uD0C0\uC784\uC874\uC774 \uB2E4\uB978 \uACBD\uC6B0 `yyyy-MM-dd` \uD615\uC2DD \uC0AC\uC6A9 \uAD8C\uC7A5\n * @note DST(\uC77C\uAD11\uC808\uC57D\uC2DC\uAC04) \uC9C0\uC5ED\uC5D0\uC11C ISO 8601 \uD615\uC2DD \uD30C\uC2F1 \uC2DC, \uD30C\uC2F1 \uB300\uC0C1 \uB0A0\uC9DC\uC758 \uC624\uD504\uC14B\uC744 \uC0AC\uC6A9\uD569\uB2C8\uB2E4.\n */\n static parse(str: string): DateOnly {\n // yyyy-MM-dd \uD615\uC2DD (\uD0C0\uC784\uC874 \uC601\uD5A5 \uC5C6\uC74C)\n const matchYMD = /^(\\d{4})-(\\d{2})-(\\d{2})$/.exec(str);\n if (matchYMD != null) {\n return new DateOnly(Number(matchYMD[1]), Number(matchYMD[2]), Number(matchYMD[3]));\n }\n\n // yyyyMMdd \uD615\uC2DD (\uD0C0\uC784\uC874 \uC601\uD5A5 \uC5C6\uC74C)\n const matchCompact = /^(\\d{4})(\\d{2})(\\d{2})$/.exec(str);\n if (matchCompact != null) {\n return new DateOnly(Number(matchCompact[1]), Number(matchCompact[2]), Number(matchCompact[3]));\n }\n\n // ISO 8601 \uB4F1 \uAE30\uD0C0 \uD615\uC2DD (Date.parse \uC0AC\uC6A9, \uD0C0\uC784\uC874 \uBCC0\uD658 \uC801\uC6A9)\n // Date.parse()\uB294 'Z' \uC811\uBBF8\uC0AC\uAC00 \uC788\uB294 ISO 8601\uC744 UTC tick\uC73C\uB85C \uBC18\uD658\n // getTimezoneOffset()\uC740 \"\uB85C\uCEEC\uC5D0\uC11C UTC\uB85C \uBCC0\uD658\uD560 \uB54C \uB354\uD560 \uBD84\"\uC744 \uBC18\uD658 (KST\uB294 -540\uBD84 = UTC+9)\n // \uC5EC\uAE30\uC11C\uB294 \"UTC \u2192 \uB85C\uCEEC\" \uBCC0\uD658\uC774\uBBC0\uB85C \uBD80\uD638\uB97C \uBC18\uB300\uB85C \uC801\uC6A9 (\uBE84\uC148)\n // \uD30C\uC2F1 \uB300\uC0C1 \uB0A0\uC9DC\uC758 \uC624\uD504\uC14B\uC744 \uC0AC\uC6A9\uD558\uC5EC DST \uC9C0\uC5ED\uC5D0\uC11C\uB3C4 \uC815\uD655\uD55C \uBCC0\uD658\n const utcTick = Date.parse(str);\n if (!Number.isNaN(utcTick)) {\n const tempDate = new Date(utcTick);\n const offsetMinutes = tempDate.getTimezoneOffset();\n const localTick = utcTick - offsetMinutes * 60 * 1000;\n return new DateOnly(localTick);\n }\n\n throw new ArgumentError(`\uB0A0\uC9DC \uD615\uC2DD\uC744 \uD30C\uC2F1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC9C0\uC6D0 \uD615\uC2DD: 'yyyy-MM-dd', 'yyyyMMdd', ISO 8601 \uB0A0\uC9DC`, {\n input: str,\n });\n }\n\n //#region \uC8FC\uCC28 \uACC4\uC0B0\n\n /**\n * \uAE30\uC900 \uC5F0\uB3C4\uC640 \uC6D4\uC744 \uC8FC\uCC28 \uC815\uBCF4\uB97C \uAE30\uBC18\uC73C\uB85C \uBC18\uD658\n * @param weekStartDay \uC8FC\uC758 \uC2DC\uC791 \uC694\uC77C (0=\uC77C\uC694\uC77C, 1=\uC6D4\uC694\uC77C, ..., 6=\uD1A0\uC694\uC77C). \uAE30\uBCF8\uAC12: 1(\uC6D4\uC694\uC77C)\n * @param minDaysInFirstWeek \uCCAB \uC8FC\uB85C \uAC04\uC8FC\uD560 \uCD5C\uC18C \uC77C\uC218 (1~7). \uAE30\uBCF8\uAC12: 4 (ISO 8601 \uD45C\uC900)\n * @returns \uD574\uB2F9 \uB0A0\uC9DC\uAC00 \uC18D\uD55C \uC8FC\uCC28\uC758 \uAE30\uC900 \uC5F0\uB3C4\uC640 \uC6D4\n *\n * @example\n * // ISO 8601 \uD45C\uC900 (\uC6D4\uC694\uC77C \uC2DC\uC791, \uCCAB \uC8FC \uCD5C\uC18C 4\uC77C)\n * new DateOnly(2024, 1, 1).getBaseYearMonthSeqForWeekSeq(1, 4)\n * // \uBBF8\uAD6D\uC2DD (\uC77C\uC694\uC77C \uC2DC\uC791, \uCCAB \uC8FC \uCD5C\uC18C 1\uC77C)\n * new DateOnly(2024, 1, 1).getBaseYearMonthSeqForWeekSeq(0, 1)\n */\n getBaseYearMonthSeqForWeekSeq(weekStartDay: number = 1, minDaysInFirstWeek: number = 4) {\n // \uC8FC\uC758 \uC2DC\uC791 \uC694\uC77C \uAE30\uC900\uC73C\uB85C \uD604\uC7AC \uB0A0\uC9DC\uC758 \uC694\uC77C \uC778\uB371\uC2A4 \uACC4\uC0B0 (0 = \uC8FC \uC2DC\uC791\uC77C)\n const dayOfWeek = (this.dayOfWeek + 7 - weekStartDay) % 7;\n // \uD604\uC7AC \uC8FC\uC758 \uB0A8\uC740 \uC77C\uC218 (\uD604\uC7AC \uB0A0\uC9DC \uD3EC\uD568)\n const daysInWeek = 7 - dayOfWeek;\n\n // \uD604\uC7AC \uC8FC\uC758 \uB0A8\uC740 \uC77C\uC218\uAC00 \uCCAB \uC8FC \uCD5C\uC18C \uC77C\uC218 \uBBF8\uB9CC\uC774\uBA74 \uC774\uC804 \uC8FC\uB85C \uAC04\uC8FC\n if (daysInWeek < minDaysInFirstWeek) {\n const prevWeek = this.addDays(-7);\n return { year: prevWeek.year, monthSeq: prevWeek.month };\n } else {\n // \uC6D4 \uACBD\uACC4\uB97C \uACE0\uB824\uD55C \uC2E4\uC81C \uC8FC\uC758 \uB0A8\uC740 \uC77C\uC218 \uACC4\uC0B0\n const nextMonthDate = this.addMonths(1).setDay(1);\n const remainedDays = (nextMonthDate.tick - this.tick) / DateOnly.MS_PER_DAY;\n\n // \uC6D4 \uACBD\uACC4\uAE4C\uC9C0\uC758 \uC2E4\uC81C \uC77C\uC218\uC640 \uC8FC\uC758 \uB0A8\uC740 \uC77C\uC218 \uC911 \uC791\uC740 \uAC12\n const realDaysInWeek = Math.min(daysInWeek, remainedDays);\n // \uC6D4 \uACBD\uACC4 \uACE0\uB824 \uC2DC\uC5D0\uB3C4 \uCCAB \uC8FC \uCD5C\uC18C \uC77C\uC218 \uBBF8\uB9CC\uC774\uBA74 \uB2E4\uC74C \uC8FC\uB85C \uAC04\uC8FC\n if (realDaysInWeek < minDaysInFirstWeek) {\n const nextWeek = this.addDays(7);\n return { year: nextWeek.year, monthSeq: nextWeek.month };\n } else {\n return { year: this.year, monthSeq: this.month };\n }\n }\n }\n\n /**\n * \uC8FC\uCC28 \uC815\uBCF4\uB97C \uAE30\uBC18\uC73C\uB85C \uD574\uB2F9 \uC8FC\uC758 \uC2DC\uC791 \uB0A0\uC9DC \uACC4\uC0B0\n * @param weekStartDay \uC8FC\uC758 \uC2DC\uC791 \uC694\uC77C (0=\uC77C\uC694\uC77C, 1=\uC6D4\uC694\uC77C, ..., 6=\uD1A0\uC694\uC77C). \uAE30\uBCF8\uAC12: 1(\uC6D4\uC694\uC77C)\n * @param minDaysInFirstWeek \uCCAB \uC8FC\uB85C \uAC04\uC8FC\uD560 \uCD5C\uC18C \uC77C\uC218 (1~7). \uAE30\uBCF8\uAC12: 4 (ISO 8601 \uD45C\uC900)\n * @returns \uD574\uB2F9 \uB0A0\uC9DC\uAC00 \uC18D\uD55C \uC8FC\uC758 \uC2DC\uC791 \uB0A0\uC9DC\n */\n getWeekSeqStartDate(weekStartDay: number = 1, minDaysInFirstWeek: number = 4) {\n const dayOfWeek = (this.dayOfWeek + 7 - weekStartDay) % 7;\n const daysInFirstWeek = 7 - dayOfWeek;\n\n if (daysInFirstWeek < minDaysInFirstWeek) {\n return this.addDays(-dayOfWeek + 7);\n } else {\n return this.addDays(-dayOfWeek);\n }\n }\n\n /**\n * \uC5F0\uB3C4 \uBC0F \uC8FC\uCC28 \uC21C\uC11C \uC815\uBCF4\uB97C \uBC18\uD658\n * @param weekStartDay \uC8FC\uC758 \uC2DC\uC791 \uC694\uC77C (0=\uC77C\uC694\uC77C, 1=\uC6D4\uC694\uC77C, ..., 6=\uD1A0\uC694\uC77C). \uAE30\uBCF8\uAC12: 1(\uC6D4\uC694\uC77C)\n * @param minDaysInFirstWeek \uCCAB \uC8FC\uB85C \uAC04\uC8FC\uD560 \uCD5C\uC18C \uC77C\uC218 (1~7). \uAE30\uBCF8\uAC12: 4 (ISO 8601 \uD45C\uC900)\n * @returns \uC5F0\uB3C4\uC640 \uD574\uB2F9 \uC5F0\uB3C4 \uAE30\uC900 \uC8FC\uCC28 \uBC88\uD638\n *\n * @example\n * // ISO 8601 \uD45C\uC900 (\uC6D4\uC694\uC77C \uC2DC\uC791, \uCCAB \uC8FC 4\uC77C \uC774\uC0C1)\n * new DateOnly(2025, 1, 6).getWeekSeqOfYear(); // { year: 2025, weekSeq: 2 }\n *\n * // \uBBF8\uAD6D\uC2DD (\uC77C\uC694\uC77C \uC2DC\uC791, \uCCAB \uC8FC 1\uC77C \uC774\uC0C1)\n * new DateOnly(2025, 1, 1).getWeekSeqOfYear(0, 1); // { year: 2025, weekSeq: 1 }\n */\n getWeekSeqOfYear(weekStartDay: number = 1, minDaysInFirstWeek: number = 4): { year: number; weekSeq: number } {\n const base = this.getBaseYearMonthSeqForWeekSeq(weekStartDay, minDaysInFirstWeek);\n\n const firstWeekStart = new DateOnly(base.year, 1, 1).getWeekSeqStartDate(weekStartDay, minDaysInFirstWeek);\n\n const diffDays = (this.tick - firstWeekStart.tick) / DateOnly.MS_PER_DAY;\n return {\n year: base.year,\n weekSeq: Math.floor(diffDays / 7) + 1,\n };\n }\n\n /**\n * \uD574\uB2F9 \uB0A0\uC9DC\uC758 \uC5F0\uB3C4, \uC6D4 \uBC0F \uC8FC\uCC28(weekSeq) \uC815\uBCF4\uB97C \uBC18\uD658\n * @param weekStartDay \uC8FC\uC758 \uC2DC\uC791 \uC694\uC77C (0=\uC77C\uC694\uC77C, 1=\uC6D4\uC694\uC77C, ..., 6=\uD1A0\uC694\uC77C). \uAE30\uBCF8\uAC12: 1(\uC6D4\uC694\uC77C)\n * @param minDaysInFirstWeek \uCCAB \uC8FC\uB85C \uAC04\uC8FC\uD560 \uCD5C\uC18C \uC77C\uC218 (1~7). \uAE30\uBCF8\uAC12: 4 (ISO 8601 \uD45C\uC900)\n * @returns \uC5F0\uB3C4, \uC6D4 \uBC0F \uD574\uB2F9 \uC6D4 \uAE30\uC900 \uC8FC\uCC28 \uBC88\uD638\n *\n * @example\n * // ISO 8601 \uD45C\uC900 (\uC6D4\uC694\uC77C \uC2DC\uC791, \uCCAB \uC8FC 4\uC77C \uC774\uC0C1)\n * new DateOnly(2025, 1, 15).getWeekSeqOfMonth(); // { year: 2025, monthSeq: 1, weekSeq: 3 }\n *\n * // \uBBF8\uAD6D\uC2DD (\uC77C\uC694\uC77C \uC2DC\uC791, \uCCAB \uC8FC 1\uC77C \uC774\uC0C1)\n * new DateOnly(2025, 1, 15).getWeekSeqOfMonth(0, 1); // { year: 2025, monthSeq: 1, weekSeq: 3 }\n */\n getWeekSeqOfMonth(\n weekStartDay: number = 1,\n minDaysInFirstWeek: number = 4,\n ): { year: number; monthSeq: number; weekSeq: number } {\n const base = this.getBaseYearMonthSeqForWeekSeq(weekStartDay, minDaysInFirstWeek);\n\n const firstWeekStart = new DateOnly(base.year, base.monthSeq, 1).getWeekSeqStartDate(\n weekStartDay,\n minDaysInFirstWeek,\n );\n\n const diffDays = (this.tick - firstWeekStart.tick) / DateOnly.MS_PER_DAY;\n return {\n year: base.year,\n monthSeq: base.monthSeq,\n weekSeq: Math.floor(diffDays / 7) + 1,\n };\n }\n\n /**\n * \uC8FC\uCC28 \uC815\uBCF4\uB97C \uAE30\uBC18\uC73C\uB85C \uD574\uB2F9 \uC8FC\uC758 \uC2DC\uC791 \uB0A0\uC9DC \uAC00\uC838\uC624\uAE30\n * @param arg \uC5F0\uB3C4, \uC120\uD0DD\uC801 \uC6D4, \uC8FC\uCC28 \uBC88\uD638\n * @param weekStartDay \uC8FC\uC758 \uC2DC\uC791 \uC694\uC77C (0=\uC77C\uC694\uC77C, 1=\uC6D4\uC694\uC77C, ..., 6=\uD1A0\uC694\uC77C). \uAE30\uBCF8\uAC12: 1(\uC6D4\uC694\uC77C)\n * @param minDaysInFirstWeek \uCCAB \uC8FC\uB85C \uAC04\uC8FC\uD560 \uCD5C\uC18C \uC77C\uC218 (1~7). \uAE30\uBCF8\uAC12: 4 (ISO 8601 \uD45C\uC900)\n * @returns \uD574\uB2F9 \uC8FC\uCC28\uC758 \uC2DC\uC791 \uB0A0\uC9DC\n *\n * @example\n * // 2025\uB144 2\uC8FC\uCC28\uC758 \uC2DC\uC791\uC77C (ISO 8601 \uD45C\uC900)\n * DateOnly.getDateByYearWeekSeq({ year: 2025, weekSeq: 2 }); // 2025-01-06 (\uC6D4\uC694\uC77C)\n *\n * // 2025\uB144 1\uC6D4 3\uC8FC\uCC28\uC758 \uC2DC\uC791\uC77C\n * DateOnly.getDateByYearWeekSeq({ year: 2025, month: 1, weekSeq: 3 }); // 2025-01-13 (\uC6D4\uC694\uC77C)\n */\n static getDateByYearWeekSeq(\n arg: { year: number; month?: number; weekSeq: number },\n weekStartDay: number = 1,\n minDaysInFirstWeek: number = 4,\n ) {\n return new DateOnly(arg.year, arg.month ?? 1, (arg.weekSeq - 1) * 7 + 1).getWeekSeqStartDate(\n weekStartDay,\n minDaysInFirstWeek,\n );\n }\n\n //#endregion\n\n //#region Getters (\uC77D\uAE30 \uC804\uC6A9)\n\n /** \uB0A0\uC9DC \uC138\uD305\uC774 \uC81C\uB300\uB85C \uB418\uC5C8\uB294\uC9C0 \uC5EC\uBD80 */\n get isValid(): boolean {\n return this.date instanceof Date && !Number.isNaN(this.date.getTime());\n }\n\n get year(): number {\n return this.date.getFullYear();\n }\n\n get month(): number {\n return this.date.getMonth() + 1;\n }\n\n get day(): number {\n return this.date.getDate();\n }\n\n get tick(): number {\n return this.date.getTime();\n }\n\n /** \uC694\uC77C (\uC77C~\uD1A0: 0~6) */\n get dayOfWeek(): number {\n return this.date.getDay();\n }\n\n //#endregion\n\n //#region \uBD88\uBCC0 \uBCC0\uD658 \uBA54\uC11C\uB4DC (\uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658)\n\n /** \uC9C0\uC815\uB41C \uC5F0\uB3C4\uB85C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n setYear(year: number): DateOnly {\n return new DateOnly(year, this.month, this.day);\n }\n\n /**\n * \uC9C0\uC815\uB41C \uC6D4\uB85C \uC0C8 DateOnly \uC778\uC2A4\uD134\uC2A4\uB97C \uBC18\uD658\n * @param month \uC124\uC815\uD560 \uC6D4 (1-12, \uBC94\uC704 \uC678 \uAC12\uC740 \uC5F0\uB3C4 \uC870\uC815)\n * @note \uB300\uC0C1 \uC6D4\uC758 \uC77C\uC218\uBCF4\uB2E4 \uD604\uC7AC \uC77C\uC790\uAC00 \uD06C\uBA74 \uD574\uB2F9 \uC6D4\uC758 \uB9C8\uC9C0\uB9C9 \uB0A0\uB85C \uC870\uC815\uB428\n * (\uC608: 1\uC6D4 31\uC77C\uC5D0\uC11C setMonth(2) \u2192 2\uC6D4 28\uC77C \uB610\uB294 29\uC77C)\n */\n setMonth(month: number): DateOnly {\n const normalized = normalizeMonth(this.year, month, this.day);\n return new DateOnly(normalized.year, normalized.month, normalized.day);\n }\n\n /**\n * \uC9C0\uC815\uB41C \uC77C\uC790\uB85C \uC0C8 DateOnly \uC778\uC2A4\uD134\uC2A4\uB97C \uBC18\uD658\n * @param day \uC124\uC815\uD560 \uC77C\uC790\n * @note \uD574\uB2F9 \uC6D4\uC758 \uC720\uD6A8 \uBC94\uC704\uB97C \uBC97\uC5B4\uB098\uB294 \uC77C\uC790\uB294 JavaScript Date \uAE30\uBCF8 \uB3D9\uC791\uC5D0 \uB530\uB77C\n * \uC790\uB3D9\uC73C\uB85C \uB2E4\uC74C/\uC774\uC804 \uB2EC\uB85C \uC870\uC815\uB428 (\uC608: 1\uC6D4\uC5D0 day=32 \u2192 2\uC6D4 1\uC77C)\n */\n setDay(day: number): DateOnly {\n return new DateOnly(this.year, this.month, day);\n }\n\n //#endregion\n\n //#region \uC0B0\uC220 \uBA54\uC11C\uB4DC (\uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658)\n\n /** \uC9C0\uC815\uB41C \uC5F0\uC218\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addYears(years: number): DateOnly {\n return this.setYear(this.year + years);\n }\n\n /** \uC9C0\uC815\uB41C \uC6D4\uC218\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addMonths(months: number): DateOnly {\n return this.setMonth(this.month + months);\n }\n\n /** \uC9C0\uC815\uB41C \uC77C\uC218\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addDays(days: number): DateOnly {\n return new DateOnly(this.tick + days * DateOnly.MS_PER_DAY);\n }\n\n //#endregion\n\n //#region \uD3EC\uB9F7\uD305\n\n /**\n * \uC9C0\uC815\uB41C \uD3EC\uB9F7\uC73C\uB85C \uBB38\uC790\uC5F4 \uBCC0\uD658\n * @param format \uD3EC\uB9F7 \uBB38\uC790\uC5F4\n * @see dtFormat \uC9C0\uC6D0 \uD3EC\uB9F7 \uBB38\uC790\uC5F4 \uCC38\uC870\n */\n toFormatString(formatStr: string): string {\n return formatDate(formatStr, {\n year: this.year,\n month: this.month,\n day: this.day,\n });\n }\n\n toString(): string {\n return this.toFormatString(\"yyyy-MM-dd\");\n }\n\n //#endregion\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1,96 @@
1
+ /**
2
+ * 날짜시간 클래스 (불변)
3
+ *
4
+ * JavaScript Date 객체를 래핑하여 불변성과 편리한 API를 제공한다.
5
+ * 밀리초 단위까지 지원하며, 로컬 타임존을 기준으로 동작한다.
6
+ *
7
+ * @example
8
+ * const now = new DateTime();
9
+ * const specific = new DateTime(2025, 1, 15, 10, 30, 0);
10
+ * const parsed = DateTime.parse("2025-01-15 10:30:00");
11
+ */
12
+ export declare class DateTime {
13
+ readonly date: Date;
14
+ /** 현재 시간으로 생성 */
15
+ constructor();
16
+ /** 연월일시분초밀리초로 생성 */
17
+ constructor(year: number, month: number, day: number, hour?: number, minute?: number, second?: number, millisecond?: number);
18
+ /** tick (밀리초)으로 생성 */
19
+ constructor(tick: number);
20
+ /** Date 객체로 생성 */
21
+ constructor(date: Date);
22
+ /**
23
+ * 문자열을 파싱하여 DateTime 인스턴스를 생성
24
+ *
25
+ * @param str 날짜시간 문자열
26
+ * @returns 파싱된 DateTime 인스턴스
27
+ * @throws ArgumentError 지원하지 않는 형식인 경우
28
+ *
29
+ * @example
30
+ * DateTime.parse("2025-01-15 10:30:00") // yyyy-MM-dd HH:mm:ss
31
+ * DateTime.parse("2025-01-15 10:30:00.123") // yyyy-MM-dd HH:mm:ss.fff
32
+ * DateTime.parse("20250115103000") // yyyyMMddHHmmss
33
+ * DateTime.parse("2025-01-15 오전 10:30:00") // yyyy-MM-dd 오전/오후 HH:mm:ss
34
+ * DateTime.parse("2025-01-15T10:30:00Z") // ISO 8601
35
+ */
36
+ static parse(str: string): DateTime;
37
+ get year(): number;
38
+ get month(): number;
39
+ get day(): number;
40
+ get hour(): number;
41
+ get minute(): number;
42
+ get second(): number;
43
+ get millisecond(): number;
44
+ get tick(): number;
45
+ /** 요일 (일~토: 0~6) */
46
+ get dayOfWeek(): number;
47
+ get timezoneOffsetMinutes(): number;
48
+ /** 날짜시간 세팅이 제대로 되었는지 여부 */
49
+ get isValid(): boolean;
50
+ /** 지정된 연도로 새 인스턴스 반환 */
51
+ setYear(year: number): DateTime;
52
+ /**
53
+ * 지정된 월로 새 DateTime 인스턴스를 반환
54
+ * @param month 설정할 월 (1-12, 범위 외 값은 연도 조정)
55
+ * @note 대상 월의 일수보다 현재 일자가 크면 해당 월의 마지막 날로 조정됨
56
+ * (예: 1월 31일에서 setMonth(2) → 2월 28일 또는 29일)
57
+ */
58
+ setMonth(month: number): DateTime;
59
+ /**
60
+ * 지정된 일자로 새 DateTime 인스턴스를 반환
61
+ * @param day 설정할 일자
62
+ * @note 해당 월의 유효 범위를 벗어나는 일자는 JavaScript Date 기본 동작에 따라
63
+ * 자동으로 다음/이전 달로 조정됨 (예: 1월에 day=32 → 2월 1일)
64
+ */
65
+ setDay(day: number): DateTime;
66
+ /** 지정된 시로 새 인스턴스 반환 */
67
+ setHour(hour: number): DateTime;
68
+ /** 지정된 분으로 새 인스턴스 반환 */
69
+ setMinute(minute: number): DateTime;
70
+ /** 지정된 초로 새 인스턴스 반환 */
71
+ setSecond(second: number): DateTime;
72
+ /** 지정된 밀리초로 새 인스턴스 반환 */
73
+ setMillisecond(millisecond: number): DateTime;
74
+ /** 지정된 연수를 더한 새 인스턴스 반환 */
75
+ addYears(years: number): DateTime;
76
+ /** 지정된 월수를 더한 새 인스턴스 반환 */
77
+ addMonths(months: number): DateTime;
78
+ /** 지정된 일수를 더한 새 인스턴스 반환 */
79
+ addDays(days: number): DateTime;
80
+ /** 지정된 시간을 더한 새 인스턴스 반환 */
81
+ addHours(hours: number): DateTime;
82
+ /** 지정된 분을 더한 새 인스턴스 반환 */
83
+ addMinutes(minutes: number): DateTime;
84
+ /** 지정된 초를 더한 새 인스턴스 반환 */
85
+ addSeconds(seconds: number): DateTime;
86
+ /** 지정된 밀리초를 더한 새 인스턴스 반환 */
87
+ addMilliseconds(milliseconds: number): DateTime;
88
+ /**
89
+ * 지정된 포맷으로 문자열 변환
90
+ * @param format 포맷 문자열
91
+ * @see dtFormat 지원 포맷 문자열 참조
92
+ */
93
+ toFormatString(formatStr: string): string;
94
+ toString(): string;
95
+ }
96
+ //# sourceMappingURL=date-time.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date-time.d.ts","sourceRoot":"","sources":["../../src/types/date-time.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AACH,qBAAa,QAAQ;IACnB,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAEpB,iBAAiB;;IAEjB,oBAAoB;gBAElB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE,MAAM,EACb,MAAM,CAAC,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,MAAM;IAEtB,sBAAsB;gBACV,IAAI,EAAE,MAAM;IACxB,kBAAkB;gBACN,IAAI,EAAE,IAAI;IAqBtB;;;;;;;;;;;;;OAaG;IACH,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAwDnC,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,KAAK,IAAI,MAAM,CAElB;IAED,IAAI,GAAG,IAAI,MAAM,CAEhB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,MAAM,IAAI,MAAM,CAEnB;IAED,IAAI,WAAW,IAAI,MAAM,CAExB;IAED,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,oBAAoB;IACpB,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED,IAAI,qBAAqB,IAAI,MAAM,CAElC;IAED,2BAA2B;IAC3B,IAAI,OAAO,IAAI,OAAO,CAErB;IAMD,wBAAwB;IACxB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;IAI/B;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IAajC;;;;;OAKG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ;IAI7B,uBAAuB;IACvB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;IAI/B,wBAAwB;IACxB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAInC,uBAAuB;IACvB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAInC,yBAAyB;IACzB,cAAc,CAAC,WAAW,EAAE,MAAM,GAAG,QAAQ;IAQ7C,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IAIjC,2BAA2B;IAC3B,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ;IAInC,2BAA2B;IAC3B,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ;IAI/B,2BAA2B;IAC3B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,QAAQ;IAIjC,0BAA0B;IAC1B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ;IAIrC,0BAA0B;IAC1B,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,QAAQ;IAIrC,4BAA4B;IAC5B,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,QAAQ;IAQ/C;;;;OAIG;IACH,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAazC,QAAQ,IAAI,MAAM;CAKnB"}
@@ -0,0 +1,220 @@
1
+ import { ArgumentError } from "../errors/argument-error";
2
+ import { convert12To24, formatDate, normalizeMonth } from "../utils/date-format";
3
+ class DateTime {
4
+ date;
5
+ constructor(arg1, arg2, arg3, arg4, arg5, arg6, arg7) {
6
+ if (arg1 === void 0) {
7
+ this.date = /* @__PURE__ */ new Date();
8
+ } else if (arg2 !== void 0 && arg3 !== void 0) {
9
+ this.date = new Date(arg1, arg2 - 1, arg3, arg4 ?? 0, arg5 ?? 0, arg6 ?? 0, arg7 ?? 0);
10
+ } else if (arg1 instanceof Date) {
11
+ this.date = new Date(arg1.getTime());
12
+ } else {
13
+ this.date = new Date(arg1);
14
+ }
15
+ }
16
+ /**
17
+ * 문자열을 파싱하여 DateTime 인스턴스를 생성
18
+ *
19
+ * @param str 날짜시간 문자열
20
+ * @returns 파싱된 DateTime 인스턴스
21
+ * @throws ArgumentError 지원하지 않는 형식인 경우
22
+ *
23
+ * @example
24
+ * DateTime.parse("2025-01-15 10:30:00") // yyyy-MM-dd HH:mm:ss
25
+ * DateTime.parse("2025-01-15 10:30:00.123") // yyyy-MM-dd HH:mm:ss.fff
26
+ * DateTime.parse("20250115103000") // yyyyMMddHHmmss
27
+ * DateTime.parse("2025-01-15 오전 10:30:00") // yyyy-MM-dd 오전/오후 HH:mm:ss
28
+ * DateTime.parse("2025-01-15T10:30:00Z") // ISO 8601
29
+ */
30
+ static parse(str) {
31
+ const parsedTick = Date.parse(str);
32
+ if (!Number.isNaN(parsedTick)) {
33
+ return new DateTime(parsedTick);
34
+ }
35
+ const match1 = /^([0-9]{4})-([0-9]{2})-([0-9]{2}) (오전|오후) ([0-9]{1,2}):([0-9]{2}):([0-9]{2})(\.([0-9]{1,3}))?$/.exec(str);
36
+ if (match1 != null) {
37
+ const rawHour = Number(match1[5]);
38
+ const isPM = match1[4] === "\uC624\uD6C4";
39
+ const hour = convert12To24(rawHour, isPM);
40
+ return new DateTime(
41
+ Number(match1[1]),
42
+ Number(match1[2]),
43
+ Number(match1[3]),
44
+ hour,
45
+ Number(match1[6]),
46
+ Number(match1[7]),
47
+ match1[9] ? Number(match1[9].padEnd(3, "0")) : void 0
48
+ );
49
+ }
50
+ const match2 = /^[0-9]{14}$/.exec(str);
51
+ if (match2 != null) {
52
+ return new DateTime(
53
+ Number(str.substring(0, 4)),
54
+ Number(str.substring(4, 6)),
55
+ Number(str.substring(6, 8)),
56
+ Number(str.substring(8, 10)),
57
+ Number(str.substring(10, 12)),
58
+ Number(str.substring(12, 14))
59
+ );
60
+ }
61
+ const match3 = /^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})(\.([0-9]{1,3}))?$/.exec(str);
62
+ if (match3 != null) {
63
+ return new DateTime(
64
+ Number(match3[1]),
65
+ Number(match3[2]),
66
+ Number(match3[3]),
67
+ Number(match3[4]),
68
+ Number(match3[5]),
69
+ Number(match3[6]),
70
+ match3[8] ? Number(match3[8].padEnd(3, "0")) : void 0
71
+ );
72
+ }
73
+ throw new ArgumentError(
74
+ `\uB0A0\uC9DC\uC2DC\uAC04 \uD615\uC2DD\uC744 \uD30C\uC2F1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC9C0\uC6D0 \uD615\uC2DD: 'yyyy-MM-dd HH:mm:ss', 'yyyyMMddHHmmss', 'yyyy-MM-dd \uC624\uC804/\uC624\uD6C4 HH:mm:ss', ISO 8601`,
75
+ { input: str }
76
+ );
77
+ }
78
+ //#region Getters (읽기 전용)
79
+ get year() {
80
+ return this.date.getFullYear();
81
+ }
82
+ get month() {
83
+ return this.date.getMonth() + 1;
84
+ }
85
+ get day() {
86
+ return this.date.getDate();
87
+ }
88
+ get hour() {
89
+ return this.date.getHours();
90
+ }
91
+ get minute() {
92
+ return this.date.getMinutes();
93
+ }
94
+ get second() {
95
+ return this.date.getSeconds();
96
+ }
97
+ get millisecond() {
98
+ return this.date.getMilliseconds();
99
+ }
100
+ get tick() {
101
+ return this.date.getTime();
102
+ }
103
+ /** 요일 (일~토: 0~6) */
104
+ get dayOfWeek() {
105
+ return this.date.getDay();
106
+ }
107
+ get timezoneOffsetMinutes() {
108
+ return -this.date.getTimezoneOffset();
109
+ }
110
+ /** 날짜시간 세팅이 제대로 되었는지 여부 */
111
+ get isValid() {
112
+ return this.date instanceof Date && !Number.isNaN(this.date.getTime());
113
+ }
114
+ //#endregion
115
+ //#region 불변 변환 메서드 (새 인스턴스 반환)
116
+ /** 지정된 연도로 새 인스턴스 반환 */
117
+ setYear(year) {
118
+ return new DateTime(year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);
119
+ }
120
+ /**
121
+ * 지정된 월로 새 DateTime 인스턴스를 반환
122
+ * @param month 설정할 월 (1-12, 범위 외 값은 연도 조정)
123
+ * @note 대상 월의 일수보다 현재 일자가 크면 해당 월의 마지막 날로 조정됨
124
+ * (예: 1월 31일에서 setMonth(2) → 2월 28일 또는 29일)
125
+ */
126
+ setMonth(month) {
127
+ const normalized = normalizeMonth(this.year, month, this.day);
128
+ return new DateTime(
129
+ normalized.year,
130
+ normalized.month,
131
+ normalized.day,
132
+ this.hour,
133
+ this.minute,
134
+ this.second,
135
+ this.millisecond
136
+ );
137
+ }
138
+ /**
139
+ * 지정된 일자로 새 DateTime 인스턴스를 반환
140
+ * @param day 설정할 일자
141
+ * @note 해당 월의 유효 범위를 벗어나는 일자는 JavaScript Date 기본 동작에 따라
142
+ * 자동으로 다음/이전 달로 조정됨 (예: 1월에 day=32 → 2월 1일)
143
+ */
144
+ setDay(day) {
145
+ return new DateTime(this.year, this.month, day, this.hour, this.minute, this.second, this.millisecond);
146
+ }
147
+ /** 지정된 시로 새 인스턴스 반환 */
148
+ setHour(hour) {
149
+ return new DateTime(this.year, this.month, this.day, hour, this.minute, this.second, this.millisecond);
150
+ }
151
+ /** 지정된 분으로 새 인스턴스 반환 */
152
+ setMinute(minute) {
153
+ return new DateTime(this.year, this.month, this.day, this.hour, minute, this.second, this.millisecond);
154
+ }
155
+ /** 지정된 초로 새 인스턴스 반환 */
156
+ setSecond(second) {
157
+ return new DateTime(this.year, this.month, this.day, this.hour, this.minute, second, this.millisecond);
158
+ }
159
+ /** 지정된 밀리초로 새 인스턴스 반환 */
160
+ setMillisecond(millisecond) {
161
+ return new DateTime(this.year, this.month, this.day, this.hour, this.minute, this.second, millisecond);
162
+ }
163
+ //#endregion
164
+ //#region 산술 메서드 (새 인스턴스 반환)
165
+ /** 지정된 연수를 더한 새 인스턴스 반환 */
166
+ addYears(years) {
167
+ return this.setYear(this.year + years);
168
+ }
169
+ /** 지정된 월수를 더한 새 인스턴스 반환 */
170
+ addMonths(months) {
171
+ return this.setMonth(this.month + months);
172
+ }
173
+ /** 지정된 일수를 더한 새 인스턴스 반환 */
174
+ addDays(days) {
175
+ return new DateTime(this.tick + days * 24 * 60 * 60 * 1e3);
176
+ }
177
+ /** 지정된 시간을 더한 새 인스턴스 반환 */
178
+ addHours(hours) {
179
+ return new DateTime(this.tick + hours * 60 * 60 * 1e3);
180
+ }
181
+ /** 지정된 분을 더한 새 인스턴스 반환 */
182
+ addMinutes(minutes) {
183
+ return new DateTime(this.tick + minutes * 60 * 1e3);
184
+ }
185
+ /** 지정된 초를 더한 새 인스턴스 반환 */
186
+ addSeconds(seconds) {
187
+ return new DateTime(this.tick + seconds * 1e3);
188
+ }
189
+ /** 지정된 밀리초를 더한 새 인스턴스 반환 */
190
+ addMilliseconds(milliseconds) {
191
+ return new DateTime(this.tick + milliseconds);
192
+ }
193
+ //#endregion
194
+ //#region 포맷팅
195
+ /**
196
+ * 지정된 포맷으로 문자열 변환
197
+ * @param format 포맷 문자열
198
+ * @see dtFormat 지원 포맷 문자열 참조
199
+ */
200
+ toFormatString(formatStr) {
201
+ return formatDate(formatStr, {
202
+ year: this.year,
203
+ month: this.month,
204
+ day: this.day,
205
+ hour: this.hour,
206
+ minute: this.minute,
207
+ second: this.second,
208
+ millisecond: this.millisecond,
209
+ timezoneOffsetMinutes: this.timezoneOffsetMinutes
210
+ });
211
+ }
212
+ toString() {
213
+ return this.toFormatString("yyyy-MM-ddTHH:mm:ss.fffzzz");
214
+ }
215
+ //#endregion
216
+ }
217
+ export {
218
+ DateTime
219
+ };
220
+ //# sourceMappingURL=date-time.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/types/date-time.ts"],
4
+ "sourcesContent": ["import { ArgumentError } from \"../errors/argument-error\";\nimport { convert12To24, formatDate, normalizeMonth } from \"../utils/date-format\";\n\n/**\n * \uB0A0\uC9DC\uC2DC\uAC04 \uD074\uB798\uC2A4 (\uBD88\uBCC0)\n *\n * JavaScript Date \uAC1D\uCCB4\uB97C \uB798\uD551\uD558\uC5EC \uBD88\uBCC0\uC131\uACFC \uD3B8\uB9AC\uD55C API\uB97C \uC81C\uACF5\uD55C\uB2E4.\n * \uBC00\uB9AC\uCD08 \uB2E8\uC704\uAE4C\uC9C0 \uC9C0\uC6D0\uD558\uBA70, \uB85C\uCEEC \uD0C0\uC784\uC874\uC744 \uAE30\uC900\uC73C\uB85C \uB3D9\uC791\uD55C\uB2E4.\n *\n * @example\n * const now = new DateTime();\n * const specific = new DateTime(2025, 1, 15, 10, 30, 0);\n * const parsed = DateTime.parse(\"2025-01-15 10:30:00\");\n */\nexport class DateTime {\n readonly date: Date;\n\n /** \uD604\uC7AC \uC2DC\uAC04\uC73C\uB85C \uC0DD\uC131 */\n constructor();\n /** \uC5F0\uC6D4\uC77C\uC2DC\uBD84\uCD08\uBC00\uB9AC\uCD08\uB85C \uC0DD\uC131 */\n constructor(\n year: number,\n month: number,\n day: number,\n hour?: number,\n minute?: number,\n second?: number,\n millisecond?: number,\n );\n /** tick (\uBC00\uB9AC\uCD08)\uC73C\uB85C \uC0DD\uC131 */\n constructor(tick: number);\n /** Date \uAC1D\uCCB4\uB85C \uC0DD\uC131 */\n constructor(date: Date);\n constructor(\n arg1?: number | Date,\n arg2?: number,\n arg3?: number,\n arg4?: number,\n arg5?: number,\n arg6?: number,\n arg7?: number,\n ) {\n if (arg1 === undefined) {\n this.date = new Date();\n } else if (arg2 !== undefined && arg3 !== undefined) {\n this.date = new Date(arg1 as number, arg2 - 1, arg3, arg4 ?? 0, arg5 ?? 0, arg6 ?? 0, arg7 ?? 0);\n } else if (arg1 instanceof Date) {\n this.date = new Date(arg1.getTime());\n } else {\n this.date = new Date(arg1);\n }\n }\n\n /**\n * \uBB38\uC790\uC5F4\uC744 \uD30C\uC2F1\uD558\uC5EC DateTime \uC778\uC2A4\uD134\uC2A4\uB97C \uC0DD\uC131\n *\n * @param str \uB0A0\uC9DC\uC2DC\uAC04 \uBB38\uC790\uC5F4\n * @returns \uD30C\uC2F1\uB41C DateTime \uC778\uC2A4\uD134\uC2A4\n * @throws ArgumentError \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uB294 \uD615\uC2DD\uC778 \uACBD\uC6B0\n *\n * @example\n * DateTime.parse(\"2025-01-15 10:30:00\") // yyyy-MM-dd HH:mm:ss\n * DateTime.parse(\"2025-01-15 10:30:00.123\") // yyyy-MM-dd HH:mm:ss.fff\n * DateTime.parse(\"20250115103000\") // yyyyMMddHHmmss\n * DateTime.parse(\"2025-01-15 \uC624\uC804 10:30:00\") // yyyy-MM-dd \uC624\uC804/\uC624\uD6C4 HH:mm:ss\n * DateTime.parse(\"2025-01-15T10:30:00Z\") // ISO 8601\n */\n static parse(str: string): DateTime {\n const parsedTick = Date.parse(str);\n if (!Number.isNaN(parsedTick)) {\n return new DateTime(parsedTick);\n }\n\n const match1 =\n /^([0-9]{4})-([0-9]{2})-([0-9]{2}) (\uC624\uC804|\uC624\uD6C4) ([0-9]{1,2}):([0-9]{2}):([0-9]{2})(\\.([0-9]{1,3}))?$/.exec(str);\n if (match1 != null) {\n const rawHour = Number(match1[5]);\n const isPM = match1[4] === \"\uC624\uD6C4\";\n const hour = convert12To24(rawHour, isPM);\n return new DateTime(\n Number(match1[1]),\n Number(match1[2]),\n Number(match1[3]),\n hour,\n Number(match1[6]),\n Number(match1[7]),\n match1[9] ? Number(match1[9].padEnd(3, \"0\")) : undefined,\n );\n }\n\n const match2 = /^[0-9]{14}$/.exec(str);\n if (match2 != null) {\n return new DateTime(\n Number(str.substring(0, 4)),\n Number(str.substring(4, 6)),\n Number(str.substring(6, 8)),\n Number(str.substring(8, 10)),\n Number(str.substring(10, 12)),\n Number(str.substring(12, 14)),\n );\n }\n\n const match3 = /^([0-9]{4})-([0-9]{2})-([0-9]{2}) ([0-9]{2}):([0-9]{2}):([0-9]{2})(\\.([0-9]{1,3}))?$/.exec(str);\n if (match3 != null) {\n return new DateTime(\n Number(match3[1]),\n Number(match3[2]),\n Number(match3[3]),\n Number(match3[4]),\n Number(match3[5]),\n Number(match3[6]),\n match3[8] ? Number(match3[8].padEnd(3, \"0\")) : undefined,\n );\n }\n\n throw new ArgumentError(\n `\uB0A0\uC9DC\uC2DC\uAC04 \uD615\uC2DD\uC744 \uD30C\uC2F1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uC9C0\uC6D0 \uD615\uC2DD: 'yyyy-MM-dd HH:mm:ss', 'yyyyMMddHHmmss', 'yyyy-MM-dd \uC624\uC804/\uC624\uD6C4 HH:mm:ss', ISO 8601`,\n { input: str },\n );\n }\n\n //#region Getters (\uC77D\uAE30 \uC804\uC6A9)\n\n get year(): number {\n return this.date.getFullYear();\n }\n\n get month(): number {\n return this.date.getMonth() + 1;\n }\n\n get day(): number {\n return this.date.getDate();\n }\n\n get hour(): number {\n return this.date.getHours();\n }\n\n get minute(): number {\n return this.date.getMinutes();\n }\n\n get second(): number {\n return this.date.getSeconds();\n }\n\n get millisecond(): number {\n return this.date.getMilliseconds();\n }\n\n get tick(): number {\n return this.date.getTime();\n }\n\n /** \uC694\uC77C (\uC77C~\uD1A0: 0~6) */\n get dayOfWeek(): number {\n return this.date.getDay();\n }\n\n get timezoneOffsetMinutes(): number {\n return -this.date.getTimezoneOffset();\n }\n\n /** \uB0A0\uC9DC\uC2DC\uAC04 \uC138\uD305\uC774 \uC81C\uB300\uB85C \uB418\uC5C8\uB294\uC9C0 \uC5EC\uBD80 */\n get isValid(): boolean {\n return this.date instanceof Date && !Number.isNaN(this.date.getTime());\n }\n\n //#endregion\n\n //#region \uBD88\uBCC0 \uBCC0\uD658 \uBA54\uC11C\uB4DC (\uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658)\n\n /** \uC9C0\uC815\uB41C \uC5F0\uB3C4\uB85C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n setYear(year: number): DateTime {\n return new DateTime(year, this.month, this.day, this.hour, this.minute, this.second, this.millisecond);\n }\n\n /**\n * \uC9C0\uC815\uB41C \uC6D4\uB85C \uC0C8 DateTime \uC778\uC2A4\uD134\uC2A4\uB97C \uBC18\uD658\n * @param month \uC124\uC815\uD560 \uC6D4 (1-12, \uBC94\uC704 \uC678 \uAC12\uC740 \uC5F0\uB3C4 \uC870\uC815)\n * @note \uB300\uC0C1 \uC6D4\uC758 \uC77C\uC218\uBCF4\uB2E4 \uD604\uC7AC \uC77C\uC790\uAC00 \uD06C\uBA74 \uD574\uB2F9 \uC6D4\uC758 \uB9C8\uC9C0\uB9C9 \uB0A0\uB85C \uC870\uC815\uB428\n * (\uC608: 1\uC6D4 31\uC77C\uC5D0\uC11C setMonth(2) \u2192 2\uC6D4 28\uC77C \uB610\uB294 29\uC77C)\n */\n setMonth(month: number): DateTime {\n const normalized = normalizeMonth(this.year, month, this.day);\n return new DateTime(\n normalized.year,\n normalized.month,\n normalized.day,\n this.hour,\n this.minute,\n this.second,\n this.millisecond,\n );\n }\n\n /**\n * \uC9C0\uC815\uB41C \uC77C\uC790\uB85C \uC0C8 DateTime \uC778\uC2A4\uD134\uC2A4\uB97C \uBC18\uD658\n * @param day \uC124\uC815\uD560 \uC77C\uC790\n * @note \uD574\uB2F9 \uC6D4\uC758 \uC720\uD6A8 \uBC94\uC704\uB97C \uBC97\uC5B4\uB098\uB294 \uC77C\uC790\uB294 JavaScript Date \uAE30\uBCF8 \uB3D9\uC791\uC5D0 \uB530\uB77C\n * \uC790\uB3D9\uC73C\uB85C \uB2E4\uC74C/\uC774\uC804 \uB2EC\uB85C \uC870\uC815\uB428 (\uC608: 1\uC6D4\uC5D0 day=32 \u2192 2\uC6D4 1\uC77C)\n */\n setDay(day: number): DateTime {\n return new DateTime(this.year, this.month, day, this.hour, this.minute, this.second, this.millisecond);\n }\n\n /** \uC9C0\uC815\uB41C \uC2DC\uB85C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n setHour(hour: number): DateTime {\n return new DateTime(this.year, this.month, this.day, hour, this.minute, this.second, this.millisecond);\n }\n\n /** \uC9C0\uC815\uB41C \uBD84\uC73C\uB85C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n setMinute(minute: number): DateTime {\n return new DateTime(this.year, this.month, this.day, this.hour, minute, this.second, this.millisecond);\n }\n\n /** \uC9C0\uC815\uB41C \uCD08\uB85C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n setSecond(second: number): DateTime {\n return new DateTime(this.year, this.month, this.day, this.hour, this.minute, second, this.millisecond);\n }\n\n /** \uC9C0\uC815\uB41C \uBC00\uB9AC\uCD08\uB85C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n setMillisecond(millisecond: number): DateTime {\n return new DateTime(this.year, this.month, this.day, this.hour, this.minute, this.second, millisecond);\n }\n\n //#endregion\n\n //#region \uC0B0\uC220 \uBA54\uC11C\uB4DC (\uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658)\n\n /** \uC9C0\uC815\uB41C \uC5F0\uC218\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addYears(years: number): DateTime {\n return this.setYear(this.year + years);\n }\n\n /** \uC9C0\uC815\uB41C \uC6D4\uC218\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addMonths(months: number): DateTime {\n return this.setMonth(this.month + months);\n }\n\n /** \uC9C0\uC815\uB41C \uC77C\uC218\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addDays(days: number): DateTime {\n return new DateTime(this.tick + days * 24 * 60 * 60 * 1000);\n }\n\n /** \uC9C0\uC815\uB41C \uC2DC\uAC04\uC744 \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addHours(hours: number): DateTime {\n return new DateTime(this.tick + hours * 60 * 60 * 1000);\n }\n\n /** \uC9C0\uC815\uB41C \uBD84\uC744 \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addMinutes(minutes: number): DateTime {\n return new DateTime(this.tick + minutes * 60 * 1000);\n }\n\n /** \uC9C0\uC815\uB41C \uCD08\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addSeconds(seconds: number): DateTime {\n return new DateTime(this.tick + seconds * 1000);\n }\n\n /** \uC9C0\uC815\uB41C \uBC00\uB9AC\uCD08\uB97C \uB354\uD55C \uC0C8 \uC778\uC2A4\uD134\uC2A4 \uBC18\uD658 */\n addMilliseconds(milliseconds: number): DateTime {\n return new DateTime(this.tick + milliseconds);\n }\n\n //#endregion\n\n //#region \uD3EC\uB9F7\uD305\n\n /**\n * \uC9C0\uC815\uB41C \uD3EC\uB9F7\uC73C\uB85C \uBB38\uC790\uC5F4 \uBCC0\uD658\n * @param format \uD3EC\uB9F7 \uBB38\uC790\uC5F4\n * @see dtFormat \uC9C0\uC6D0 \uD3EC\uB9F7 \uBB38\uC790\uC5F4 \uCC38\uC870\n */\n toFormatString(formatStr: string): string {\n return formatDate(formatStr, {\n year: this.year,\n month: this.month,\n day: this.day,\n hour: this.hour,\n minute: this.minute,\n second: this.second,\n millisecond: this.millisecond,\n timezoneOffsetMinutes: this.timezoneOffsetMinutes,\n });\n }\n\n toString(): string {\n return this.toFormatString(\"yyyy-MM-ddTHH:mm:ss.fffzzz\");\n }\n\n //#endregion\n}\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }