JiwonDev

Java μ—μ„œ μ‹œκ°„μ„ κ΄€λ¦¬ν•˜λŠ” 방법 (Instant.now(), LocalDate.now())

by JiwonDev

 

JDK8 java.time μ‚¬μš©λ²•λ§Œ λ°”λ‘œ μ•Œκ³  μ‹Άλ‹€λ©΄:

 

μžλ°”8의 java.time νŒ¨ν‚€μ§€(LocalDate, LocalTime, LocalDateTime λ“±)

μ˜ˆμ „μ— JPA와 LocalDate, LocalDateTime μ‚¬μš©ν•˜κΈ° μ—μ„œ μžλ°”8μ—μ„œ μΆ”κ°€λœ μƒˆλ‘œμš΄ λ‚ μ§œμ™€ μ‹œκ°„μ— λŒ€ν•œ API에 λŒ€ν•΄μ„œ κ°„λ‹¨ν•˜κ²Œ 글을 μΌμ—ˆλ‹€. μ΄λ²ˆμ—λŠ” μžλ°”8에 μΆ”κ°€λœ λ‚ μ§œμ™€ μ‹œκ°„ API에 λŒ€ν•΄μ„œ 쑰금 더 μžμ„Έ

blog.eomdev.com

 

😱 달λ ₯κ³Ό μ‹œκ°„μ€ κ·Έ μžμ²΄λ‘œλ„ λ³΅μž‘ν•©λ‹ˆλ‹€.

1년은 지ꡬ가 νƒœμ–‘μ„ ν•œλ°”ν€΄λ₯Ό κ·œμΉ™μ μœΌλ‘œ λ„λŠ” μ‹œκ°„μ„ μž°κ²ƒμž…λ‹ˆλ‹€. 365.2421일 μ •λ„λ˜κ³ , 맀년 0.000001일 정도 μ˜€μ°¨κ°€ μ‘΄μž¬ν•©λ‹ˆλ‹€.

 

율리우슀λ ₯(Julian Calendar)

μš°λ¦¬κ°€ 많이 μ“°λŠ” 12μ›” 달λ ₯ μ²΄κ³„λŠ” λ‘œλ§ˆμ—μ„œ μ „νŒŒλ˜κΈ° μ‹œμž‘ν–ˆμŠ΅λ‹ˆλ‹€. κ·Έ λ‹Ήμ‹œμ—λŠ” 봄이 1μ›”μ΄μ—ˆκ³  μ§μˆ˜λ‹¬μ΄ 30인 κ·œμΉ™μ„±μ΄ μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

  • μ›λž˜ λ΄„(march)이 ν•œν•΄μ˜ μ‹œμž‘μ΄μ—ˆμœΌλ‚˜ 율리우슀 μ·¨μž„ λ§žμΆ”λ €κ³  걍 3μ›”λ‘œ λ³€κ²½ν•©λ‹ˆλ‹€.(κΈ°μ‘΄ sex:6 sep:7 octo:8 nov:9 dec:10)

달λ ₯의 이름은 μ‹ μ˜ μ΄λ¦„μ΄λ‚˜ μ„œμˆ˜(six->sextilis)둜 μ§€μ—ˆμŠ΅λ‹ˆλ‹€. 이후 7, 8월은 둜마 ν™©μ œ 이름 λ°•νžˆκ²Œλ¨(Julius, Augustus)

  • 1년은 365μΌμ΄λ―€λ‘œ 31-30 κ·œμΉ™μœΌλ‘œ ν•˜κΈ°μ—” ν•˜λ£¨κ°€ λΆ€μ‘±ν•©λ‹ˆλ‹€. 12μ›”(ν˜„μž¬μ˜ 2μ›”)은 λ§ˆμ§€λ§‰μ΄ 29일이 λ©λ‹ˆλ‹€.
  • 이 λ‹Ήμ‹œμ—λ„ 1년은 365.25일 μ •λ„μž„μ„ μ•Œκ³ μžˆμ—ˆκ³  κ·Έλž˜μ„œ 4λ…„λ§ˆλ‹€ 12μ›” 30일(ν˜„μž¬μ˜ 2μ›”)을 μΆ”κ°€ν•˜λŠ” μœ€λ…„μ„ λ§Œλ“­λ‹ˆλ‹€. 
  • μ•„μš°κ΅¬μŠ€νˆ¬μŠ€κ°€ λ‹€μŒ ν™©μ œλ₯Ό λ¬Όλ €λ°›μž, 본인 이름을 8월에 λ°•κ³  31일둜 λŠ˜λ €λ²„λ¦½λ‹ˆλ‹€. λΆ€μ‘±ν•œ ν•˜λ£¨λŠ” 12μ›”(ν˜„μž¬μ˜ 2μ›”)에 λ•Œμ˜΅λ‹ˆλ‹€.
  • μ΄λ ‡κ²Œ BC46(2069λ…„μ „) μ •λ¦½λœ 이 달λ ₯은 율리우슀λ ₯μ΄λΌλŠ” μ΄λ¦„μœΌλ‘œ 널리 퍼져 μ²œλ…„μ΄ λ„˜λŠ” κΈ°κ°„λ™μ•ˆ μ‚¬μš©λ˜κ²Œ λ©λ‹ˆλ‹€.

 

 

그레고리λ ₯(Gregorian Calendar)

1년은 365.2421 정도 λ©λ‹ˆλ‹€.

율리우슀λ ₯의 365.25의 μ˜€μ°¨κ°€ 1500λ…„κ°„ μŒ“μ—¬μ„œ μ‹€μ œ κ³„μ ˆκ³Ό 10일이 λ„˜κ²Œ 차이가 생겨버렸고, 점점 더 개판이 λ˜μ–΄κ°€κ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€.

λ‹Ήμ‹œ ꡐ황 κ·Έλ ˆκ³ λ¦¬λŠ” 1582λ…„ 10μ›”4일(λͺ©) λ‹€μŒλ‚ μ„ 10μ›”15일(금)으둜 κ³Όκ°ν•˜κ²Œ 바꿔버리고 μ•„λž˜μ˜ 그레고리λ ₯을 λ§Œλ“­λ‹ˆλ‹€.

  • 연도가 100의 배수(1900,2000,2100)인 ν•΄λŠ” μœ€λ…„μ„ λ¬΄μ‹œν•˜κ³  평년(2μ›” 28일)을 μ‚¬μš©ν•œλ‹€
  • 단 κ·Έ 쀑 400의 배수인 ν•΄λŠ” μ˜ˆμ™Έμ μœΌλ‘œ 무쑰건 μœ€λ…„(2μ›” 29일)을 μ‚¬μš©ν•œλ‹€.
  • 이러면 10λ§Œλ…„μ— 1μΌμ •λ„λ‘œ 였차λ₯Ό 쀄일 수 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 단 율리우슀λ ₯κ³Ό λ‹€λ₯΄κ²Œ 그레고리λ ₯은 λͺ¨λ“  κ΅­κ°€κ°€ μ‚¬μš©ν•˜λŠ”κ±΄ μ•„λ‹™λ‹ˆλ‹€.

ν˜„λŒ€μ—μ„œλŠ” μ •λ°€ν•œ μ„Έκ³„μ‹œκ°„(UTC)κ°€ μ‘΄μž¬ν•˜κ³ , ν•„μš”ν•˜λ‹€λ©΄ 초 λ‹¨μœ„λ‘œ λ³΄μ •ν•΄μ„œ μ‚¬μš©ν•˜κΈ°λ„ ν•©λ‹ˆλ‹€.

 

 

세계 μ‹œκ°„ ν˜‘μ • UTC (Universel Time Coordinated)

1972λ…„, 영ꡭ의 κ·Έλ¦¬λ‹ˆμΉ˜ μ²œλ¬ΈλŒ€λ₯Ό κΈ°μ€€μœΌλ‘œ 1970λ…„ 1μ›” 1일 0μ‹œ 0λΆ„ 0초λ₯Ό μ‹œμž‘μœΌλ‘œ μ •μ˜ν•˜λŠ” 세계 μ‹œκ°„ ν‘œμ€€ UTCκ°€ μ •λ¦½λ©λ‹ˆλ‹€.

사싀 μ˜κ΅­μ—μ„œλŠ” GMT(Greenwich Mean Time) 라고 이름을 μ§€μ—ˆμœΌλ‚˜, μ„Έκ³„μ˜ 반발으둜 UTC둜 이름이 μ •ν•΄μ§‘λ‹ˆλ‹€.

참고둜 1970λ…„μ—” μ„ΈμŠ˜μ›μžμ‹œκ³„λ₯Ό μ‚¬μš©ν•˜λ‹€κ°€, 2021년에 빛을 μ΄μš©ν•˜λŠ” κ΄‘μ‹œκ³„λ‘œ λ³€κ²½ν•˜λ©° UTCλŠ” 1초의 μ†Œμˆ˜μ  16μžλ¦¬κΉŒμ§€ μΈ‘μ •λ©λ‹ˆλ‹€. 

UTC(Coordinated Universal Time)λŠ” 세계 ν‘œμ€€μ‹œλ‘œμ„œ, 컴퓨터와 λ„€νŠΈμ›Œν¬μ—μ„œ μ‹œκ°„μ„ ν‘œμ‹œν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ©λ‹ˆλ‹€. UTCλŠ” 1972λ…„ ITU(International Telecommunication Union)μ—μ„œ κ³΅μ‹μ μœΌλ‘œ μ±„νƒλ˜μ—ˆμœΌλ©°, μ΄μ „μ—λŠ” GMT(Greenwich Mean Time)λΌλŠ” μ΄λ¦„μœΌλ‘œ μ‚¬μš©λ˜μ—ˆμŠ΅λ‹ˆλ‹€.

ν•œκ΅­ μ‹œκ°„μ˜ ν‘œμ€€μΈ μ„œμšΈ(KR_ZONE)은 UTC에 9μ‹œκ°„μ„ λ”ν•˜λ©΄ κ°™μ•„μ§€λ―€λ‘œ UTC/GMT+9 κ°€ λ©λ‹ˆλ‹€.

 

 

μ»΄ν“¨ν„°μ—μ„œ μ‹œκ°„μ„ μ €μž₯ν•˜λŠ” 방법

λΉ„μŠ·ν•œ μ‹œκΈ°μ— νƒ„μƒν•œ 컴퓨터도 세계 ν‘œμ€€μ‹œκ°„μΈ UTC/GMTλ₯Ό μ‚¬μš©ν•©λ‹ˆλ‹€.

κ·Έ λ‹Ήμ‹œ Unix μš΄μ˜μ²΄μ œμ—μ„œλŠ” Unix Time λΌλŠ” μ΄λ¦„μœΌλ‘œ UTCλ₯Ό 밀리 초 λ‹¨μœ„(1/1000)인 μ •μˆ˜κ°’μœΌλ‘œ κ΄€λ¦¬ν–ˆμŠ΅λ‹ˆλ‹€. 이 Unix Time을 μš°νŽΈλ¬Όμ— μ‚¬μš©ν•˜λŠ” TimeStamp 라고 λΆ€λ₯΄κΈ°λ„ ν–ˆλŠ”λ°, μ΄λŠ” μ§€κΈˆλ„ μ“°μ΄λŠ” 단어죠.

long millis = System.currentTimeMillis();

// 2023λ…„ 1μ›” 28일(UTC+9) 20μ‹œ 12뢄은 1674904313535 λ°€λ¦¬μ΄ˆμž…λ‹ˆλ‹€.
System.out.println(millis); // prints a Unix timestamp in milliseconds

// 2023λ…„ 1μ›” 28일(UTC+9) 20μ‹œ 12뢄은 1674904313 μ΄ˆμž…λ‹ˆλ‹€.
System.out.println(millis / 1000); // prints the same Unix timestamp in seconds
  • Unix Time λŒ€μ‹  1970년인 νŠΉμ • μ‹œλŒ€(epoch)λ₯Ό κΈ°μ€€μœΌλ‘œν•˜λŠ” 밀리 초 κ°’μ΄λΌλŠ” 의미둜 (Epoch millisecond) 라고도 λΆ€λ¦…λ‹ˆλ‹€. 
  • UTC와 같은 값인데 μ΄λ¦„λ§Œ λ‹¬λΌμ„œ POSIX time이라고도 λΆ€λ¦…λ‹ˆλ‹€. λ¬Όλ‘  ν˜„λŒ€μ˜ UTCλŠ” μ†Œμˆ«μ  λ‹¨μœ„κΉŒμ§€ 가기에 Unix Timeκ³Ό λ―Έμ„Έν•˜κ²Œ λ‹€λ¦…λ‹ˆλ‹€.

μ„œλ₯˜μ— μ°λŠ” TimeStamp

 

 

λ„€, λ¨Ό 길을 λŒμ•„μ™”μŠ΅λ‹ˆλ‹€. 이제 μš°λ¦¬λŠ” μ•„λž˜ μžλ°” μ½”λ“œμ— 달린 주석을 이해할 수 있게 λ©λ‹ˆλ‹€.

1970λ…„ 1μ›” 1일이 UTC 0μ΄ˆμ΄λ―€λ‘œ, κ·Έ 이전은 μŒμˆ˜κ°’μ΄ λ©λ‹ˆλ‹€.

 

 


πŸ• μžλ°”μ—μ„œμ˜ μ‹œκ°„

μ˜›λ‚  μžλ°”λŠ” java.util.Date, java.util.Time, java.sql.Timestamp 3가지 객체λ₯Ό μ‚¬μš©ν•˜κ³  달λ ₯이 ν•„μš”ν•˜λ©΄ GregorianCalendarλ₯Ό μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ 2014λ…„ JDK8μ—μ„œ κΈ°μ‘΄ μ‹œκ°„ 객체듀이 Deprecated 되고 java.time νŒ¨ν‚€μ§€κ°€ μΆ”κ°€λ©λ‹ˆλ‹€. μžλ°”μ˜ μ‹œκ°„κ³Ό κ΄€λ ¨λœ 객체듀은  μ•„λž˜μ™€ 같이 크게 λ³€κ²½λ˜μ—ˆμ£ . 

 

κΈ°μ‘΄ Date, Time, TimestampλŠ” 무슨 λ¬Έμ œκ°€ μžˆμ—ˆκΈΈλž˜ μ‚¬μš©μ„ ꢌμž₯ν•˜μ§€ μ•ŠλŠ”κ±΄κ°€μš”?

더보기

λ¬Έμ œκ°€ ν•œ λ‘κ°œκ°€ μ•„λ‹ˆλΌ 사싀상 λͺ»μ“Έμ •λ„μ˜€κ³ , μ‹€μ œ ν”„λ‘œμ νŠΈμ—μ„  μ™ΈλΆ€ 라이브러리인 Joda Time을 거의 ν‘œμ€€μœΌλ‘œ μ‚¬μš©ν–ˆμ—ˆμŠ΅λ‹ˆλ‹€. κ·Έ 쀑 큰 문제 λͺ‡ 개만 λ½‘μ•„λ³΄μžλ©΄ μ•„λž˜μ™€ κ°™μŠ΅λ‹ˆλ‹€.

 

1. 객체의 이름과 μ‚¬μš©λ²•μ΄ 직관적이지 μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

import java.text.SimpleDateFormat
import java.util.*

fun main() {
  val date: Date = Date() // κΈ°λ³Έκ°’: System.currentTimeMillis()
  val time1:Long = date.time // 이거 밀리 초둜된 Unix Time μž…λ‹ˆλ‹€ γ…‹γ…‹

  val calendar: Calendar = GregorianCalendar() // κΈ°λ³Έκ°’: TimeZone.getDefaultRef()
  val time2:Date = calendar.time // calendar.getTime은 λ†€λžκ²Œλ„ Dateκ°€ λ‚˜μ˜΅λ‹ˆλ‹€ γ…‹γ…‹  
}

 

2. Date, Time 객체가 λΆˆλ³€ν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€. 였히렀 객체 볡사가 λ²ˆκ±°λ‘œμ› κ³  setterλŠ” μ–Έμ œλ‚˜ ν™œμ§ μ—΄λ €μžˆμŠ΅λ‹ˆλ‹€.

// new Date(); λ₯Ό ν˜„μž¬μ‹œκ°„μœΌλ‘œ 많이 μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ—, 값을 setν•œκ±΄μ§€ μ•Œμ•„λ‚΄κΈ°κ°€ λ‘λ°°λ‘œ μ–΄λ ΅μŠ΅λ‹ˆλ‹€.
val date:Date = new Date();
date.setTime(time)

// μΊ˜λ¦°λ”λ„ λ§ˆμ°¬κ°€μ§€.
val calendar: Calendar = GregorianCalendar(2022,1,10)
calendar.add(Calendar.DAY_OF_YEAR, 1)

 

3. monthκ°€ 0λΆ€ν„° μ‹œμž‘ν•©λ‹ˆλ‹€..γ…‹γ…‹ Javaλ₯Ό λ² κ»΄λ§Œλ“  Javascript도 같은 문제λ₯Ό 가지고 있죠

  val calendar: Calendar = GregorianCalendar(2022,1,10) // 이거 2μ›” 10μΌμž…λ‹ˆλ‹€.

 

4. μ‹œκ°„μ„ λ³€ν™˜ν•  λ•Œ μ‚¬μš©ν•˜λŠ” μƒμˆ˜κ°’ java.time.chrono κ³Ό ν•¨κ»˜ μ‚¬μš©ν•˜λ©΄ λ³΅μž‘λ„λŠ” 2배둜!

음λ ₯, λΆˆκ΅λ‹¬λ ₯, νžŒλ‘κ΅λ‹¬λ ₯, μ»€μŠ€ν…€λ‹¬λ ₯...

 

https://stackoverflow.com/questions/32437550/whats-the-difference-between-instant-and-localdatetime/32443004#32443004

 

 

JDK8 - java.time νŒ¨ν‚€μ§€

Instant : 컴퓨터에 λ°•νžŒ UTC μ •μˆ˜ κ°’ (Unix Time λ˜λŠ” EpochMillsecond)

μ΄λŠ” 순수 μ •μˆ˜λ§Œ 가지기에 비ꡐ/연산속도가 μ•„μ£Ό λΉ λ₯΄λ‹€λŠ” μž₯점도 있음. 단 κΈ°λ³Έ 값이 λ°€λ¦¬μ„Έμ»¨λ“œ(1/1000초)λΌμ„œ λ³€ν™˜μ— μ£Όμ˜ν•  것.

Instant.now()// 1674904313535λ°€λ¦¬μ΄ˆ, Zone μ •λ³΄λŠ” 넣을 수 μ—†μŒ.

 

LocalTime: ν‘œμ€€ μ‹œκ°„μ΄ μ•„λ‹˜, κ·Έλƒ₯ 숫자둜 된 μ‹œκ°„ κ°’ (21:03:10)

LocalDate : ν‘œμ€€ μ‹œκ°„μ΄ μ•„λ‹˜, κ·Έλƒ₯ 숫자둜 된 달λ ₯ κ°’ (2022-10-10)

LocalDateTime: ν‘œμ€€ μ‹œκ°„μ΄ μ•„λ‹˜, κ·Έλƒ₯ 숫자둜 된 달λ ₯ + μ‹œλΆ„μ΄ˆ κ°’ (2022-10-10 21:03:10) / λ°€λ¦¬μ΄ˆ, λ‚˜λ…Έμ΄ˆλŠ” μ˜΅μ…˜

// μ˜› μžλ°” month(0λΆ€ν„° μ‹œμž‘)λž‘ ν—·κ°ˆλ¦΄ 수 있기 λ•Œλ¬Έμ—, MonthλŠ” μˆ«μžλŒ€μ‹  ENUM μ‚¬μš©
LocalDate ld = LocalDate.of( 2018 , Month.DECEMBER , 25 ) ;
LocalTime lt = LocalTime.MIN ;   // 00:00:00
LocalDateTime ldt = LocalDateTime.of( ld , lt ) ;  // Christmas morning anywhere.

 

ZoneId : λ‹¨μˆœ UTC에 μ‚¬μš©λ˜λŠ” 지역 아이디 (λ˜λŠ” UTC/GMT κ°’)

ZoneOffset : λ‹¨μˆœ UTC offset κ°’, 직접 숫자둜 적을 μˆ˜λ„ μžˆμœΌλ‚˜ 보톡 ZoneIdλ₯Ό μ΄μš©ν•˜μ—¬ 생성함

ZoneRegion: 잘 μ‚¬μš©ν•˜μ§€ μ•Šμ•„ μƒλž΅. ZoneOffset + ZoneRule 인데,  SummerTime(CET, CEST) 을 μ‚¬μš©ν•˜λŠ” κ΅­κ°€λ₯Ό μœ„ν•΄ μ‘΄μž¬ν•¨.

ZonedDateTime : ν‘œμ€€ μ‹œκ°„μΈ DateTime 객체 (Instant + ZoneId)

OffsetDateTime: ν‘œμ€€ μ‹œκ°„μΈ DateTime 객체 (Instant + ZoneOffset), 사싀상 ZoneDateTimeκ³Ό 동일

// ν•œκ΅­/μ„œμšΈ ZoneId 생성
ZoneId zoneId1 = ZoneId.of("Asia/Seoul");
ZoneId zoneId2 = ZoneId.of("UTC+9");
ZoneId zoneId3 = ZoneId.of("UTC+09");
ZoneId zoneId4 = ZoneId.of("UTC+09:00");
ZoneId zoneId5 = ZoneId.of("GMT+9");
ZoneId zoneId6 = ZoneId.of("GMT+09");
ZoneId zoneId7 = ZoneId.of("GMT+09:00");
ZoneId zoneId8 = ZoneId.of("UT+9");
ZoneId zoneId9 = ZoneId.of("UT+09");
ZoneId zoneId10 = ZoneId.of("UT+09:00");

// ν•œκ΅­/μ„œμšΈ ZoneOffset 생성  
ZoneOffset zoneOffset1 = ZoneOffset.of("+9");
ZoneOffset zoneOffset2 = ZoneOffset.of("+09");
ZoneOffset zoneOffset3 = ZoneOffset.of("+09:00");
ZoneOffset zoneOffset4 = ZoneOffset.of("+09:00:00");
ZoneOffset zoneOffset5 = ZoneId.of("+09:00:00");
ZoneOffset zoneOffset6 = ZoneId.of("+9");
ZoneOffset zoneOffset7 = ZoneId.of("+09");
ZoneOffset zoneOffset8 = ZoneId.of("+09:00");
ZoneOffset zoneOffset9 = OffsetDateTime.now(ZoneId.of("Asia/Seoul")).getOffset();
ZoneOffset zoneOffset10 = ZonedDateTime.now(ZoneId.of("Asia/Seoul")).getOffset();

 

Period : 두 Date 사이 λ…„/μ›”/일 간격 

Duration : 두 Time μ‚¬μ΄μ˜ 초(λ˜λŠ” λ‚˜λ…Έμ΄ˆ) 간격

LocalDate startDate = LocalDate.of(1939, 9, 1);
LocalDate endDate = LocalDate.of(1945, 9, 2);

Period period = Period.between(startDate, endDate);// Period (years=6, months=0, days=1)

Duration ofMinutes = Duration.ofMinutes(1); // Duraiotn(seconds=60)
Duration ofHours = Duration.ofHours(1); // Duration(seconds=86400)

 

 

 

ChronoUnit

μ‹œκ°„ 객체듀은 μ‰½κ²Œ κ³„μ‚°μ΄λ‚˜ λ³€ν™˜μ΄ κ°€λŠ₯ν•©λ‹ˆλ‹€. λ‹€λ§Œ LocalDate.. μ‹œλ¦¬μ¦ˆλŠ” ChronoUnit을 μ΄μš©ν•΄ λ‹¨μœ„λ₯Ό μž…λ ₯ν•΄μ€˜μ•Όν•©λ‹ˆλ‹€.

μƒˆλ‘œ λ§Œλ“€μ–΄μ§„ μ‹œκ°„ 객체듀은 λΆˆλ³€ν•©λ‹ˆλ‹€. 즉 연산을 κΈ°λ³Έ 객체가 λ³€ν•˜μ§€ μ•Šκ³ , μƒˆλ‘œμš΄ 객체가 λ§Œλ“€μ–΄μ§‘λ‹ˆλ‹€.

 

μ‹œκ°„μ„ λΉ„κ΅ν•˜μ—¬ μ‚¬μž‡ 값을 ꡬ할 λ•Œ ChronoUnit을 μ‚¬μš©ν•˜λ©΄ νŽΈλ¦¬ν•©λ‹ˆλ‹€

LocalDate startDate = LocalDate.of(1939, 9, 1);
LocalDate endDate = LocalDate.of(1945, 9, 2);

long months = ChronoUnit.MONTHS.between(startDate, endDate); // 72
long weeks = ChronoUnit.WEEKS.between(startDate, endDate); // 313
long days = ChronoUnit.DAYS.between(startDate, endDate); // 2193
long hours = ChronoUnit.HOURS.between(startTime, endTime); // 0
long minutes = ChronoUnit.MINUTES.between(startTime, endTime); // 1
long seconds = ChronoUnit.SECONDS.between(startTime, endTime); // 70

 

 


🧨 μžλ°”μ—μ„œ μ‹œκ°„μ„ λ‹€λ£° λ•Œ μ£Όμ˜ν• μ 

  • μ‹œκ°„μ„ λ¬Έμžμ—΄λ‘œ λ³€ν™˜ν–ˆμ„ λ•Œ ν•œκ΅­ κΈ°μ€€ λ‚ μ§œκ°€ λ§žλŠ”μ§€ 확인이 ν•„μš”ν•©λ‹ˆλ‹€.
  • κΈ°μ‘΄ DBλ‚˜ μ„œλ²„μ—μ„œ μ‚¬μš©ν•˜λŠ” μ‹œκ°„μ΄ UTCκ°€ 아닐 수 μžˆμŠ΅λ‹ˆλ‹€. κΈ°μ‘΄ μ½”λ“œμ— UTC 값을 일일이 λ³€κ²½ν•˜κΈ° λ²ˆκ±°λ‘­μŠ΅λ‹ˆλ‹€.
    특히 λ‚˜μ΄/μƒμΌλ“±μ˜ μž…λ ₯ 값은 κ·ΈλŒ€λ‘œ DB에 μ €μž₯ν•˜μ§€ 말고 Instant λ“±μœΌλ‘œ μ €μž₯ ν›„ μ„œλ²„μ—μ„œ 계산/λ³€ν™˜ν•΄μ„œ μ‚¬μš©ν•˜κΈ°λ₯Ό ꢌμž₯ν•©λ‹ˆλ‹€.
  • LocalDate.now() 등은 μˆœμˆ˜ν•œ μžλ°”μ½”λ“œμ§€λ§Œ, 맀 μˆœκ°„λ§ˆλ‹€ κ²°κ³Όκ°€ λ‹€λ₯΄κ²Œ λ‚˜μ˜€κΈ°μ— ν…ŒμŠ€νŠΈν•˜κΈ° κΉŒλ‹€λ‘­μŠ΅λ‹ˆλ‹€.

 

κ·Έλž˜μ„œ μ‹œκ°„μ„ λ‹΄λ‹Ήν•˜λŠ” μ„œλΉ„μŠ€λ₯Ό 뢄리해 μ£Όμž…λ°›μ•„ μ‚¬μš©ν•˜κ±°λ‚˜, LocalDate.now(clock)κ³Ό 같이 java.util.Clock 을 μ£Όμž… λ°›μ•„ μ‹œκ°„μ— λŒ€ν•œ μ˜μ‘΄μ„±μ„ λŠμ–΄λ‘λŠ” κ±Έ ꢌμž₯ν•©λ‹ˆλ‹€.

@Bean
fun clock():Clock{
  return Clock.systemDefaultZone()
}
@Serivce
class Service(
    private val clock;
){
    fun method(){
      val now = LocalDateTime.now(clock)
    }
}

 

Test Mocking

μœ„ 예제처럼 μ‹œκ°„μ„ μ£Όμž…λ°›μ•„ μ‚¬μš©ν•˜κΈ΄ 번거둜운데, Test λŠ” ν•˜κ³ μ‹Άλ‹€λ©΄ MockitoStatic을 μ΄μš©ν•˜μ—¬ static λ©”μ„œλ“œλ₯Ό λͺ¨ν‚Ήν•  수 μžˆμŠ΅λ‹ˆλ‹€.

- μ‹œκ°„μ„ λͺ¨ν‚Ήν•˜λŠ”건 λ‹€λ₯Έ ν…ŒμŠ€νŠΈμ— 영ν–₯이 μžˆμ„ 수 μžˆμœΌλ―€λ‘œ, 직접 close() ν•΄μ£Όκ±°λ‚˜ try-resource λ¬Έ(μ½”ν‹€λ¦° use)λ₯Ό ν™œμš©ν•΄μ•Ό ν•©λ‹ˆλ‹€.

testImplementation("org.mockito.kotlin:mockito-kotlin:4.0.0") // 코틀린을 μ‚¬μš©ν•˜λŠ” 경우
testImplementation("org.mockito:mockito-inline:4.0.0") // mockitoStatic을 μ‚¬μš©ν•˜κΈ° μœ„ν•΄ λ³„λ„λ‘œ μΆ”κ°€
  @Test
  fun test() {
    val fixedToday = LocalDate.of(2022, 12, 19)

    // Mockito.CALLS_REAL_METHODS 섀정은 λͺ¨ν‚Ήν•œ λ©”μ„œλ“œ 외에 λ‹€λ₯Έ 것듀을 κΈ°μ‘΄ κ·ΈλŒ€λ‘œ μœ μ§€μ‹œμΌœμ€λ‹ˆλ‹€.
    Mockito.mockStatic(LocalDate::class.java, Mockito.CALLS_REAL_METHODS)
      .use {
        it.`when`<LocalDate> { LocalDate.now() }.thenReturn(fixedToday)
        it.`when`<LocalDate> { LocalDate.now(any(ZoneOffset::class.java)) }.thenReturn(fixedToday)
        //** Test Code *//
      }
}

 

λΈ”λ‘œκ·Έμ˜ 정보

JiwonDev

JiwonDev

ν™œλ™ν•˜κΈ°