Java μμ μκ°μ κ΄λ¦¬νλ λ°©λ² (Instant.now(), LocalDate.now())
by JiwonDev
JDK8 java.time μ¬μ©λ²λ§ λ°λ‘ μκ³ μΆλ€λ©΄:
π± λ¬λ ₯κ³Ό μκ°μ κ·Έ μ체λ‘λ 볡μ‘ν©λλ€.
1λ μ μ§κ΅¬κ° νμμ νλ°ν΄λ₯Ό κ·μΉμ μΌλ‘ λλ μκ°μ μ°κ²μ λλ€. 365.2421μΌ μ λλκ³ , 맀λ 0.000001μΌ μ λ μ€μ°¨κ° μ‘΄μ¬ν©λλ€.
μ¨λ¦¬μ°μ€λ ₯(Julian Calendar)
μ°λ¦¬κ° λ§μ΄ μ°λ 12μ λ¬λ ₯ 체κ³λ λ‘λ§μμ μ νλκΈ° μμνμ΅λλ€. κ·Έ λΉμμλ λ΄μ΄ 1μμ΄μκ³ μ§μλ¬μ΄ 30μΈ κ·μΉμ±μ΄ μμμ΅λλ€.
- μλ λ΄(march)μ΄ νν΄μ μμμ΄μμΌλ μ¨λ¦¬μ°μ€ μ·¨μ λ§μΆλ €κ³ κ± 3μλ‘ λ³κ²½ν©λλ€.(κΈ°μ‘΄ sex:6 sep:7 octo:8 nov:9 dec:10)
- 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 (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κ³Ό λ―ΈμΈνκ² λ€λ¦ λλ€.
λ€, λ¨Ό κΈΈμ λμμμ΅λλ€. μ΄μ μ°λ¦¬λ μλ μλ° μ½λμ λ¬λ¦° μ£Όμμ μ΄ν΄ν μ μκ² λ©λλ€.
π μλ°μμμ μκ°
μλ μλ°λ 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λ°°λ‘!
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 *//
}
}
'πκΈ°λ³Έ μ§μ > Java κΈ°λ³Έμ§μ' μΉ΄ν κ³ λ¦¬μ λ€λ₯Έ κΈ
μ£Όκ΄μ μΈ μΈνλ° κ°μ 리뷰(π±κΉμνλ μ€νλ§) (18) | 2024.02.15 |
---|---|
μμμ νλ¦λλ‘ μ¨λ³΄λ DB νΈλμμ μ΄μΌκΈ° (0) | 2022.08.15 |
μλ°μ NIO (java.nio) (1) | 2022.03.08 |
μλ°μ λμμ± λΌμ΄λΈλ¬λ¦¬μ λμꡬ쑰 (Atomic, Adder, Accumulator) (0) | 2022.03.08 |
μ€λΈμ νΈ λμμΈ μ€νμΌ #1 κ°μ²΄μ§ν₯, μλΉμ€ μμ±νκΈ° (0) | 2021.10.04 |
λΈλ‘κ·Έμ μ 보
JiwonDev
JiwonDev