지난 시간에 배운 지식을 기반으로 날짜유틸 클래스를 만들어보자.
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();
}
- 근데 잘보면, 버그가 존재한다. 귀찮아서 수정은 안하겠다. 한번 연구해보도록.
DatePatternToken.java |
DatePatternTokenTests.java |
DateUtils.java |
DateUtilsTest.java |
DatePatternToken.java