출처 : http://www.javaclue.org/pub/java/dateutil/DateUtil.java.txt
1 /**
2 * @(#)DateUtil.java v1.1 19-Nov-2002
3 *
4 * 날짜 계산에 유용한 여러가지 메소드.
5 *
6 *
7 * public static int[] getMonthDaysArray(int yr)
8 * 지정한 년도의 각 달에 포함된 날수의 배열을 구하는 메소드
9 *
10 * public static int getDaysInYear(int y)
11 * 지정한 년도에 포함된 날수 구하는 메소드
12 *
13 * public static int getDaysInMonth(int m, int y)
14 * 지정한 년도의 지정한 달에 포함된 날수 구하는 메소드
15 *
16 * public static int getDaysFromMonthFirst(int d, int m, int y)
17 * public static int getDaysFromMonthFirst(String s)
18 * 지정한 년도의 1월 1일 이후에 경과한 날수 구하는 메소드
19 * 만약 지정한 날짜가 유효한 범위를 벗어나면 예외상황을 던진다.
20 *
21 * public static int getDaysFromYearFirst(int d, int m, int y)
22 * public static int getDaysFromYearFirst(String s)
23 * 지정한 년도의 1월 1일 이후에 경과한 날수 구하는 메소드
24 *
25 * public static int getDaysFrom21Century(int d, int m, int y)
26 * public static int getDaysFrom21Century(String s)
27 * 2000년 1월 1일 이후에 경과한 날수 구하는 메소드
28 *
29 * public static int getDaysBetween(String s1, String s2)
30 * 지정한 두 날짜의 (양 끝 제외) 날짜 차이 구하는 메소드
31 *
32 * public static int getDaysDiff(String s1, String s2)
33 * 지정한 두 날짜의 날짜 차이 구하는 메소드
34 *
35 * public static int getDaysFromTo(String s1, String s2)
36 * 지정한 두 날짜의 (양 끝 포함) 날짜 차이 구하는 메소드
37 *
38 * public static int getWeekdaysInMonth(int weekDay, int m, int y)
39 * public static int getWeekdaysInMonth(String weekName, int m, int y)
40 * 지정한 년도의 지정한 달에 포함된 지정한 요일의 개수 구하는 메소드
41 *
42 * public static String getDateStringFrom21Century(int elapsed)
43 * 2000년 1월 이후 elapsed일 경과한 날짜를 String 타입으로는 메소드
44 *
45 * public static String addDate(int offset, int d, int m, int y)
46 * public static String addDate(int offset, String date)
47 * 지정한 날짜 이후 지정한 offset일 경과한 날짜를 String 타입으로는 메소드
48 *
49 *
50 * [참고 1] 그레고리식 달력은 1582 년도 10월 달력이 비정상적이다.
51 * 즉, 10월 4일 다음 날이 10월 15일이었다. 그러므로,
52 * 그 달은 열흘이 부족한 21일이 한달이었다.
53 *
54 * [참고 2] 영국식 달력은 1752 년도 9월 달력이 비정상적이다.
55 * 즉, 9월 2일 다음 날이 9월 14일이었다. 그러므로,
56 * 그 달은 열하루가 부족한 19일이 한달이었다.
57 *
58 *
59 * @date 10-Sep-2002 (ver 1.0) DateDiffTest.java
60 * @date 19-Nov-2002 (ver 1.1)
61 * @author Pilho Kim (phkim at cluecom.co.kr)
62 */
63
64 import java.util.*;
65 import java.io.*;
66
67 public class DateUtil {
68
69 ////////////////////////////////////////////////////////////////////////////
70 // 일년 간 달력의 월별 날짜수 배열을 구한다.
71 //
72 public static int[] getMonthDaysArray(int yr) {
73 int[] a1 = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
74 int[] a2 = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
75
76 if (yr <= 1582) {
77 if ((yr % 4) == 0) {
78 if (yr == 4) {
79 return a1;
80 }
81 return a2;
82 }
83 }
84 else {
85 if (((yr % 4) == 0) && ((yr % 100) != 0)) {
86 return a2;
87 }
88 else if ((yr % 400) == 0) {
89 return a2;
90 }
91 }
92
93 return a1;
94 }
95
96
97 ////////////////////////////////////////////////////////////////////////////
98 // 지정된 년도와 달에 따른 요일 편차를 구한다.
99 //
100 public static int addWeekDays(int y, int m) {
101 int[] b1 = { 3, 0, 3, 2, 3, 2, 3, 3, 2, 3, 2, 3 };
102 int[] b2 = { 3, 1, 3, 2, 3, 2, 3, 3, 2, 3, 2, 3 };
103 int i = 0;
104 int rval = 0;
105
106 if (y <= 1582) {
107 if ((y % 4) == 0) {
108 if (y == 4) {
109 for (i = 0; i < m - 1; i++)
110 rval += b1[i];
111 }
112 else {
113 for (i = 0; i < m - 1; i++)
114 rval += b2[i];
115 }
116 }
117 else {
118 for (i = 0; i < m - 1; i++)
119 rval += b1[i];
120 }
121 }
122 else {
123 if (((y % 4) == 0) && ((y % 100) != 0)) {
124 for (i = 0; i < m - 1; i++)
125 rval += b2[i];
126 }
127 else if ((y % 400) == 0) {
128 for (i = 0; i < m - 1; i++)
129 rval += b2[i];
130 }
131 else {
132 for (i = 0; i < m - 1; i++)
133 rval += b1[i];
134 }
135 }
136
137 return rval;
138 }
139
140
141 ////////////////////////////////////////////////////////////////////////////
142 // 지정한 년도의 총 날짜 수를 구한다.
143 //
144 public static int getDaysInYear(int y) {
145 if (y > 1582) {
146 if (y % 400 == 0)
147 return 366;
148 else if (y % 100 == 0)
149 return 365;
150 else if (y % 4 == 0)
151 return 366;
152 else
153 return 365;
154 }
155 else if (y == 1582)
156 return 355;
157 else if (y > 4) {
158 if (y % 4 == 0)
159 return 366;
160 else
161 return 365;
162 }
163 else if (y > 0)
164 return 365;
165 else
166 return 0;
167 }
168
169
170 ////////////////////////////////////////////////////////////////////////////
171 // 지정한 년도, 지정한 월의 총 날짜 수를 구한다.
172 //
173 public static int getDaysInMonth(int m, int y) {
174 if (m < 1 || m > 12)
175 throw new RuntimeException("Invalid month: " + m);
176
177 int[] b = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
178 if (m != 2 && m >= 1 && m <= 12 && y != 1582)
179 return b[m - 1];
180 if (m != 2 && m >= 1 && m <= 12 && y == 1582)
181 if (m != 10)
182 return b[m - 1];
183 else
184 return b[m - 1] - 10;
185
186 if (m != 2)
187 return 0;
188
189 // m == 2 (즉 2월)
190 if (y > 1582) {
191 if (y % 400 == 0)
192 return 29;
193 else if (y % 100 == 0)
194 return 28;
195 else if (y % 4 == 0)
196 return 29;
197 else
198 return 28;
199 }
200 else if (y == 1582)
201 return 28;
202 else if (y > 4) {
203 if (y % 4 == 0)
204 return 29;
205 else
206 return 28;
207 }
208 else if (y > 0)
209 return 28;
210 else
211 throw new RuntimeException("Invalid year: " + y);
212 }
213
214
215 ////////////////////////////////////////////////////////////////////////////
216 // 지정한 년도의 지정한 월의 첫날 부터 지정한 날 까지의 날짜 수를 구한다.
217 //
218 public static int getDaysFromMonthFirst(int d, int m, int y) {
219 if (m < 1 || m > 12)
220 throw new RuntimeException("Invalid month " + m + " in " + d + "/" + m + "/" + y);
221
222 int max = getDaysInMonth(m, y);
223 if (d >= 1 && d <= max)
224 return d;
225 else
226 throw new RuntimeException("Invalid date " + d + " in " + d + "/" + m + "/" + y);
227 }
228
229
230 ////////////////////////////////////////////////////////////////////////////
231 // 지정한 년도의 첫날 부터 지정한 월의 지정한 날 까지의 날짜 수를 구한다.
232 //
233 public static int getDaysFromYearFirst(int d, int m, int y) {
234 if (m < 1 || m > 12)
235 throw new RuntimeException("Invalid month " + m + " in " + d + "/" + m + "/" + y);
236
237 int max = getDaysInMonth(m, y);
238 if (d >= 1 && d <= max) {
239 int sum = d;
240 for (int j = 1; j < m; j++)
241 sum += getDaysInMonth(j, y);
242 return sum;
243 }
244 else
245 throw new RuntimeException("Invalid date " + d + " in " + d + "/" + m + "/" + y);
246 }
247
248 ////////////////////////////////////////////////////////////////////////////
249 // 2000년 1월 1일 부터 지정한 년, 월, 일 까지의 날짜 수를 구한다.
250 // 2000년 1월 1일 이전의 경우에는 음수를 리턴한다.
251 //
252 public static int getDaysFrom21Century(int d, int m, int y) {
253 if (y >= 2000) {
254 int sum = getDaysFromYearFirst(d, m, y);
255 for (int j = y - 1; j >= 2000; j--)
256 sum += getDaysInYear(j);
257 return sum - 1;
258 }
259 else if (y > 0 && y < 2000) {
260 int sum = getDaysFromYearFirst(d, m, y);
261 for (int j = 1999; j >= y; j--)
262 sum -= getDaysInYear(y);
263 return sum - 1;
264 }
265 else
266 throw new RuntimeException("Invalid year " + y + " in " + d + "/" + m + "/" + y);
267 }
268
269
270
271 ////////////////////////////////////////////////////////////////////////////
272 // 지정한 년도의 지정한 월의 첫날 부터 지정한 날 까지의 날짜 수를 구한다.
273 //
274 public static int getDaysFromMonthFirst(String s) {
275 int d, m, y;
276 if (s.length() == 8) {
277 y = Integer.parseInt(s.substring(0, 4));
278 m = Integer.parseInt(s.substring(4, 6));
279 d = Integer.parseInt(s.substring(6));
280 return getDaysFromMonthFirst(d, m, y);
281 }
282 else if (s.length() == 10) {
283 y = Integer.parseInt(s.substring(0, 4));
284 m = Integer.parseInt(s.substring(5, 7));
285 d = Integer.parseInt(s.substring(8));
286 return getDaysFromMonthFirst(d, m, y);
287 }
288 else if (s.length() == 11) {
289 d = Integer.parseInt(s.substring(0, 2));
290 String strM = s.substring(3, 6).toUpperCase();
291 String[] monthNames = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
292 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
293 m = 0;
294 for (int j = 1; j <= 12; j++) {
295 if (strM.equals(monthNames[j-1])) {
296 m = j;
297 break;
298 }
299 }
300 if (m < 1 || m > 12)
301 throw new RuntimeException("Invalid month name: " + strM + " in " + s);
302 y = Integer.parseInt(s.substring(7));
303 return getDaysFromMonthFirst(d, m, y);
304 }
305 else
306 throw new RuntimeException("Invalid date format: " + s);
307 }
308
309
310 ////////////////////////////////////////////////////////////////////////////
311 // 지정한 년도의 첫날 부터 지정한 월의 지정한 날 까지의 날짜 수를 구한다.
312 //
313 public static int getDaysFromYearFirst(String s) {
314 int d, m, y;
315 if (s.length() == 8) {
316 y = Integer.parseInt(s.substring(0, 4));
317 m = Integer.parseInt(s.substring(4, 6));
318 d = Integer.parseInt(s.substring(6));
319 return getDaysFromYearFirst(d, m, y);
320 }
321 else if (s.length() == 10) {
322 y = Integer.parseInt(s.substring(0, 4));
323 m = Integer.parseInt(s.substring(5, 7));
324 d = Integer.parseInt(s.substring(8));
325 return getDaysFromYearFirst(d, m, y);
326 }
327 else if (s.length() == 11) {
328 d = Integer.parseInt(s.substring(0, 2));
329 String strM = s.substring(3, 6).toUpperCase();
330 String[] monthNames = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
331 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
332 m = 0;
333 for (int j = 1; j <= 12; j++) {
334 if (strM.equals(monthNames[j-1])) {
335 m = j;
336 break;
337 }
338 }
339 if (m < 1 || m > 12)
340 throw new RuntimeException("Invalid month name: " + strM + " in " + s);
341 y = Integer.parseInt(s.substring(7));
342 return getDaysFromYearFirst(d, m, y);
343 }
344 else
345 throw new RuntimeException("Invalid date format: " + s);
346 }
347
348
349 //////////////////////////////////////////////////////////////////////
350 // 2000년 1월 1일 부터 지정한 년, 월, 일 까지의 날짜 수를 구한다.
351 // 2000년 1월 1일 이전의 경우에는 음수를 리턴한다.
352 //
353 public static int getDaysFrom21Century(String s) {
354 int d, m, y;
355 if (s.length() == 8) {
356 y = Integer.parseInt(s.substring(0, 4));
357 m = Integer.parseInt(s.substring(4, 6));
358 d = Integer.parseInt(s.substring(6));
359 return getDaysFrom21Century(d, m, y);
360 }
361 else if (s.length() == 10) {
362 y = Integer.parseInt(s.substring(0, 4));
363 m = Integer.parseInt(s.substring(5, 7));
364 d = Integer.parseInt(s.substring(8));
365 return getDaysFrom21Century(d, m, y);
366 }
367 else if (s.length() == 11) {
368 d = Integer.parseInt(s.substring(0, 2));
369 String strM = s.substring(3, 6).toUpperCase();
370 String[] monthNames = { "JAN", "FEB", "MAR", "APR", "MAY", "JUN",
371 "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
372 m = 0;
373 for (int j = 1; j <= 12; j++) {
374 if (strM.equals(monthNames[j-1])) {
375 m = j;
376 break;
377 }
378 }
379 if (m < 1 || m > 12)
380 throw new RuntimeException("Invalid month name: " + strM + " in " + s);
381 y = Integer.parseInt(s.substring(7));
382 return getDaysFrom21Century(d, m, y);
383 }
384 else
385 throw new RuntimeException("Invalid date format: " + s);
386 }
387
388
389 /////////////////////////////////////////////
390 // (양 끝 제외) 날짜 차이 구하기
391 //
392 public static int getDaysBetween(String s1, String s2) {
393 int y1 = getDaysFrom21Century(s1);
394 int y2 = getDaysFrom21Century(s2);
395 return y1 - y2 - 1;
396 }
397
398
399 /////////////////////////////////////////////
400 // 날짜 차이 구하기
401 //
402 public static int getDaysDiff(String s1, String s2) {
403 int y1 = getDaysFrom21Century(s1);
404 int y2 = getDaysFrom21Century(s2);
405 return y1 - y2;
406 }
407
408
409 /////////////////////////////////////////////
410 // (양 끝 포함) 날짜 차이 구하기
411 //
412 public static int getDaysFromTo(String s1, String s2) {
413 int y1 = getDaysFrom21Century(s1);
414 int y2 = getDaysFrom21Century(s2);
415 return y1 - y2 + 1;
416 }
417
418
419 ////////////////////////////////////////////////////////////////////////////
420 // 지정한 년도, 지정한 월에 지정한 요일이 들어 있는 회수를 구한다.
421 //
422 public static int getWeekdaysInMonth(int weekDay, int m, int y) {
423 int week = ((weekDay - 1) % 7);
424 int days = getDaysInMonth(m, y);
425 int sum = 6; // 2000년 1월 1일은 토요일
426 if (y >= 2000) {
427 for (int i = 2000; i < y; i++)
428 sum += getDaysInYear(i);
429 }
430 else {
431 for (int i = y; i < 2000; i++)
432 sum -= getDaysInYear(i);
433 }
434 for (int i = 1; i < m; i++)
435 sum += getDaysInMonth(i, y);
436
437 // if (sum < 0)
438 // sum += 350*3000;
439
440 int firstWeekDay = sum % 7;
441 if (firstWeekDay < 0) {
442 firstWeekDay += 7;
443 }
444
445 // firstWeekDay += 1;
446 int n = firstWeekDay + days;
447 int counter = (n / 7) + (((n % 7) > week) ? 1 : 0);
448 if (firstWeekDay > week)
449 counter--;
450
451 return counter;
452 }
453
454
455 ////////////////////////////////////////////////////////////////////////////
456 // 지정한 년도의 지정한 달에 지정한 요일이 들어 있는 회수를 구한다.
457 //
458 public static int getWeekdaysInMonth(String weekName, int m, int y) {
459 StringBuffer weekNames1 = new StringBuffer("일월화수목금토");
460 StringBuffer weekNames2 = new StringBuffer("日月火水木金土");
461 String[] weekNames3 = { "sun", "mon", "tue", "wed", "thu", "fri", "sat" };
462
463 int n = weekNames1.indexOf(weekName);
464 if (n < 0)
465 n = weekNames2.indexOf(weekName);
466 if (n < 0) {
467 String str = weekName.toLowerCase();
468 for (int i = 0; i < weekNames3.length; i++) {
469 if (str.equals(weekNames3[i])) {
470 n = i;
471 break;
472 }
473 }
474 }
475 // System.out.println("n = " + n);
476
477 if (n < 0)
478 throw new RuntimeException("Invalid week name: " + weekName);
479
480 return getWeekdaysInMonth(n + 1, m, y);
481 }
482
483
484 ////////////////////////////////////////////////////////////////////////////
485 // 2000년 1월 1일 기준을 n일 경과한 날짜 구하기
486 //
487 // @return yyyy-mm-dd 양식의 String 타입
488 public static String getDateStringFrom21Century(int elapsed) {
489 int y = 2000;
490 int m = 1;
491 int d = 1;
492
493 int n = elapsed + 1;
494 int j = 2000;
495 if (n > 0) {
496 while (n > getDaysInYear(j)) {
497 n -= getDaysInYear(j);
498 j++;
499 }
500 y = j;
501
502 int i = 1;
503 while (n > getDaysInMonth(i, y)) {
504 n -= getDaysInMonth(i, y);
505 i++;
506 }
507 m = i;
508 d = n;
509 }
510 else if (n < 0) {
511 while (n < 0) {
512 n += getDaysInYear(j - 1);
513 j--;
514 }
515 y = j;
516
517 int i = 1;
518 while (n > getDaysInMonth(i, y)) {
519 n -= getDaysInMonth(i, y);
520 i++;
521 }
522 m = i;
523 d = n;
524 }
525
526 String strY = "" + y;
527 String strM = "";
528 String strD = "";
529
530 if (m < 10)
531 strM = "0" + m;
532 else
533 strM = "" + m;
534
535 if (d < 10)
536 strD = "0" + d;
537 else
538 strD = "" + d;
539
540 return strY + "/" + strM + "/" + strD;
541 }
542
543
544 ////////////////////////////////////////////////////////////////////////////
545 // 지정한 날짜를 offset일 경과한 날짜 구하기
546 //
547 // @return yyyy-mm-dd 양식의 String 타입
548 public static String addDate(int offset, int d, int m, int y) {
549 int z = getDaysFrom21Century(d, m, y);
550 int n = z + offset;
551 return getDateStringFrom21Century(n);
552 }
553
554
555 ////////////////////////////////////////////////////////////////////////////
556 // 지정한 날짜를 offset일 경과한 날짜 구하기
557 //
558 // @return yyyy-mm-dd 양식의 String 타입
559 public static String addDate(int offset, String date) {
560 int z = getDaysFrom21Century(date);
561 int n = z + offset;
562 return getDateStringFrom21Century(n);
563 }
564
565
566 public static void main(String[] args) {
567 System.out.println("----------------------------------------------");
568 System.out.println("지정한 년도에 포함된 날수 구하기:");
569 int x = getDaysInYear(2002);
570 System.out.println(x);
571 System.out.println("지정한 년도의 지정한 달에 포함된 날수 구하기:");
572 int y = getDaysInMonth(1, 2002);
573 System.out.println(y);
574 System.out.println("2000년 1월 1일 이후 경과한 날수 구하기:");
575 int z = getDaysFromYearFirst(11, 9, 2002);
576 System.out.println(z);
577 int z1 = getDaysFromYearFirst("20020911");
578 System.out.println(z1);
579 int z2 = getDaysFromYearFirst("2002/09/11");
580 System.out.println(z2);
581 int z3 = getDaysFromYearFirst("2002-09-11");
582 System.out.println(z3);
583 int z4 = getDaysFromYearFirst("11-Sep-2002");
584 System.out.println(z4);
585 int z5 = getDaysFromMonthFirst("11-Sep-2002");
586 System.out.println(z5);
587 int z6 = getDaysFrom21Century(11, 9, 2002);
588 System.out.println(z6);
589 int z7 = getDaysFrom21Century("2002-09-11");
590 System.out.println(z7);
591 int z8 = getDaysFrom21Century("11-Sep-2002");
592 System.out.println(z8);
593 int u = getDaysDiff("11-Sep-2002", "01-Jan-2002");
594 System.out.println(u);
595 int u2 = getDaysDiff("01-Jan-2002", "11-Sep-2002");
596 System.out.println(u2);
597 int u3 = getDaysDiff("11-Sep-2002", "31-Dec-2000");
598 System.out.println(u3);
599 int u4 = getDaysDiff("2002-09-10", "2002-09-01");
600 System.out.println(u4);
601 int u5 = getDaysFrom21Century("31-Dec-2000");
602 System.out.println(u5);
603 int u6 = getDaysFrom21Century("2000-12-31");
604 System.out.println(u6);
605 int u7 = getDaysFrom21Century("1999-12-31");
606 System.out.println(u7);
607 int u8 = getDaysFrom21Century("2000-01-01");
608 System.out.println(u8);
609
610 System.out.println("-------------------------------------------------------------");
611 System.out.println("지정한 년도의 지정한 달에 포함된 지정한 요일의 개수 구하기:");
612 System.out.println("2002년 11월에 금요일 개수는 " + getWeekdaysInMonth(6, 11, 2002));
613 System.out.println("2002년 11월에 목요일 개수는 " + getWeekdaysInMonth("목", 11, 2002));
614 System.out.println("2002년 12월에 금요일 개수는 " + getWeekdaysInMonth(6, 12, 2002));
615 System.out.println("2002년 12월에 金요일 개수는 " + getWeekdaysInMonth("金", 12, 2002));
616 System.out.println("2002년 12월에 Tuesday 개수는 " + getWeekdaysInMonth("tue", 12, 2002));
617 System.out.println("2002년 12월에 Saturday 개수는 " + getWeekdaysInMonth("sat", 12, 2001));
618 System.out.println("1998년 12월에 Saturday 개수는 " + getWeekdaysInMonth("sat", 12, 1998));
619
620 System.out.println("-------------------------------------------------------------");
621 System.out.println("1990년 12월에 Sunday 개수는 " + getWeekdaysInMonth("sun", 12, 1990));
622 System.out.println(" Monday 개수는 " + getWeekdaysInMonth("mon", 12, 1990));
623 System.out.println(" Tuesday 개수는 " + getWeekdaysInMonth("tue", 12, 1990));
624 System.out.println(" Wednsday 개수는 " + getWeekdaysInMonth("wed", 12, 1990));
625 System.out.println(" Thursday 개수는 " + getWeekdaysInMonth("thu", 12, 1990));
626 System.out.println(" Friday 개수는 " + getWeekdaysInMonth("fri", 12, 1990));
627 System.out.println(" Saturday 개수는 " + getWeekdaysInMonth("sat", 12, 1990));
628
629 System.out.println("-------------------------------------------------------------");
630 System.out.println("2002년 1월 1일 기준으로 지정한 날수 만큼 경과한 날짜 구하기:");
631 System.out.println(getDateStringFrom21Century(366));
632 System.out.println(getDateStringFrom21Century(-365));
633 System.out.println(addDate(364, 1, 1, 2002));
634 System.out.println(addDate(365, "2002/01/01"));
635 }
636 }
