/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.openflamingo.mapreduce.util;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Date Utility.
*
* @author Edward KIM
* @author Seo Ji Hye
* @since 0.2
*/
public class DateUtils {
/**
* 현재 날짜의 이전 이후날짜를 더할때 사용하는 Enumeration 상수
*/
public static enum TYPE { BEFORE, AFTER };
/**
* 기본 날짜 변환 포맷
*/
public static String[] DATE_FORMAT = {"yyyyMMdd"};
/**
* 매월의 일수
*/
public static int DAYS_OF_MONTH[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
/**
* 두 날짜가 같은 날짜인지 확인한다. 이 메소드는 시간은 무시한다.
*
* @param date1 비교할 첫번째 날짜
* @param date2 비교할 두번째 날짜
* @return 날짝 같으면 <tt>true</tt>
* @throws IllegalArgumentException 날짜가 <tt>null인 경우</tt>
*/
public static boolean isSameDay(Date date1, Date date2) {
return org.apache.commons.lang.time.DateUtils.isSameDay(date1, date2);
}
/**
* 두 날짜가 같은 날짜인지 확인한다. 이 메소드는 시간은 무시한다.
*
* @param cal1 비교할 첫번째 날짜
* @param cal2 비교할 두번째 날짜
* @return 날짝 같으면 <tt>true</tt>
* @throws IllegalArgumentException 날짜가 <tt>null인 경우</tt>
*/
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
return org.apache.commons.lang.time.DateUtils.isSameDay(cal1, cal2);
}
/**
* 두 날짜 객체가 시간까지 동일한지 확인한다.
*
* @param date1 비교할 첫번째 날짜
* @param date2 비교할 두번째 날짜
* @return 밀리초까지 동일하면 <tt>true</tt>
* @throws IllegalArgumentException 날짜가 <tt>null인 경우</tt>
*/
public static boolean isSameInstant(Date date1, Date date2) {
return org.apache.commons.lang.time.DateUtils.isSameInstant(date1, date2);
}
/**
* 두 달력 객체가 시간까지 동일한지 확인한다.
*
* @param cal1 비교할 첫번째 날짜
* @param cal2 비교할 두번째 날짜
* @return true 밀리초까지 동일하면 <tt>true</tt>
* @throws IllegalArgumentException 날짜가 <tt>null인 경우</tt>
*/
public static boolean isSameInstant(Calendar cal1, Calendar cal2) {
return org.apache.commons.lang.time.DateUtils.isSameInstant(cal1, cal2);
}
/**
* 두 달력 객체가 지역 시간까지 동일한지 확인한다. 이 메소드는 밀리초, 초, 분, 시간, 년, 월, 일, ERA 까지 비교 한다.
*
* @param cal1 비교할 첫번째 날짜
* @param cal2 비교할 두번째 날짜
* @return true 밀리초까지 동일하면 <tt>true</tt>
* @throws IllegalArgumentException 날짜가 <tt>null인 경우</tt>
*/
public static boolean isSameLocalTime(Calendar cal1, Calendar cal2) {
return org.apache.commons.lang.time.DateUtils.isSameLocalTime(cal1, cal2);
}
/**
* 지정한 다양한 파싱 패턴을 이용하여 문자열로 표현되는 날짜를 파싱한다.
*
* @param str 파싱할 날짜(<tt>null</tt>이 아님)
* @param parsePatterns 파싱하는데 사용하는 날짜 형식 패턴. <tt>null</tt>이 아님. {@link java.text.SimpleDateFormat}을 참고.
* @return 파싱된 날짜
* @throws IllegalArgumentException 문자열로 된 날짜 또는 패턴이 <tt>null</tt>인 경우
* @throws java.text.ParseException 패턴이 적합하지 않은 경우
*/
public static Date parseDate(String str, String[] parsePatterns) throws ParseException {
return org.apache.commons.lang.time.DateUtils.parseDate(str, parsePatterns);
}
/**
* 날짜에 지정한 만큼의 년수를 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 년수를 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addYears(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addYears(date, amount);
}
/**
* 날짜에 지정한 만큼의 개월수를 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 개월수를 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addMonths(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addMonths(date, amount);
}
/**
* 날짜에 지정한 만큼의 주(week)를 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 주(week)를 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addWeeks(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addWeeks(date, amount);
}
/**
* 날짜에 지정한 만큼의 일수를 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 일수를 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addDays(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addDays(date, amount);
}
/**
* 날짜에 지정한 만큼의 시간을 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 시간을 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addHours(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addHours(date, amount);
}
/**
* 날짜에 지정한 만큼의 분을 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 분을 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addMinutes(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addMinutes(date, amount);
}
/**
* 날짜에 지정한 만큼의 초를 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 초를 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addSeconds(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addSeconds(date, amount);
}
/**
* 날짜에 지정한 만큼의 밀리초를 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param amount 추가할 양(음수도 가능)
* @return 밀리초 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date addMilliseconds(Date date, int amount) {
return org.apache.commons.lang.time.DateUtils.addMilliseconds(date, amount);
}
/**
* 날짜에 지정한 필드와 양만큼 추가한다. 원본 객체를 변경되지 않으며 반환값은 새로운 객체다.
*
* @param date 날짜(<tt>null</tt>이 아님)
* @param calendarField {@link java.util.Calendar}의 필드
* @param amount 추가할 양(음수도 가능)
* @return 추가한 새로운 날짜 객체
* @throws IllegalArgumentException 날짜가 <tt>null</tt>인 경우
*/
public static Date add(Date date, int calendarField, int amount) {
return org.apache.commons.lang.time.DateUtils.add(date, calendarField, amount);
}
/**
* YYYY-MM-DDTHH:MI:SS 형태의 문자열(예:2007-02-13T10:25:00)로 XMLGregorianCalendar 을 생성한다.
*
* @param stringTypeDate YYYY-MM-DDTHH:MI:SS 형태의 문자열(예:2007-02-13T10:25:00)
* @return XMLGregorianCalendar
*/
public static XMLGregorianCalendar toXMLGregorianCalendar(String stringTypeDate) throws DatatypeConfigurationException {
String yyyy = stringTypeDate.substring(0, 4);
String mm = stringTypeDate.substring(5, 7);
String dd = stringTypeDate.substring(8, 10);
String hh = stringTypeDate.substring(11, 13);
String mi = stringTypeDate.substring(14, 16);
String ss = stringTypeDate.substring(17, 19);
int iyyyy = Integer.parseInt(yyyy);
int imm = Integer.parseInt(mm);
int idd = Integer.parseInt(dd);
int ihh = Integer.parseInt(hh);
int imi = Integer.parseInt(mi);
int iss = Integer.parseInt(ss);
DatatypeFactory dataTypeFactory = DatatypeFactory.newInstance();
return dataTypeFactory.newXMLGregorianCalendar(iyyyy, imm, idd, ihh, imi, iss, 0, 0);
}
/**
* 지정한 날짜의 이전 일수를 뺀 날짜를 반환한다.
*
* @param date 기준 날짜
* @param before 이전 일수
* @return 지정한 날짜의 이전 일수를 뺀 날짜
*/
public static Date before(Date date, int before) {
return org.apache.commons.lang.time.DateUtils.addDays(date, -before);
}
/**
* 지정한 날짜의 다음 일수를 더한 날짜를 반환한다.
*
* @param date 기준 날짜
* @param after 다음 일수
* @return 지정한 날짜의 다음 일수를 뺀 날짜
*/
public static Date after(Date date, int after) {
return org.apache.commons.lang.time.DateUtils.addDays(date, after);
}
/**
* 지정한 날짜에 대해서 지정한 패턴과 일수에 따라서 더하거나 뺀 날짜를 반환한다. 기본 유형은 지정한 날짜에서 뺀다. 유형을 지정하면 지정한 유형대로 처리한다.
*
* @param baseDate 기준일
* @param type 날짜 연산 유형(before, after)
* @param duration 더하거나 뺄 일수(예; 20)
* @return 연산된 날짜
* @throws java.text.ParseException 날짜를 지정한 패턴으로 파싱할 수 없는 경우
*/
public static Date calculateDate(Date baseDate, TYPE type, int duration) throws ParseException {
switch (type) {
case BEFORE:
return DateUtils.before(baseDate, duration);
case AFTER:
return DateUtils.after(baseDate, duration);
default:
return DateUtils.before(baseDate, duration);
}
}
/**
* 지정한 날짜에 대해서 지정한 패턴과 일수에 따라서 더하거나 뺀 날짜를 반환한다.
*
* @param date 기준일
* @param type 날짜 연산 유형(before, after)
* @param duration 더하거나 뺄 일수(예; 20)
* @return 연산된 날짜
* @throws java.text.ParseException 날짜를 지정한 패턴으로 파싱할 수 없는 경우
*/
public static String calculateDate(String date, TYPE type, int duration) throws ParseException {
Date baseDate = DateUtils.parseDate(date, DATE_FORMAT);
Date result = DateUtils.calculateDate(baseDate, type, duration);
return parseDate(result, DATE_FORMAT[0]);
}
/**
* 지정한 날짜에 대해서 지정한 패턴과 일수에 따라서 더하거나 뺀 날짜를 반환한다.
*
* @param date 기준일
* @param strType 날짜 연산 유형(before, after)
* @param strDuration 문자열 형태의 더하거나 뺄 일수(예; "20")
* @return 연산된 날짜
* @throws java.text.ParseException 날짜를 지정한 패턴으로 파싱할 수 없는 경우
*/
public static String calculateDate(String date, String strType, String strDuration) throws ParseException {
int duration = Integer.parseInt(strDuration);
if ("BEFORE".equals(strType)) {
return calculateDate(date, TYPE.BEFORE, duration);
} else if ("AFTER".equals(strType)) {
return calculateDate(date, TYPE.AFTER, duration);
} else {
return null;
}
}
/**
* 지정한 날자를 패턴에 맞도록 문자열 날짜로 변환한다.
*
* @param date 날짜
* @param pattern 패턴 (예; YYYYMMDD)
* @return 문자열 날짜
*/
public static String parseDate(Date date, String pattern) {
SimpleDateFormat formatter = new SimpleDateFormat(pattern, Locale.US);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return formatter.format(calendar.getTime());
}
/**
* 두 날짜간의 날짜수를 반환한다. 이 메소드는 윤년이 적용하여 계산한다.
* <p>
* <pre>
* long date = DateUtils.getDiffDays("20080501",DateUtils.getCurrentYyyymmdd())
* </pre>
* </p>
*
* @param startStr 시작 날짜
* @param endStr 끝 날짜
* @return 일수
*/
public static long getDiffDays(String startStr, String endStr) {
GregorianCalendar start = getGregorianCalendar(startStr);
GregorianCalendar end = getGregorianCalendar(endStr);
return (start.getTime().getTime() - end.getTime().getTime()) / 86400000;
}
/**
* 두 날짜간의 초수를 반환한다. 이 메소드는 윤년이 적용하여 계산한다.
*
* @param from 시작 날짜
* @param to 끝 날짜
* @return 초수
*/
public static long getDiffSeconds(Date from, Date to) {
return (from.getTime() - to.getTime()) / 1000;
}
/**
* "yyyyMMdd" 문자열 형식의 날짜를 {@link java.util.Calendar} 형식으로 변환한다.
* <p>
* <pre>
* Calendar cal = DateUtils.getGregorianCalendar(DateUtil.getCurrentYyyymmdd());
* </pre>
* </p>
*
* @param yyyymmdd 날짜
* @return GregorianCalendar
*/
public static GregorianCalendar getGregorianCalendar(String yyyymmdd) {
int yyyy = Integer.parseInt(yyyymmdd.substring(0, 4));
int mm = Integer.parseInt(yyyymmdd.substring(4, 6));
int dd = Integer.parseInt(yyyymmdd.substring(6, 8));
GregorianCalendar calendar = new GregorianCalendar(yyyy, mm - 1, dd, 0, 0, 0);
return calendar;
}
/**
* 지정한 월의 시작일을 포함한 날짜를 반환한다.
*
* @param yyyyMM 년월
* @return 시작일을 포함한 년월일
*/
public static String getStartMonthDayOfDate(String yyyyMM) {
return yyyyMM + "01";
}
/**
* 지정한 월의 마지막 일을 포함한 날짜를 반환한다.
*
* @param yyyyMM 년월
* @return 마지막을 포함한 년월일
*/
public static String getEndMonthDayOfDate(String yyyyMM) {
int mm = Integer.parseInt(yyyyMM.substring(4, 6));
return yyyyMM + DAYS_OF_MONTH[mm - 1];
}
/**
* 현재 날짜를 "yyyyMMdd" 형태로 변환한다.
* <p>
* <pre>
* String today = DateUtils.getCurrentYyyymmdd();
* </pre>
* </p>
*
* @return yyyyMMdd
*/
public static String getCurrentYyyymmdd() {
return getCurrentDateTime().substring(0, 8);
}
/**
* 현재 날짜를 "yyyyMM" 형태로 변환한다.
* <p>
* <pre>
* String today = DateUtils.getCurrentYyyymm();
* </pre>
* </p>
*
* @return yyyyMM
*/
public static String getCurrentYyyymm() {
return getCurrentDateTime().substring(0, 6);
}
/**
* 현재 날짜와 시각을 "yyyyMMddhhmmss" 형태로 변환한다.
* <p>
* <pre>
* String today = DateUtils.getCurrentDateTime();
* </pre>
* </p>
*
* @return yyyyMMddhhmmss 형식의 문자열 날짜
*/
public static String getCurrentDateTime() {
Date today = new Date();
Locale currentLocale = new Locale("KOREAN", "KOREA");
String pattern = "yyyyMMddHHmmss";
SimpleDateFormat formatter = new SimpleDateFormat(pattern, currentLocale);
return formatter.format(today);
}
/**
* java.util.Date 를 java.util.GregorianCalendar 로 변환한다.
*
* @param date
* @return GregorianCalendar
*/
public static GregorianCalendar dateToGregorianCalendar(Date date) {
if (date == null) return null;
GregorianCalendar cal = new GregorianCalendar(TimeZone.getTimeZone("GMT+09:00"), Locale.KOREAN);
cal.setTime(date);
return cal;
}
/**
* java.util.Date 를 javax.xml.datatype.XMLGregorianCalendar 로 변환한다.
*
* @param date
* @return XMLGregorianCalendar
* @throws javax.xml.datatype.DatatypeConfigurationException
*/
public static XMLGregorianCalendar dateToXMLGregorianCalendar(Date date) throws DatatypeConfigurationException {
if (date == null) return null;
return DatatypeFactory.newInstance().newXMLGregorianCalendar(dateToGregorianCalendar(date));
}
/**
* 시작 시간과 종료 시간의 차이를 포맷팅한다.
*
* @param end 종료 시간
* @param start 시작 시간
* @return "H:M:S" 형식의 시간
*/
public static String formatDiffTime(Date end, Date start) {
long timeDiff = end.getTime() - start.getTime();
return formatTime(timeDiff);
}
/**
* 초단위 시간을 "H:M:S" 형식으로 포맷팅한다.
*
* @param diffLongTime 시간
* @return "H:M:S" 형식의 시간
*/
public static String formatTime(long diffLongTime) {
StringBuffer buf = new StringBuffer();
long hours = diffLongTime / (60 * 60 * 1000);
long rem = (diffLongTime % (60 * 60 * 1000));
long minutes = rem / (60 * 1000);
rem = rem % (60 * 1000);
long seconds = rem / 1000;
if (hours != 0) {
buf.append(hours);
buf.append("시간 ");
}
if (minutes != 0) {
buf.append(minutes);
buf.append("분 ");
}
// 차이가 없다면 0을 반환한다.
buf.append(seconds);
buf.append("초");
return buf.toString();
}
}