1.날짜와 시간
1.1 Calendar 와 Date
- Date -> Calendar(오래 쓰다가 바뀜) -> time
- 실무에서는 아직 Calendar을 쓰기도 한다.
- Calendar 클래스
-> 추상 클래스(인스턴스 생성 불가)이므로 getInstance() - (static)를 통해 구현된 객체를 얻어야 한다.
- Calendar 클래스
- Date와 Calendar 간의 변환
-> Date의 메서드는 대부분 'deprecated-더 이상 사용을 권장하지 않음.'되었지만 여전히 사용한다. "하위 호환성"
- 컴퓨터는 항상 시간을 정수로 저장한다.
- clear(int field)는 Calendar 객체의 모든(특정) 필드를 초기화한다.
-> 1970년 1월 1일 00:00:00 (EPOCH TIME)
- add(): 특정 필드의 값을 증가 또는 감소 (다른 필드에 영향 O)
- roll(): 특정 필드의 값을 증가 또는 감소 (다른 필드에 영향 X)
Ex) Date와 Calendar 간의 변환
<hide/>
package first;
import java.util.*;
public class CalendarEx1 {
public static void main(String[] args) {
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("이 해의 몇 째 주 : " + today.get(Calendar.WEEK_OF_YEAR));
System.out.println("이 달의 몇 째 주 : " + today.get(Calendar.WEEK_OF_MONTH));
//DATE와 DAY_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));
System.out.println("요일(1~7, 1:일요일) : " + today.get(Calendar.DAY_OF_WEEK)); // 1: 일요일, ... 7: 토요일
System.out.println("이 달의 몇 째 요일 : " + today.get(Calendar.DAY_OF_WEEK_IN_MONTH));
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("분(0~59) : " + today.get(Calendar.MINUTE));
System.out.println("초(0~59) : " + today.get(Calendar.SECOND));
System.out.println("1000분의 1초(0~999초) : " + today.get(Calendar.MILLISECOND));
System.out.println("TimeZone(-12~+12) : " + (today.get(Calendar.ZONE_OFFSET)/(60 * 60 * 1000) ));
System.out.println("이 달의 마지막 날 : " + today.getActualMaximum(Calendar.DATE) ); // 이 달의 마지막 날을 찾는다.
}
}
Note) 실행 결과
- getInstance() : 현재 날짜와 시간
- set()메서드를 이용하면 원하는 날짜와 시간 정할 수 있다.
- get(Calendar.MONTH) : 0~11 => 1~12월을 의미한다.
Ex) 두 날짜의 차이 구하기
<hide/>
package javaStudy;
import java.util.*;
public class CalendarEx2 {
public static void main(String[] args) {
// 요일은 1부터 시작하므로 DAY_OF_WEEK[0]은 비워 둔다.
final String[] DAY_OF_WEEK = {"", "일", "월", "화", "수", "목", "금", "토"};
Calendar date1 = Calendar.getInstance();
Calendar date2 = Calendar.getInstance();
//month의 경우 0부터 시작하므로 8월인 경우, 7로 지정한다.
// date1.set(2015, Calendar.AUGUST , 15);
date1.set(2015, 7, 15); // 2015년 8월 15일
System.out.println("date1은 " + toString(date1) + DAY_OF_WEEK[date1.get(Calendar.DAY_OF_WEEK)] + "요일이고, " );
System.out.println("오늘(date2)은 " + toString(date2) + DAY_OF_WEEK[date2.get(Calendar.DAY_OF_WEEK)] + "요일입니다. " );
// 두 날짜간의 차이를 얻으려면, getTimeInMills(): 천분의 일초 단위로 변환해야한다.
long difference = ( date2.getTimeInMillis() - date1.getTimeInMillis()) / 1000;
System.out.println("그 날(date1)부터 지금(date2)까지 " + difference + "초가 지났습니다.");
System.out.println("일(day)로 계산하면 " + difference / (24 * 60 * 60) + "일입니다."); //1일 = 24 * 60 * 60
}
public static String toString(Calendar date) {
return date.get(Calendar.YEAR) + "년 " + date.get(Calendar.MONTH) + "월 " + date.get(Calendar.DATE) + "일 ";
}
}
Note) 실행 결과
- 두 날짜를 최소 단위인 초 단위로 바꾸고 그 차이를 구한다.
- getTimeInMillis() : 1/1000초 단위로 값을 반환하기 때문에
-> '초' 단위로 얻으려면 1000으로 나눈다.
-> '일' 단위로 얻으려면: 24 * 60 * 60 * 1000으로 나눈다.
- add(int field, int amount) : 지정한 필드의 값을 원하는 만큼 증가/감소 시킬 수 있다.
- roll(int field, int amount) : 지정한 필드의 값을 원하는 만큼 증가/감소 시킬 수 있다.(다른 필드의 값에 영향 X)
-> 날짜 필드의 값을 31일 증가시키면 add는 월, 일이 함께 변하지만, roll은 일 필드의 값만 변한다.
Ex)
<hide/>
import java.util.Calendar;
public class CalendarEx {
public static void main(String[] args) {
if(args.length != 2) {
System.out.println("Usage: java Calendar Ex6 2015 9" );
return;
}
int year = Integer.parseInt(args[0]);
int month = Integer.parseInt(args[1]);
int START_DAY_OF_WEEK = 0;
int END_DAY = 0;
Calendar sDay = Calendar.getInstance(); //시작일
Calendar eDay = Calendar.getInstance(); // 끝일
// 월의 경우 0부터 11까지 값을 가지므로 1을 빼준다.
// 예를 들어, 2015년 11월 1일은 sDay.set(2015, 10, 1);과 같이 해줘야 한다.
sDay.set(year, month - 1, 1);
eDay.set(year, month, 1);
eDay.add(Calendar.DATE , -1);
//첫번째 요일을 알아온다.
START_DAY_OF_WEEK = sDay.get(Calendar.DAY_OF_WEEK);
// eDay에 지정된 날짜를 얻어온다.
END_DAY = eDay.get(Calendar.DATE);
System.out.println(" "+ args[0] + "년 " + args[1] + "월" );
System.out.println("SU MO TU WE TH FR SA");
// 해당 월의 1일이 어느요일인지에 따라 공백을 출력한다.
// 만일 1일이 수요일이면 공백을 세번찍는다. (일요일부터 시작)
for(int i = 1; i <START_DAY_OF_WEEK; ++i) {
System.out.print(" ");
}
for(int i = 1 , n = START_DAY_OF_WEEK ; i <= END_DAY; ++i, ++n) {
System.out.print( (i < 10) ? " " + i : " " + i );
if(n % 7 == 0 ) System.out.println();
}
}
}
Note) 실행 결과
- 다음 달의 1일에서 하루를 빼면 이번 달의 마지막 일을 알 수 있다.
2. 형식화 클래스
- java.text 패키지의 DecimalFormat, simpleDateFormat
- 숫자와 날짜를 원하는 형식으로 쉽게 출력 가능(숫자, 날짜 -> 형식 문자열)
- 형식 문자열에서 숫자와 날짜를 뽑아내는 기능(형식 문자열 -> 숫자, 날짜)
- DecimalFormat: 숫자를 형식화할 때
- Number 클래스: 숫자를 저장하는 래퍼 클래스의 조상
-> Integer.parseInt()는 콤마가 포함된 문자열을 숫자로 변환하지 못한다.
2.1 DecimalFormat
- 숫자를 형식화 하는데 사용한다.
2.2 SimpleDateFormat
- 날짜와 시간을 다양한 형식으로 출력할 수 있게 해준다.
- Date와 CalendarFormat만으로는 날짜 데이터를 원하는 형태로 다양하게 출력하기 복잡하다.
Ex)
<hide/>
package javaStudy;
import java.util.*;
import java.text.*;
public class DateFormatEx1 {
public static void main(String[] args) {
Date today = new Date();
SimpleDateFormat sdf1, sdf2, sdf3, sdf4;
SimpleDateFormat sdf5, sdf6, sdf7, sdf8, sdf9;
sdf1 = new SimpleDateFormat("yyyy-MM-dd");
sdf2 = new SimpleDateFormat("''yy년 MMM dd일 E요일");
sdf3 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
sdf4 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss a");
sdf5 = new SimpleDateFormat("오늘은 올해의 D번째 날입니다.");
sdf6 = new SimpleDateFormat("오늘은 이달의 d번째 날입니다.");
sdf7 = new SimpleDateFormat("오늘은 올해의 w번째 주입니다.");
sdf8 = new SimpleDateFormat("오늘은 이달의 W번째 주입니다.");
sdf9 = new SimpleDateFormat("오늘은 이달의 F번째 E요일입니다.");
System.out.println(sdf1.format(today));
System.out.println(sdf2.format(today));
System.out.println(sdf3.format(today));
System.out.println(sdf4.format(today));
System.out.println();
System.out.println(sdf5.format(today));
System.out.println(sdf6.format(today));
System.out.println(sdf7.format(today));
System.out.println(sdf8.format(today));
System.out.println(sdf9.format(today));
}
}
Note) 실행결과
- '(홑따옴표)는 escape기호이기 때문에 패턴 내에서 사용하기 위해서는 연속해서 두 번 사용한다. => ''
- w(오늘은 올해의 몇 번째 주), W(오늘은 이 달의 몇 번째 주)
- D(오늘은 올해의 D번째 날), d(오늘은 올해의 d번째 달)
- F번째 E요일: (오늘은 이달의 F번째 E요일)
Ex)
- Date인스턴스만 format메서드에 사용될 수 있으므로 Calendar인스턴스를 Date인스턴스로 변환해서 사용한다.
- Date인스턴스를 Calendar로 변환할 때는 Calendar클래스의 setTimes()를 사용한다.
Ex)
<hide/>
package first;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Scanner;
public class DateFormatEx4 {
public static void main(String[] args) {
String pattern = "yyyy/MM/dd";
DateFormat df = new SimpleDateFormat(pattern);
Scanner s = new Scanner(System.in);
Date inDate = null;
System.out.println("날짜를 " + pattern + "의 형태로 입력하시오. (입력예: 2015/12/31)");
while(s.hasNextLine()) {
try {
inDate = df.parse(s.nextLine());
break;
}catch(Exception e) {
System.out.println("날짜를 "+ pattern + "의 형태로 다시 입력하시오. (입력예: 2015/12/31)");
}
}
Calendar cal = Calendar.getInstance();
cal.setTime(inDate);
Calendar today = Calendar.getInstance();
long day = ( cal.getTimeInMillis() - today.getTimeInMillis() ) / (60 * 60 * 1000);
System.out.println("입력하신 날짜는 현재와 " +day + "시간 차이가 있습니다.");
}
}
Note) 실행결과
2.3 ChoiceFormat
- 특정 범위에 속하는 값을 문자열로 변환한다.
- 연속적/불연속적인 값을 처리하는데 있어서 if/ switch문은 적절하지 않다.
Ex)
<hide/>
package javaStudy;
import java.text.ChoiceFormat;
public class ChiceFormatEx1 {
public static void main(String[] args) {
double [] limits = {60, 70, 80, 90}; //오름차순으로 적는다.
String [] grades = {"D", "C", "B", "A"};
int [] scores = {100, 95, 88, 70, 52, 60, 70};
ChoiceFormat form = new ChoiceFormat(limits, grades);
for(int i = 0; i < scores.length; ++i) {
System.out.println(scores[i] + ":" + form.format(scores[i]) );
}
}
}
Note) 실행 결과
- limits: 경계값, 경계값은 double형으로 반드시 오름차순으로 정렬
- grades는 치환할 문자열을 저장한다.
- limits와 grades는 개수가 같아야 예외가 발생하지 않는다.
- ChoiceFormat 다른 형태: "limit#value"
-> '#'은 경계값을 범위에 포함, '<'는 범위에 포함하지 않는다.
2.4 MessageFormat
- MessageFormat는 데이터를 정해진 양식에 맞게 출력할 수 있도록 한다.
- SimpleDateFormat 의 parse처럼 MessageFormat의 parse를 이용하면 지정된 양식에서 필요한 데이터만 추출 가능.
Ex)
</hide>
String msg = "Name: {0} \nTel: {1} \nAge: {2} \nBirthday: {3}";
Object[] arguments = {"계란", "010-0000-2222", "20", "2003-01-01"};
String result = MessageFormat.format(msg, arguments);
System.out.println(result);
System.out.println(msg);
Note) 실행 결과
- 0~3 과 같이 arguments 배열 안에 인덱스 범위가 아닌 숫자를 입력할 경우, 중괄호와 숫자가 그대로 출력된다.
3. java.time패키지
3.1 java.time패키지의 핵심클래스
- Calendar 클래스는 날짜와 시간을 하나로 표현 <-> time클래스는 별도의 클래스로 분리한다.
-> 시간(LocalTime) ,날짜(LocalDate), 시간 & 날짜(LocalDateTime)
- Calendar는 ZonedDateTime처럼 날짜, 시간, 시간대까지 모두 가지고 있다.
- Period와 Duration
-> Period: 두 날짜간의 차이
-> Duration: 시간의 차이
- now(): 현재 날짜와 시간을 저장하는 객체 생성
- of(): 해당 필드의 값을 순서대로 지정해주면 된다.
3.2 LocalDate() 와 LocalTime()
- time패키지의 가장 기본이다.
- now(), of() 모두 static 메서드
- 특정 필드의 값 가져오기 - get() , getXXX()
- 날짜와 시간에서 필드의 값 변경하기 - with(), plus(), minus()
-> with() : 원하는 필드를 직접 지정 가능
- 날짜와 시간의 비교 - isAfter(), isBefore(), isEqual()
-> date1.compareTo(date2) : 같으면 0, date1이 이전이면 -1, date1이 이후이면 1
Ex) chronrlogy(연표)
<hide/>
package javaStudy;
import java.time.*;
import java.time.temporal.*;
public class NewTimeEx1 {
public static void main(String[] args) {
LocalDate today = LocalDate.now(); // 오늘의 시간
LocalTime now = LocalTime.now(); // 현재 시간
LocalDate birthDate = LocalDate.of(1999, 12, 31); //1999년 12월 31일
LocalTime birthTime = LocalTime.of(23, 59, 59); // 23시 59분 59초
System.out.println("today = " + today);
System.out.println("now = " + now);
System.out.println("birthDate = " + birthDate); //1999-12-31
System.out.println("birthTime = " + birthTime); //23:59:59
System.out.println(birthDate.withYear(2000)); //2000-12-31
System.out.println(birthDate.plusDays(1)); //2000-01-01
System.out.println(birthDate.plus(1, ChronoUnit.DAYS)); // 2000-01-01
System.out.println(birthTime.truncatedTo(ChronoUnit.HOURS)); // 23:59:59 -> 23:00
System.out.println(ChronoField.CLOCK_HOUR_OF_DAY.range()); // 1 -24
System.out.println(ChronoField.HOUR_OF_DAY.range()); // 0 - 23
}
}
Note) 실행결과
3.3 Instant
- instant는 에포크 타임(1970-01-01-00:00:00 UTC) 부터 경과된 시간을 나노초 단위로 표현한다.
- Instant를 생성할 때는 now() 와 ofEpochSecond()를 사용한다.
3.4 LocalDateTime과 ZonedDateTime
- ZoneOffset
-> UTC로부터 얼마만큼 떨어져있는지를 표현한다.
-> 서울은 +9이다. UTC보다 (32400초 = 60 * 60 * 9 ) 9시간이 빠르다.
Ex)
<hide/>
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class NewTimeEx2 {
public static void main(String[] args) {
LocalDate date = LocalDate.of(2015, 12, 31); // 2015년 12월 31일
LocalTime time = LocalTime.of(12, 34, 56); // 2015년 12월 31일
//2015년 12월 31일 12시 34분 56초
LocalDateTime dt = LocalDateTime.of(date, time);
ZoneId zid = ZoneId.of("Asia/Seoul");
ZonedDateTime zdt = dt.atZone(zid);
// String strZid = zdt.getZone().getId();
ZonedDateTime seoulTime = ZonedDateTime.now();
ZoneId nyId = ZoneId.of("America/New_York");
ZonedDateTime nyTime = ZonedDateTime.now().withZoneSameInstant(nyId);
//ZonwsDatetime -> OffsetDateTime
OffsetDateTime odt = zdt.toOffsetDateTime();
System.out.println(dt);
System.out.println(zid);
System.out.println(zdt);
System.out.println(seoulTime);
System.out.println(nyTime);
System.out.println(odt);
}
}
Note) 실행결과
3.5 Temporaladjusters 클래스
- 자주 쓰일만한 날짜 계산들을 대신 해주는 메서드 정의되어있다.
Ex)
<hide/>
package javaStudy;
import java.time.*;
import java.time.temporal.*;
import static java.time.DayOfWeek.*;
import static java.time.temporal.TemporalAdjusters.*;
class DayAfterTomorrow implements TemporalAdjuster{
@Override
public Temporal adjustInto(Temporal temporal ) {
return temporal.plus(2, ChronoUnit.DAYS);
}
}
public class NewTimeEx3 {
public static void main(String[] args) {
LocalDate today = LocalDate.now();
LocalDate date = today.with(new DayAfterTomorrow());
p(today);
p(date);
p(today.with(firstDayOfNextMonth()));
p(today.with(firstDayOfMonth()));
p(today.with(lastDayOfMonth()));
p(today.with(firstInMonth(TUESDAY)));
p(today.with(lastInMonth(TUESDAY)));
p(today.with(previous(TUESDAY)));
p(today.with(previousOrSame(TUESDAY)));
p(today.with(next(TUESDAY)));
p(today.with(nextOrSame(TUESDAY)));
p(today.with(dayOfWeekInMonth(4, TUESDAY)));
}
static void p(Object obj) {
System.out.println(obj);
}
}
Note) 실행결과
- adjustInto()는 내부적으로만 사용할 의도로 작성되었다. ->( with 사용)
3.6 Period와 Duration
- between() : 두 날짜의 차이를 타나타내는 Period를 얻을 수 있다. (static 메서드)
- until(): between()과 거의 같으나 인스턴스 메서드
- 시간 차이를 이요할 때는 "Duration"
- 특정 필드의 값을 얻을 때는 get()을 이용한다.
- of(), with()
- normalized() : 월의 값이 12을 넘지 않게, 1년 13개월 -> 2년 1개월로 바꿔 준다. (일의 길이는 그대로)
Ex)
<hide/>
package javaStudy;
import java.time.*;
import java.time.temporal.*;
public class NewTimeEx4 {
public static void main(String[] args) {
LocalDate date1 = LocalDate.of(2014, 1, 1);
LocalDate date2 = LocalDate.of(2015, 12, 31);
Period pe = Period.between(date1, date2);
System.out.println("date1 = "+ date1 );
System.out.println("date2 = "+ date2 );
System.out.println("pe = "+ pe );
System.out.println("YEAR = "+ pe.get(ChronoUnit.YEARS));
System.out.println("MONTH = "+ pe.get(ChronoUnit.MONTHS));
System.out.println("DAY = "+ pe.get(ChronoUnit.DAYS));
LocalTime time1 = LocalTime.of(0, 0, 0);
LocalTime time2 = LocalTime.of(12, 34, 56); // 12시간 23분 56초
Duration du = Duration.between(time1, time2);
System.out.println("time1 = "+ time1);
System.out.println("time2 = "+ time2);
System.out.println("du = "+ du);
LocalTime tmpTime = LocalTime.of(0, 0).plusSeconds(du.getSeconds());
System.out.println("HOUR = " + tmpTime.getHour());
System.out.println("MINUTE = " + tmpTime.getMinute());
System.out.println("SECOND = " + tmpTime.getSecond());
System.out.println("NANO = " + tmpTime.getNano());
}
}
Note) 실행결과
3.7 파싱(parsing)과 포맷
- 파싱: 날짜와 시간을 원하는 형식으로 출력하고 해석
- 로케일에 종속된 포맷터를 생성: ofLocalizedDate(), ofLocalizedTime(), odLocalized DateTime()
Ex)
<hide/>
package javaStudy;
import java.time.*;
import java.time.format.*;
public class DateFormatterEx1 {
public static void main(String[] args) {
ZonedDateTime zdateTime = ZonedDateTime.now();
String [] patternArr = {
"yyyy-MM-dd HH:mm:ss",
"''yy년 MMM dd일 E요일",
"yyyy-MM-dd HH:mm:ss.SSS Z VV",
"yyyy-MM-dd hh:mm:ss a",
"오늘은 올해의 D번째 날입니다.",
"오늘은 이달의 d번째 날입니다.",
"오늘은 올해의 w번째 주입니다.",
"오늘은 이달의 W번째 주입니다.",
"오늘은 이달의 W번째 E요일입니다.",
};
for(String p : patternArr) {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(p);
System.out.println(zdateTime.format(formatter));
}
}
}
Note) 실행결과
- MMM: 2월
- SSS: 천분의 일초
- Z: zone-offset , +0900
- VV: 시간대(ID) , Asia/Seoul
- 문자열을 날짜와 시간으로 파싱하기
-> parse()는 오버로딩된 메서드가 여러 개 있다.
-> 다음의 두 가지가 자주 쓰인다.
static LocalDateTime parse(CharSequence text)
static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter)
- 자주 사용되는 기본적인 문자열은 형식화 상수를 사용하지 않고도 파싱이 가능하다.
Ex)
<hide/>
package javaStudy;
import java.time.*;
import java.time.format.*;
public class DateFormatterEx2 {
public static void main(String[] args) {
LocalDate newYear = LocalDate.parse("2016-01-01", DateTimeFormatter.ISO_LOCAL_DATE);
LocalDate date = LocalDate.parse("2001-01-01");
LocalTime time = LocalTime.parse("23:59:59");
LocalDateTime dateTime = LocalDateTime.parse("2001-01-01T23:59:59");
DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
LocalDateTime endOfYear = LocalDateTime.parse("2015-12-31 23:59:59", pattern);
System.out.println(newYear);
System.out.println(date);
System.out.println(time);
System.out.println(dateTime);
System.out.println(endOfYear);
}
}
Note) 실행 결과
- ofPattern()을 이용해서 파싱한다.
'Java > Java의 정석' 카테고리의 다른 글
Chapter 12 지네릭스, 열거형, 에너테이션 (0) | 2022.03.02 |
---|---|
Chapter 11 컬렉션 프레임웍(Collection Framework) (0) | 2022.03.02 |
Chapter 09 java.lang 패키지와 유용한 클래스 (0) | 2022.02.24 |
Chapter 08 예외처리 Exception Handling (0) | 2022.02.23 |
Chapter 07 객체지향 프로그래밍 II (0) | 2022.02.22 |