Java 1.0에서는 Date 클래스를 사용하여 날짜에 관한 처리를 했었으나, Date 클래스는 현재 대부분 메서드 사용을 권장하고 있지 않다. (Deprecated)
java.time.chrono
ISO-8601에 정의된 표준 달력 이외의 달력 시스템을 사용할 때 필요한 클래스들
java.time.format
날짜와 시간에 대한 데이터를 구문분석하고 형식화하는 데 사용되는 클래스들
java.time.temporal
날짜와 시간에 대한 데이터를 연산하는 데 사용되는 보조 클래스들
java.time.zone
타임 존(time-zone)과 관련된 클래스들
java.time 패키지 클래스
LocalDate
날짜를 처리할 때 사용한다.
LocalTime
시간을 처리할 때 사용한다.
LocalDateTime
날짜와 시간을 한 번에 처리할 수 있다.
ZonedDateTime
특정 타임 존(time-zone)에 해당하는 날짜와 시간을 다루는데 사용된다.
Instant
특정 시점의 날짜와 시간을 나노초(nanosecond) 단위로 표현하는 타임스탬프(time-stamp)를 다루는데 사용된다.
Period
두 날짜 사이의 차이를 처리하는데 사용되며, Duration 클래스는 두 시간 사이의 차이를 표현하는데 사용된다.
Java 8 버전 이전의 날짜/시간을 처리하는 클래스
java.lang.System
현재 시간을 밀리초 단위로 변환하는 currentTimeMillis() 메서드를 제공한다.
java.util.Date
특정 순간을 밀리초 단위로 표시하는데 사용된다.
java.util.Calendar
다양한 방식으로 필드를 조작하기 위한 메서드를 제공하는 추상 클래스다.
java.text.SimpleDateFormat
미리 정의된 방식 또는 사용자 정의 패턴으로 날짜를 포맷화하고, 구문 분석하는데 사용되는 클래스다.
java.util.TimeZone
시간대 오프셋을 나타낸다. 전 세계의 타임존에 맞는 시간을 구할 때 사용할 수 있다.
스레드 안정성
Date 및 Calendar와 같은 클래스는 스레드 안정성을 제공하지 않아 개발자가 처리해야 하기 때문에 동시성 문제가 발생해도 확인이 어렵다. Java 8의 새로운 Date/Time API는 스레드 안전성을 제공하고 변경할 수 없으므로 개발자의 동시성 문제를 방지한다.
Bad API 설계
Date 및 Calendar API는 기본적인 일상 기능을 수행하는 메서드를 제공하지 않는데, Java 8에 도입된 Date/Time 클래스는 ISO(국제 표준) 중심이며, 날짜, 시간, 기간 및 기간과 관련된 작업을 수행하기 위한 다양한 방법을 제공한다.
어려운 Time zone 처리
Date 및 Calendar 클래스를 사용하여 time zone을 처리하는 것은 개발자가 코드로 작성하기 어려웠으나 새로 도입된 API를 사용하면 Local 및 ZonedDate/Time API를 사용하여 time zone 처리를 쉽게 수행할 수 있다.
LocalDate 클래스에서 제공하는 대표적인 getter 메서드는 아래와 같다.
Method | Description |
---|---|
Int get(TemporalField field) long getLong(TemporalField field) | 해당 날짜 객체의 명시된 필드의 값을 int형이나 long형으로 반환한다. |
Int getYear() | 해당 날짜 객체의 연도(YEAR) 필드의 값을 반환한다. |
Month getMonth() | 해당 날짜 객체의 월(MONTH_OF_YEAR) 필드의 값을 Month 열거체를 이용하여 반환한다. |
Int getMonthValue() | 해당 날짜 객체의 월(MONTH_OF_YEAR) 필드의 값을 반환한다(1~12). |
Int getDayOfMonth() | 해당 날짜 객체의 일(DAY_OF_MONTH) 필드의 값을 반환한다(1~31). |
Int getDayOfYear() | 해당 날짜 객체의 일(DAY_OF_YEAR) 필드의 값을 반환한다(1~365, 윤년이면 366). |
Int getDayOfWeek() | 해당 날짜 객체의 일(DAY_OF_WEEK) 필드의 값을 DayOfWeek 열거체를 이용하여 반환한다. |
예제(DayOfWeek 열거체의 getDisplayName() 메서드의 TextStyle 열거체와 Locale 클래스를 이용해서 원하는 형태로 요일을 표현할 수 있다.)
public class LocalDateTimeEx2 {
public static void main(String args[]){
LocalDate today = LocalDate.now();
System.out.println("올해는 " + today.getYear() + "년입니다.");
System.out.println("이번달은 " + today.getMonthValue() + "월입니다.");
System.out.println("오늘은 " + today.getDayOfWeek() + "입니다.");
System.out.println("오늘은 1년 중 " + today.get(ChronoField.DAY_OF_YEAR) + "일째 날입니다.");
DayOfWeek dayOfWeek = today.getDayOfWeek();
// 텍스트 요일 구하기 (영문)
System.out.println(dayOfWeek.getDisplayName(TextStyle.FULL, Locale.US)); // Sunday
System.out.println(dayOfWeek.getDisplayName(TextStyle.NARROW, Locale.US)); // S
System.out.println(dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.US)); // Sun
System.out.println("-----");
// 텍스트 요일 구하기 (한글)
System.out.println(dayOfWeek.getDisplayName(TextStyle.FULL, Locale.KOREAN)); // 일요일
System.out.println(dayOfWeek.getDisplayName(TextStyle.NARROW, Locale.KOREAN)); // 일
System.out.println(dayOfWeek.getDisplayName(TextStyle.SHORT, Locale.KOREAN)); // 일
System.out.println("-----");
// 텍스트 요일 구하기 (default)
System.out.println(dayOfWeek.getDisplayName(TextStyle.FULL, Locale.getDefault())); // 일
}
}
[결과]
올해는 2023년입니다.
이번달은 1월입니다.
오늘은 SUNDAY입니다.
오늘은 1년 중 15일째 날입니다.
Sunday
S
Sun
-----
일요일
일
일
-----
일요일
LocalTime 클래스에서 제공하는 대표적인 getter 메서드는 아래와 같다.
Method | Description |
---|---|
Int get(TemporalField field) long getLong(TemporalField field) | 해당 시간 객체의 명시된 필드의 값을 int형이나 long으로 반환한다. |
Int getHour() | 해당 시간 객체의 시(HOUR_OF_DAY) 필드의 값을 반환한다. |
Int getMinute() | 해당 시간 객체의 분(MINUTE_OF_HOUR) 필드의 값을 반환한다. |
Int getSecond() | 해당 시간 객체의 초(SECOND_OF_MINUTE) 필드의 값을 반환한다. |
Int getNano() | 해당 시간 객체의 나노초(NANO_OF_SECOND) 필드의 값을 반환한다. |
public class LocalDateTimeEx3 {
public static void main(String args[]){
LocalTime present1 = LocalTime.now();
System.out.println("현재 시각은 " +
present1.getHour() + "시 " +
present1.getMinute() + “분입니다.");
}
}
[결과]
현재 시각은 20시 10분입니다.
날짜와 시간 객체의 필드값을 변경하기 위해 LocalDate와 LocaTime 클래스는 withXXX() 메서드를 제공한다.
withXXX() 메서드를 사용하면 값이 변경될 필드를 개발자가 직접 명시할 수 있다.
Method | Description |
---|---|
LocalDate with(TemporalField field, long newValue) | 해당 날짜 객체에서 특정 필드를 전달받은 값으로 설정한 날짜 객체를 반환한다. |
LocalDate withYear(int year) | 해당 날짜 객체에서 연도(YEAR) 필드를 전달받은 값으로 설정한 날짜 객체를 반환한다. |
LocalDate withMonth(int month) | 해당 날짜 객체에서 월(MONTH_OF_YEAR) 필드를 전달받은 값으로 설정한 날짜 객체를 반환한다. |
LocalDate withDayOfMonth(int dayOfMonth) | 해당 날짜 객체에서 일(DAY_OF_MONTH) 필드를 전달받은 값으로 설정한 날짜 객체를 반환한다. |
LocalDate withDayOfYear(int dayOfYear) | 해당 날짜 객체에서 DAY_OF_YEAR 필드를 전달받은 값으로 설정한 날짜 객체를 반환한다. |
public class LocalDateTimeEx4 {
public static void main(String args[]) {
LocalDate today = LocalDate.now();
System.out.println("올해는 " + today.getYear() + "년입니다.");
LocalDate otherDay = today.withYear(1982);
System.out.println("올해는 " + otherDay.getYear() + "년입니다.");
}
}
[결과]
올해는 2023년입니다.
올해는 1982년입니다.
LocalTime 클래스 객체에 접근하여 특정 필드의 값을 변경하기 위한 withXXX() 메서드는 아래와 같다.
Method | Description |
---|---|
LocalTime with(TemporalField field, long newValue) | 해당 시간 객체에서 특정 필드를 전달받은 값으로 설정한 시간 객체를 반환한다. |
LocalTIme withHour(int hour) | 해당 시간 객체에서 시(HOUR_OF_DAY) 필드를 전달받은 값으로 설정한 시간 객체를 반환한다. |
LocalTIme withMinute(int minute) | 해당 시간 객체에서 분(MINUTE_OF_HOUR) 필드를 전달받은 값으로 설정한 시간 객체를 반환한다. |
LocalTime withSecond(int second) | 해당 시간 객체에서 초(SECOND_OF_MINUTE) 필드를 전달받은 값으로 설정한 시간 객체를 반환한다. |
LocalDate withDayOfYear(int dayOfYear) | 해당 시간 객체에서 나노초(NANO_OF_SECOND) 필드를 전달받은 값으로 설정한 시간 객체를 반환한다. |
public class LocalDateTimeEx5{
public static void main(String[] args){
LocalTime present = LocalTime.now();
System.out.println("현재 시각은 " + present.getHour() + "시입니다.");
LocalTime otherTime = present.withHour(8);
System.out.println("현재 시간은 " + otherTime.getHour() + "시입니다.");
}
}
[결과]
현재 시각은 20시입니다.
현재 시각은 8시입니다.
LocalDate와 LocalTime 클래스에도 객체를 비교할 수 있는 compareTo() 메서드가 오버라이딩되어 있다.
이외에 비교할 수 있는 메서드를 제공한다.
isEqual()
LocalDate 클래스에서만 제공하며 날짜만을 비교한다.
isBefore()
두 개의 날짜와 시간 객체를 비교하여 현재 객체가 명시된 객체보다 이전 시간인지를 비교한다.
isAfter()
두 개의 날짜와 시간 객체를 비교하여 현재 객체가 명시된 객체보다 늦은 시간인지를 비교한다.
public class LocalDateTimeEx6{
public static void main(String[] args){
LocalDate today = LocalDate.now();
LocalDate otherDay = LocalDate.of(1982, 02, 19);
System.out.println(today.compareTo(otherDay));
System.out.println(today.isBefore(otherDay));
System.out.println(today.isEqual(otherDay));
}
}
[결과]
41
false
false
public class LocalDateTimeEx3 {
public static void main(String args[]){
LocalTime present2 = LocalTime.now();
String ampm;
if(present2.get(ChronoField.AMPM_OF_DAY) == 0) {
ampm = "오전";
} else {
ampm = "오후";
}
System.out.println("지금은 " + ampm + " " +
present2.get(ChronoField.HOUR_OF_AMPM) + "시입니다.");
}
}
[결과]
지금은 오후 9시입니다.
열거체 상수 | 설명 |
---|---|
ERA | 시대 |
YEAR | 연도 |
MONTH_OF_YEAR | 월 |
DAY_OF_MONTH | 일 |
DAY_OF_WEEK | 요일 (월요일:1, 화요일:2, … , 일요일:7) |
AMPM_OF_DAY | 오전/오후 |
HOUR_OF_DAY | 시(0~23) |
CLOCK_HOUR_OF_DAY | 시(1~24) |
HOUR_OF_AMPM | 시(0~11) |
CLOCK_HOUR_OF_AMPM | 시(1~12) |
MINUTE_OF_HOUR | 분 |
SECOND_OF_MIN | 초 |
DAY_OF_YEAR | 해당 연도의 몇 번째 날 (1~365, 윤년이면 366) |
EPOCH_DAY | EPOCH(1970년 1월 1일)을 기준으로 몇 번째 날 |
public abstract class Calendar implements Serializable, Cloneable, Comparable<Calender>{
...
}
...
Calendar cal = Calendar.getInstance();
Calendar cal = Calendar.getInstance();
Date date = new Date(cal.getTimeInMillis());
Date date2 = new Date();
Calendar cal2 = Calendar.getInstance();
cal2.setTime(date2);
예제
Calendar today = Calendar.getInstance();
System.out.println("올해의 년도 : "+ today.get(Calendar.YEAR));
System.out.println("월(0~11, 0:1월): "+ today.get(Calendar.MONTH));
System.out.println("월(0~11, 0:1월): "+ today.get(Calendar.MONTH)+1;
System.out.println("올해의 몇 째 주: "+ today.get(Calendar.WEEK_OF_YEAR));
System.out.println("이달의 몇 째 주: "+ today.get(Calendar.WEEK_OF_MONTH));
System.out.println("이달의 며칠: "+ today.get(Calendar.DATE));
System.out.println("이달의 며칠: "+ today.get(Calendar.DAY_OF_MONTH));
System.out.println("올해의 며칠: "+ today.get(Calendar.DAY_OF_YEAR));
//1:일요일, 2:월요일...
System.out.println("요일(1~7, 1:일요일): "+ today.get(Calendar.DAY_OF_WEEK));
System.out.println("오전_오후(0:오전, 1:오후): "+ today.get(Calendar.AM_PM));
System.out.println("시간(0~11): "+ today.get(Calendar.HOUR));
System.out.println("시간(0~23): "+ today.get(Calendar.HOUR_OF_DAY));
System.out.println("이달의 마지막 날: "+ today.getActualMaximum(Calendar.DATE));
[결과]
올해의 년도: 2022
월(0~11, 0:1월): 2
월(0~11, 0:1월): 3
올해의 몇 째 주: 14
이달의 몇 째 주: 5
이달의 며칠: 28
이달의 며칠: 28
올해의 며칠: 87
요일(1~7, 1:일요일): 2
오전_오후(0:오전, 1:오후): 0
시간(0~11): 1
시간(0~23): 1
이달의 마지막 날: 31
예제: SimpleDateFormat 클래스를 사용하여 날짜 및 시간형식 출력
public class SimpleDateFormatEx2{
public static void main(String[] args){
Date date = new Date();
SimpleDateFormat formatter = new SimpleDateFormat("MM/dd/yyyy");
String strDate = formatter.format(date);
System.out.println("Date Format MM/dd/yyyy : "+strDate);
formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss");
strDate = formatter.format(date);
System.out.println("Date Format dd-M-yyyy hh:mm:ss : "+strDate);
formatter = new SimpleDateFormat("dd MMMM yyyy");
strDate = formatter.format(date);
System.out.println("Date Format dd MMMM yyyy : "+strDate);
formatter = new SimpleDateFormat("dd MMMM yyyy zzzz");
strDate = formatter.format(date);
System.out.println("Date Format dd MMMM yyyy zzzz : "+strDate);
formatter = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss z");
strDate = formatter.format(date);
System.out.println("Date Format E, dd MMM yyyy HH:mm:ss z : "+strDate);
}
}
[결과]
Date Format MM/dd/yyyy : 01/09/2023
Date Format dd-M-yyyy hh:mm:ss : 09-1-2023 02:30:06
Date Format dd MMMM yyyy : 09 1월 2023
Date Format dd MMMM yyyy zzzz : 09 1월 2023 대한민국 표준시
Date Format E, dd MMM yyyy HH:mm:ss z : 월, 09 1월 2023 02:30:06 KST
Format 형태
문자 | Date 요소 | 예시 |
---|---|---|
G | 연대 | AD |
Y | 년도 | 2020 |
M | 월(1~12 or 01~12) | 7 |
w | 년의 몇 번째 주(1~53) | 5 |
D | 년의 몇 번째 일(1~366) | 50 |
d | 월의 몇 번째 일(1~31) | 11 |
F | 월의 몇 번째 요일(1~5) | 3 |
E | 요일 | Tue or 화 |
a | 오전/오후(AM,PM) | AM |
H | 24시를 0시부터 본 경우 (0~23) | 0 |
k | 24시를 24시로 본 경우 (1~24) | 24 |
K | 12시를 0시로 본 경우 (0~11) | 0 |
h | 12시를 12시로 본 경우 (1~12) | 12 |
m | d분(m) | 30 |
s | 초(s) | 35 |
S | 밀리초(ms) | 978 |
z | 타임존 | KST |
SimpleDateFormat formatter = new SimpleDateFormat("yyy.MM.dd HH:mm:ss");
예시 2023.01.16 07:35:20
yyyy: 2023과 같이 년도를 4자리로 표현하라는 의미
MM: 월을 의미
dd: 일을 의미
HH: 24시간을 기준으로 시간을 표시
mm: 분을 의미
ss: 초를 의미
Pattern 클래스의 지원 메서드
Method | Description |
---|---|
compile(String regex) | 주어진 정규표현식을 컴파일하고 패턴의 인스턴스를 리턴한다. |
matcher(CharSequence input) | input 인자값 패턴과 일치시키는 matcher를 생성한다. |
boolean matches(String regex, CharSequence input) | 정규식을 컴파일하고 input 인자값을 패턴과 일치하는지 여부를 리턴한다. |
pattern() | 컴파일된 정규표현식을 String 형태로 리턴한다. |
split(CharSequence input) | 주어진 패턴의 일치 항목을 기준으로 주어진 입력 문자열을 분할한다. |
Metacharacters
표현식 | 설명 | 표현식 | 설명 |
---|---|---|---|
^ | 문자열의 시작 | \w | 알파벳이나 숫자 |
$ | 문자열의 끝 | \W | 알파벳이나 숫자를 제외한 문자 |
. | 임의의 한 문자 | \d | [0-9]와 동일 |
* | 문자가 0번 이상 발생 | \D | 숫자를 제외한 모든 문자 |
+ | 문자가 1번 이상 발생 | \z | 입력의 끝 |
? | 문자가 0번 혹은 1번 발생 | \Z | 입력의 끝이지만 종결자가 있는 경우 |
[ ] | 문자의 집합 범위를 나타내며 앞에 ^가 붙으면 not을 의미 | ||
[0-9]: 숫자 (0부터 9), [a-z]: 알파벳 (a부터 z) | \s | 공백문자 | |
{ } | 횟수 또는 범위를 의미 | \S | 공백문자가 아닌 나머지 문자 |
( ) | 소괄호 안의 문자를 하나의 문자로 인식 | \b | 단어의 경계 |
or 조건 | \B |
자주 사용하는 정규표현식
정규 표현식 | 설명 |
---|---|
^[0-9]*$ | 숫자 |
^[a-zA-Z]*$ | 영문자 |
^[가-힣]*$ | 한글 |
[0-9a-zA-Z]+(.[_a-z0-9-]+)*@(?:\\w+\\.)+\\w+$ | 이메일 주소 |
^\d{2,3}-\d{3,4}-\d{4}$ | 전화번호 |
^01(?:0|1|[6-9])-(?:\d{3}|\d{4})-\d{4}$ | 핸드폰 번호 |
\d{6}\-[1-4]\d{6} | 주민등록 번호 |
^\d{3}-\d{2}$ | 우편번호 |
Pattern 클래스 예제
//숫자만 있는지 확인
String pattern = "^[0-9]*$";
String str = "728349872";
//첫 번째 파라미터는 정규 표현식, 두 번째 파라미터는 매칭 확인 대상 문자열
boolean result = Pattern.matches(pattern, str);
System.out.println(result); //true
//메서드를 연결하여 결과를 얻을 수도 있다
boolean result2 = Pattern.compile("^[0-9]*$").matcher("728349872").matches();
System.out.println(result2); //true
//matches 메서드를 통해 결과를 얻을 수도 있다
boolean result3 = Pattern.matches("^[0-9]*$","728349872");
System.out.println(result3); //true
[결과]
true
true
true
Matcher 클래스의 지원 메서드
Method | Description |
---|---|
matches() | 대상 문자열과 패턴이 일치하는 경우 true를 리턴한다. |
find() | 대상 문장열과 패턴이 일치하는 경우 true를 리턴하고 그 위치로 이동한다. |
start() | 매칭되는 문자열의 시작 위치를 리턴한다. |
end() | 매칭되는 문자열 끝의 바로 다음 위치를 리턴한다. |
group() | 매칭된 부분을 리턴한다. |
groupCount() | 패턴내 그룹핑한 전체 개수를 반환한다. |
Matcher 예제
//숫자만 있는지 확인
Pattern pattern = Pattern.compile("^[0-9]*$");
String str = "728349872";
Matcher matcher = pattern.matcher(str);
System.out.println(matcher.find());
[결과]
true