Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- Executor
- String
- Freemaker
- Runnable
- Postman
- 자바 암호화
- Instrumentation
- 한글조사처리
- JCE
- Executors
- Log4J
- sha1
- StringUtils
- IPTV
- ACAP
- Java
- RSA
- date
- mac
- AES
- 한글조사
- PKCS
- 암호학
- DAMO
- Callable
- 이클립스 플러그인 개발
- xlet
- 자바
- PKCS#8
- ORM
Archives
- Today
- Total
오늘은 어디로 갈까...
날짜(Date) 0x01 본문
지난 시간에 배운 지식을 기반으로 날짜유틸 클래스를 만들어보자.
1. Date를 Calendar로 변환하기
2. 년, 월, 일, 시, 분, 초를 입력받아 날짜형(Date)으로 만들기.
3. 문자열을 입력받아 날짜형(Date)으로 만들기.
- toDate(String) 메소드는 필자같은 게으름뱅이를 위해서 만듯것인데, 별로 추천할 메소드는 못된다.
4. 기준일의 다음주 월요일 가져오기.
5. 기준일이 속한 월의 마지막 날짜 가져오기.
6. 두 날짜(년/월/일)가 동일한지 비교하기.
7. 두 날짜간의 기간 구하기.
8. 두 날짜의 기간을 패턴에 의해서 년/월/일/시/분/초/밀리초로 출력하기.
- 별다른 방법이 생각나지 않는다. 그래서 숫자를 셀때 손가락을 구부리듯이, 기간 사이의 월수를 하나씩 세어서 계산하는 방법을 사용하겠다. 혹시 좋은 알고리즘이 있으면 알려주길 바란다.
- 일단 패턴을 분석을 하기 위한 토큰을 만들어 보겠다.
- 이 날짜패턴토큰을 가지고 기간을 구하는 메소드를 만들어 보자.
- 근데 잘보면, 버그가 존재한다. 귀찮아서 수정은 안하겠다. 한번 연구해보도록.
1. Date를 Calendar로 변환하기
/** * <p><code>java.util.Date</code>를 <code>java.util.Calendar</code>로 변환한다.</p> * * @param date * @return */ public static Calendar toCalendar(Date date) { Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return calendar; }- 지난 시간에 배운거라서 별로 어려운게 없다.
2. 년, 월, 일, 시, 분, 초를 입력받아 날짜형(Date)으로 만들기.
/** * <p>년, 월, 일, 시, 분, 초를 입력받아 날짜형(Date)으로 변환한다.</p> * * @param year 년 * @param month 월(1-12) * @param day 일 * @param hour 시 * @param min 분 * @param sec 초 * @return */ public static Date toDate(int year, int month, int day, int hour, int minute, int second) { Calendar calendar = Calendar.getInstance(); calendar.set(year, month - 1, day, hour, minute, second); calendar.set(Calendar.MILLISECOND, 0); return calendar.getTime(); } /** * <p>년, 월, 일, 시, 분을 입력받아 날짜형(Date)으로 변환한다.(0초로 설정된다)</p> * * @param year 년 * @param month 월(1-12) * @param day 일 * @param hour 시 * @param minute 분 * @return */ public static Date toDate(int year, int month, int day, int hour, int minute) { return toDate(year, month, day, hour, minute, 0); } /** * <p>년, 월, 일, 시을 입력받아 날짜형(Date)으로 변환한다.(0시 0분 0초로 설정된다)</p> * * @param year 년 * @param month 월(1-12) * @param day 일 * @return */ public static Date toDate(int year, int month, int day) { return toDate(year, month, day, 0, 0, 0); }- 지난 시간에 배운거라서 별로 어려운게 없다.
3. 문자열을 입력받아 날짜형(Date)으로 만들기.
// 자동 변환용 패턴 설정 protected static final String[] patterns = { "yyyy-MM-dd HH:mm:ss.SSS", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM-dd HH", "yyyy-MM-dd", "yyyyMMddHHmmssSSS", "yyyyMMddHHmmss", "yyyyMMddHHmm", "yyyyMMddHH", "yyyyMMdd", "yyMMdd" }; private static DateFormat getDateFormat(String pattern) { return new SimpleDateFormat(pattern); } /** * <p>문자열을 입력받아 패턴에 맞게 날짜형(Date)으로 변환하여 반환한다.</p> * * <pre> * DateUtils.toDate("2008-11-11 06:15:00", "yyyy-MM-dd HH:mm:ss") = Date@"2008-11-11 06:15:00" * DateUtils.toDate("Time is Gold", "yyyy-MM-dd HH:mm:ss") = ParseException * DateUtils.toDate(null, *) = ParseException * </pre> * * @param dateStr * @param pattern * @return * @throws ParseException 변환을 실패할때 발생 */ public static Date toDate(String dateStr, String pattern) throws ParseException { if (dateStr == null) { return null; } DateFormat dateFormat = getDateFormat(pattern); Date date = dateFormat.parse(dateStr); if (dateStr.equals(dateFormat.format(date))) { return date; } else { throw new ParseException(MessageUtils.format( "Out of bound date:\"{0}\" with format \"{1}\"", dateStr, pattern), 0); } } /** * <p>문자열을 입력받아 패턴에 맞게 날짜형(Date)으로 변환하여 반환한다.</p> * <p>(변환을 실패할때는 기본 날짜를 반환한다.<)/p> * * <pre> * DateUtils.toDate("2008-11-11 06:15:00", "yyyy-MM-dd HH:mm:ss", *) = Date@"2008-11-11 06:15:00" * DateUtils.toDate("Time is Gold", "yyyy-MM-dd HH:mm:ss", toDate("2008-11-11 06:15:00")) = Date@"2008-11-11 06:15:00" * DateUtils.toDate(null, *, toDate("2008-11-11 06:15:00")) = Date@"2008-11-11 06:15:00" * </pre> * * @param dateStr * @param pattern * @param defaultDate 기본 날짜 * @return */ public static Date toDate(String dateStr, String pattern, Date defaultDate) { if (dateStr == null) { return defaultDate; } try { DateFormat dateFormat = getDateFormat(pattern); Date date = getDateFormat(pattern).parse(dateStr); if (dateStr.equals(dateFormat.format(date))) { return date; } } catch (ParseException e) { } return defaultDate; } /** * <p>문자열을 입력받아 날짜형(Date)으로 변환한다.</p> * * <pre> * DateUtils.toDate(null) = null * DateUtils.toDate("2008-11-11") = Date@"2008-11-11 00:00:00" * DateUtils.toDate("2008-11-11 06:15:00") = Date@"2008-11-11 06:15:00" * </pre> * * <h4>지원하는형식</h4> * <ul> * <li>yyyy-MM-dd HH:mm:ss.SSS * <li>yyyy-MM-dd HH:mm:ss * <li>yyyy-MM-dd HH:mm * <li>yyyy-MM-dd HH * <li>yyyy-MM-dd * <li>yyyyMMddHHmmssSSS * <li>yyyyMMddHHmmss * <li>yyyyMMddHHmm * <li>yyyyMMddHH * <li>yyyyMMdd * </ul> * @param dateStr * @return * @throws IllegalArgumentException 지원하지 않는 형식일 경우 */ public static Date toDate(String dateStr) throws IllegalArgumentException { if (dateStr == null) { return null; } dateStr = StringUtils.trim(dateStr); int dateStrLen = dateStr.length(); Date date = null; for (String pattern : patterns) { if (dateStrLen == pattern.length()) { DateFormat dateFormat = getDateFormat(pattern); try { date = dateFormat.parse(dateStr); if (dateStr.equals(dateFormat.format(date))) { return date; } else { date = null; } } catch (ParseException e) { date = null; } } } if (date == null) { throw new IllegalArgumentException(MessageUtils.format( "Illegal Argument Date String \"{0}\"", dateStr)); } return date; }- 날짜형(Date)을 문자열로 출력할때 SimpleDateFormat 클래스를 사용한것처럼, 문자열을 날짜형으로 변환할때도 SimpleDateFormat 클래스를 사용하면 손쉽게 변환할 수 있다. parse(String) 메소드를 사용하면 날짜형으로 변환이 되는데, 경험상으로봐서는 별로 정확(?)하지만 않다. 그래서 데이터가 정확한지 확인하는 아래 코드를 추가한 것이다.
Date date = dateFormat.parse(dateStr); if (dateStr.equals(dateFormat.format(date))) { }- 즉, 날짜형으로 변환한 값을 다시 해당 포맷으로 변환하면, 처음에 입력한 값과 같아야한다는것이다.
- toDate(String) 메소드는 필자같은 게으름뱅이를 위해서 만듯것인데, 별로 추천할 메소드는 못된다.
4. 기준일의 다음주 월요일 가져오기.
/** * <p>해당 일을 기준으로 명시된 요일의 다음 날짜를 계산한다.</p> * * <pre> * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.SUNDAY) = "2008-07-20 06:15:00" * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.MONDAY) = "2008-07-21 06:15:00" * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.SATURDAY) = "2008-07-26 06:15:00" * </pre> * * @param date * @param dayOfWeek SUNDAY=1, MONDAY=2, ... SATURDAY=7 * @return */ public static Date getNextDate(Date date, int dayOfWeek) { Calendar cal = toCalendar(date); int amount = (7 - cal.get(Calendar.DAY_OF_WEEK)) + dayOfWeek; cal.add(Calendar.DAY_OF_MONTH, amount); return cal.getTime(); } /** * <p>해당 일을 기준으로 명시된 요일의 다음 날짜를 계산한다.</p> * * <pre> * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.SUNDAY, false) = "2008-07-20 06:15:00" * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.SUNDAY, true) = "2008-07-20 00:00:00" * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.MONDAY, false) = "2008-07-21 06:15:00" * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.MONDAY, true) = "2008-07-21 00:00:00" * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.SATURDAY, false) = "2008-07-26 06:15:00" * DateUtils.getNextDay(toDate("2008-07-19 06:15:00"), Calendar.SATURDAY, true) = "2008-07-26 00:00:00" * </pre> * * @param date * @param dayOfWeek SUNDAY=1, MONDAY=2, ... SATURDAY=7 * @param resetTime 시간 초기화 여부. <code>true</code>이면 시:분:초 0:0:0으로 설정한다. * @return */ public static Date getNextDate(Date date, int dayOfWeek, boolean resetTime) { Calendar cal = toCalendar(date); if (resetTime) { cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); } int amount = (7 - cal.get(Calendar.DAY_OF_WEEK)) + dayOfWeek; cal.add(Calendar.DAY_OF_MONTH, amount); return cal.getTime(); }- cal.get(Calendar.DAY_OF_WEEK) 메소드를 이용해서 요일을 구한다음, 그 차이만큼 연산한면 된다.
5. 기준일이 속한 월의 마지막 날짜 가져오기.
/** * <p>해당 날짜가 속한 달의 마지막 날짜를 계산한다.</p> * * <pre> * DateUtils.getLastDay(toDate("2008-07-19 06:15:00"), Calendar.SUNDAY) = "2008-07-31 06:15:00" * </pre> * * @param date * @return */ public static Date getLastDate(Date date) { Calendar cal = toCalendar(date); int amount = cal.getActualMaximum(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH); cal.add(Calendar.DAY_OF_MONTH, amount); return cal.getTime(); } /** * <p>해당 날짜가 속한 달의 마지막 날짜를 계산한다.</p> * * <pre> * DateUtils.getLastDay(toDate("2008-07-19 06:15:00"), Calendar.SUNDAY, false) = "2008-07-31 06:15:00" * DateUtils.getLastDay(toDate("2008-07-19 06:15:00"), Calendar.SUNDAY, true) = "2008-07-31 00:00:00" * </pre> * * @param date * @param resetTime 시간 초기화 여부. <code>true</code>이면 시:분:초 0:0:0으로 설정한다. * @return */ public static Date getLastDate(Date date, boolean resetTime) { Calendar cal = toCalendar(date); if (resetTime) { cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); } int amount = cal.getActualMaximum(Calendar.DAY_OF_MONTH) - cal.get(Calendar.DAY_OF_MONTH); cal.add(Calendar.DAY_OF_MONTH, amount); return cal.getTime(); }- cal.getActualMaximum(int)을 이용해서 해당일의 마지막일을 구한다음 현재일과의 차이를 연산해주면 된다.
6. 두 날짜(년/월/일)가 동일한지 비교하기.
/** * <p>두 달력의 날짜(시간 무시)가 일치하는지 판단한다.</p> * * @param cal1 * @param cal2 * @return */ public static boolean isSameDay(Calendar cal1, Calendar cal2) { if (cal1 == null) { return (cal2 == null); } if (cal1 == cal2) { return true; } return (cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA) && cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && cal1 .get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR)); } /** * <p>두 날짜의 날짜(시간 무시)가 일치하는지 판단한다.</p * * @param date1 * @param date2 * @return */ public static boolean isSameDay(Date date1, Date date2) { if (date1 == null) { return (date2 == null); } if (date1 == date2) { return true; } return isSameDay(toCalendar(date1), toCalendar(date2)); }- 시간 부분은 무시하고 년/월/일만 비교하는 메소드이다. 소스를 보면 Calendar.ERA의 값도 비교하게 되는데, Calendar.ERA는 율리우스력을 나타낸다. 즉 AD 또는 BC. 그리고 월과 일을 두번 비교하는게 아니라 DAY_OF_YEAR를 써서 한번에 끝내주는 센스~.
7. 두 날짜간의 기간 구하기.
public static final long MILLIS_PER_SECOND = 1000; public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND; public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE; public static final long MILLIS_PER_DAY = 24 * MILLIS_PER_HOUR; /** * <p>시작일부터 종료일까지의 기간을 ms로 계산한다.</p> * * <pre> * DateUtils.getBetween(toDate("2008-11-11 23:59"), toDate("2008-11-12 23:58")) = 86340000 * DateUtils.getBetween(toDate("2008-11-11 23:59"), toDate("2008-11-12 23:59")) = 86400000 * DateUtils.getBetween(null, *) = 0 * DateUtils.getBetween(*, null) = 0 * </pre> * * @param from 시작일 * @param to 종료일 * @return 기간의 1/1000초(ms) */ public static long getBetween(Date from, Date to) { if (from == null || to == null) { return 0; } return to.getTime() - from.getTime(); } /** * <p>시작일부터 종료일까지의 차이를 일(day)로 계산한다. * (시간 단위로 계산하기 때문에 24시간이 지나지않으면 하루로 계산하지 않는다.)</p> * * <pre> * DateUtils.getDaysBetween(toDate("2008-11-11"), toDate("2008-11-13")) = 2 * DateUtils.getDaysBetween(toDate("2008-11-11"), toDate("2008-11-11")) = 0 * DateUtils.getDaysBetween(toDate("2008-11-12"), toDate("2008-11-11")) = -1 * DateUtils.getDaysBetween(toDate("2008-11-11 23:59"), toDate("2008-11-12 23:58")) = 0 * DateUtils.getDaysBetween(toDate("2008-11-11 23:59"), toDate("2008-11-12 23:59")) = 1 * DateUtils.getDaysBetween(null, *) = 0 * DateUtils.getDaysBetween(*, null) = 0 * </pre> * * @param from 시작일 * @param to 종료일 * @return 기간의 일(day)수 */ public static int getDaysBetween(Date from, Date to) { return (int) (getBetween(from, to) / MILLIS_PER_DAY); }- 두 날짜의 기간을 일/시/분/초/밀리초로 구하는것은 아주 싶다. 밀리초로 두 값의 차이를 구한다음 해당 단위로 나누면 끝이다. 그런데, 몇 월이 지났나 계산하는것은 머리를 아프게 한다. 한달은 28일/30일/31일 다르기에 우리를 괴롭힌다. 하지만 여기서 포기할 수는 없으니 한번 도전해보도록하자.
8. 두 날짜의 기간을 패턴에 의해서 년/월/일/시/분/초/밀리초로 출력하기.
- 별다른 방법이 생각나지 않는다. 그래서 숫자를 셀때 손가락을 구부리듯이, 기간 사이의 월수를 하나씩 세어서 계산하는 방법을 사용하겠다. 혹시 좋은 알고리즘이 있으면 알려주길 바란다.
- 일단 패턴을 분석을 하기 위한 토큰을 만들어 보겠다.
package kr.kangwoo.util.date; import java.util.ArrayList; import java.util.List; import kr.kangwoo.util.StringUtils; public class DatePatternToken { private Object value; private int count; public DatePatternToken(Object value) { this(value, 1); } public DatePatternToken(Object value, int count) { this.value = value; this.count = count; } public void increment() { count++; } public Object getValue() { return value; } public int getCount() { return count; } @Override public boolean equals(Object obj) { if (obj instanceof DatePatternToken) { DatePatternToken another = (DatePatternToken)obj; if (this.value.getClass() != another.value.getClass()) { return false; } if (this.count != another.count) { return false; } if (this.value instanceof StringBuilder || this.value instanceof StringBuffer) { return this.value.toString().equals(another.value.toString()); } else { return this.value.equals(another.value); } } return false; } @Override public int hashCode() { return toString().hashCode(); } @Override public String toString() { return StringUtils.repeat(value.toString(), count); } /** * <p>해당 패턴을 분석하여 토큰을 만든다.</p> * * @param pattern * @return */ public static DatePatternToken[] getTokens(String pattern) { int patternLen = pattern.length(); List<DatePatternToken> list = new ArrayList<DatePatternToken>(patternLen); DatePatternToken previous = null; StringBuilder buffer = null; boolean inQuote = false; for (int i = 0; i < patternLen; i++) { char ch = pattern.charAt(i); if(inQuote && ch != '\'') { buffer.append(ch); continue; } if (ch == '\'') { // espace 문자 if(inQuote) { if (buffer.length() == 0) { // '' 일때 처리 buffer.append(ch); } buffer = null; inQuote = false; } else { buffer = new StringBuilder(); list.add(new DatePatternToken(buffer)); inQuote = true; } } else if (ch == 'y' || ch == 'M' || ch == 'd' || ch == 'H' || ch == 'm' || ch == 's' || ch == 'S') { String value = String.valueOf(ch); if (previous != null && previous.getValue().equals(value)) { previous.increment(); } else { DatePatternToken token = new DatePatternToken(value); list.add(token); previous = token; } buffer = null; } else { if (buffer == null) { buffer = new StringBuilder(); list.add(new DatePatternToken(buffer)); } buffer.append(ch); } } return (DatePatternToken[])list.toArray(new DatePatternToken[list.size()]); } /** * <p>패턴 존재유무를 파악하여 반환한다.</p> * * @param tokens * @return boolean[hasYears, hasMonths, hasDays, hasHours, hasMinutes, hasSeconds, hasMilliSeconds] */ public static boolean[] containsPattern(DatePatternToken[] tokens) { boolean[] result = new boolean[7]; for (DatePatternToken token : tokens) { Object value = token.getValue(); if ("y".equals(value)) { result[0] = true; } else if ("M".equals(value)) { result[1] = true; } else if ("d".equals(value)) { result[2] = true; } else if ("H".equals(value)) { result[3] = true; } else if ("m".equals(value)) { result[4] = true; } else if ("s".equals(value)) { result[5] = true; } else if ("S".equals(value)) { result[6] = true; } } return result; } }
- 이 날짜패턴토큰을 가지고 기간을 구하는 메소드를 만들어 보자.
/** * <p>시작일부터 종료일까지의 기간을 패턴에 맞게 출력한다.('0'으로 패딩한다.)</p> * * <pre> * DaetUtils.toString(toDate("1978-07-19 06:15:00.000"), toDate("2004-11-11 07:19:01.004"), "yyyy-MM-dd- HH:mm:ss.SSS") = "0026-03-23 01:04:01.004"; * DaetUtils.toString(toDate("1978-07-19 06:15:00.000"), toDate("2004-11-11 07:19:01.004"), "MM-dd- HH:mm:ss.SSS") = "315-23 01:04:01.004"; * </pre> * * @param startDate 시작일 * @param endDate 종료일 * @param pattern 패턴(yyyyMMddHHMmmssSSS) * @return * @since 1.1 */ public static String toString(Date startDate, Date endDate, String pattern) { return toString(startDate, endDate, pattern, true); } /** * <p>시작일부터 종료일까지의 기간을 패턴에 맞게 출력한다.</p> * * <pre> * DaetUtils.toString(toDate("1978-07-19 06:15:00.000"), toDate("2004-11-11 07:19:01.004"), "yyyy-MM-dd- HH:mm:ss.SSS", true) = "0026-03-23 01:04:01.004"; * DaetUtils.toString(toDate("1978-07-19 06:15:00.000"), toDate("2004-11-11 07:19:01.004"), "yyyy-MM-dd- HH:mm:ss.SSS", false) = "26-3-23 01:04:01.004"; * DaetUtils.toString(toDate("1978-07-19 06:15:00.000"), toDate("2004-11-11 07:19:01.004"), "MM-dd- HH:mm:ss.SSS", true) = "315-23 01:04:01.004"; * </pre> * * @param startDate 시작일 * @param endDate 종료일 * @param pattern 패턴(yyyyMMddHHMmmssSSS) * @param padWithZeros '0'을 패딩할지 여부 * @return * @since 1.1 */ public static String toString(Date startDate, Date endDate, String pattern, boolean padWithZeros) { if (pattern == null) { return null; } DatePatternToken[] tokens = DatePatternToken.getTokens(pattern); boolean[] contains = DatePatternToken.containsPattern(tokens); boolean hasYears = contains[0], hasMonths = contains[1], hasDays = contains[2]; boolean hasHours = contains[3], hasMinutes = contains[4], hasSeconds = contains[5]; boolean needRevert = false; if (startDate.compareTo(endDate) > 0) { Date tempDate = startDate; startDate = endDate; endDate = tempDate; needRevert = true; } int years = 0; int months = 0; int days = 0; int hours = 0; int minutes = 0; int seconds = 0; int milliseconds = 0; if (hasMonths) { Calendar start = toCalendar(startDate); Calendar end = toCalendar(endDate); hours = end.get(Calendar.HOUR_OF_DAY) - start.get(Calendar.HOUR_OF_DAY); minutes = end.get(Calendar.MINUTE) - start.get(Calendar.MINUTE); seconds = end.get(Calendar.SECOND) - start.get(Calendar.SECOND); milliseconds = end.get(Calendar.MILLISECOND) - start.get(Calendar.MILLISECOND); while (milliseconds < 0) { milliseconds += 1000; seconds -= 1; } while (seconds < 0) { seconds += 60; minutes -= 1; } while (minutes < 0) { minutes += 60; hours -= 1; } while (hours < 0) { hours += 24; days -= 1; } int endDay = end.get(Calendar.DAY_OF_MONTH); if (end.get(Calendar.YEAR) > start.get(Calendar.YEAR)) { years += (end.get(Calendar.YEAR) - (start.get(Calendar.YEAR) + 1)); months += end.get(Calendar.MONTH); days += endDay; end.set(start.get(Calendar.YEAR), 11, 1); end.set(Calendar.DAY_OF_MONTH, end .getActualMaximum(Calendar.DAY_OF_MONTH)); } endDay = end.get(Calendar.DAY_OF_MONTH); if (end.get(Calendar.MONTH) > start.get(Calendar.MONTH)) { months += (end.get(Calendar.MONTH) - (start.get(Calendar.MONTH) + 1)); days += endDay; if (days >= start.getActualMaximum(Calendar.DAY_OF_MONTH)) { months++; days -= start.getActualMaximum(Calendar.DAY_OF_MONTH); } end.set(end.get(Calendar.YEAR), start.get(Calendar.MONTH), 1); end.set(Calendar.DAY_OF_MONTH, end .getActualMaximum(Calendar.DAY_OF_MONTH)); } days += (end.get(Calendar.DAY_OF_MONTH) - start .get(Calendar.DAY_OF_MONTH)); if (days >= start.getActualMaximum(Calendar.DAY_OF_MONTH)) { months++; days -= start.getActualMaximum(Calendar.DAY_OF_MONTH); } if (hasYears) { if (months > 11) { years += (months / 12); months = (months % 12); } } else { if (years != 0) { months += (years * 12); years = 0; } } } else { long period = getBetween(startDate, endDate); days = (int) (period / MILLIS_PER_DAY); hours = (int) ((period % MILLIS_PER_DAY) / MILLIS_PER_HOUR); minutes = (int) ((period % MILLIS_PER_HOUR) / MILLIS_PER_MINUTE); seconds = (int) ((period % MILLIS_PER_MINUTE) / MILLIS_PER_SECOND); milliseconds = (int) (period % MILLIS_PER_SECOND); } if (!hasDays) { hours += 24 * days; days = 0; } if (!hasHours) { minutes += 60 * hours; hours = 0; } if (!hasMinutes) { seconds += 60 * minutes; minutes = 0; } if (!hasSeconds) { milliseconds += 1000 * seconds; seconds = 0; } String result = format(tokens, years, months, days, hours, minutes, seconds, milliseconds, padWithZeros); return needRevert ? "-" + result : result; } /** * <p>패턴에 맞게 기간을 문자열로 출력한다.</p> * * @param tokens * @param years * @param months * @param days * @param hours * @param minutes * @param seconds * @param milliseconds * @param padWithZeros * @return * @since 1.1 */ protected static String format(DatePatternToken[] tokens, int years, int months, int days, int hours, int minutes, int seconds, int milliseconds, boolean padWithZeros) { StringBuilder result = new StringBuilder(); for (DatePatternToken token : tokens) { Object value = token.getValue(); int count = token.getCount(); if (value instanceof StringBuilder) { result.append(value.toString()); } else { if ("y".equals(value)) { result.append(padWithZeros ? StringUtils.leftPad(Integer .toString(years), count, "0") : Integer .toString(years)); } else if ("M".equals(value)) { result.append(padWithZeros ? StringUtils.leftPad(Integer .toString(months), count, "0") : Integer .toString(months)); } else if ("d".equals(value)) { result.append(padWithZeros ? StringUtils.leftPad(Integer .toString(days), count, "0") : Integer .toString(days)); } else if ("H".equals(value)) { result.append(padWithZeros ? StringUtils.leftPad(Integer .toString(hours), count, "0") : Integer .toString(hours)); } else if ("m".equals(value)) { result.append(padWithZeros ? StringUtils.leftPad(Integer .toString(minutes), count, "0") : Integer .toString(minutes)); } else if ("s".equals(value)) { result.append(padWithZeros ? StringUtils.leftPad(Integer .toString(seconds), count, "0") : Integer .toString(seconds)); } else if ("S".equals(value)) { result.append(padWithZeros ? StringUtils.leftPad(Integer .toString(milliseconds), count, "0") : Integer .toString(milliseconds)); } } } return result.toString(); }
- 근데 잘보면, 버그가 존재한다. 귀찮아서 수정은 안하겠다. 한번 연구해보도록.