CHAP12 - Modern-Java-in-Action/Online-Study GitHub Wiki

์ƒˆ๋กœ์šด ๋‚ ์งœ์™€ ์‹œ๊ฐ„ API

๊ธฐ์กด Date, Calendar ๋ฌธ์ œ์ ์„ ๋ณด์™„ํ•˜๊ธฐ ์œ„ํ•ด, java.time ํŒจํ‚ค์ง€๊ฐ€ ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

  • Date ํŒจํ‚ค์ง€์˜ ๋ฌธ์ œ์ (1.1๋ถ€ํ„ฐ deprecated)
    • ํŠน์ • ์‹œ์ ์„ ๋‚ ์งœ๊ฐ€ ์•„๋‹Œ ๋ฐ€๋ฆฌ์ดˆ ๋‹จ์œ„๋กœ ํ‘œํ˜„ํ•˜๋ฉฐ, ์˜คํ”„์…‹์€ 1900๋…„์„ ๊ธฐ์ค€์œผ๋กœ ํ•จ.
    • ๋‹ฌ ์ธ๋ฑ์Šค๊ฐ€ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•จ.
    • JVM ๊ธฐ๋ณธ์‹œ๊ฐ„๋Œ€์ธ ์ค‘์•™์œ ๋Ÿฝ์‹œ๊ฐ„๋Œ€๋ฅผ ์‚ฌ์šฉํ•˜๋‚˜, ์‹œ๊ฐ„๋Œ€ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์ง€๋Š” ์•Š์Œ.
    • DateFormat ๊ธฐ๋Šฅ์„ ์ง€์›ํ•˜๋‚˜ ์Šค๋ ˆ๋“œ์— ์•ˆ์ „ํ•˜์ง€ ์•Š์Œ.
    • ๊ฐ€๋ณ€ ํด๋ž˜์Šค์—ฌ์„œ ํ•จ์ˆ˜ํ˜• ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ๋ฒ•๋ก  ์ ์šฉ์‹œ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›€.
  • Calendar
    • ๋‹ฌ์˜ ์ธ๋ฑ์Šค๊ฐ€ 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•จ.
    • Date์™€ ๋น„๊ตํ•ด์„œ DateFormat๋“ฑ ์ผ๋ถ€ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Œ.
    • ๊ฐ€๋ณ€ ํด๋ž˜์Šค์ž„.

12.1 LocalDate, LocalTime, Instant, Duratioin, Period

  • ์ฃผ์š”ํŠน์ง•

    • ๋ชจ๋‘ ๋ถˆ๋ณ€ํ˜•์ด๋‹ค.
    • ๊ฐ’์„ ๋ฐ”๊พธ๋ฉด ์ƒˆ๋กœ์šด ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • ํŠน์ •์‹œ์ ์˜ ์‹œ๊ฐ„์„ ํ‘œํ˜„

    • LocalDate : ์‹œ๊ฐ„๋Œ€ ์ •๋ณด์™€ ์‹œ/๋ถ„/์ดˆ ์ •๋ณด์—†์ด, ์—ฐ/์›”/์ผ.
    • LocalTime : ์‹œ๊ฐ„๋Œ€ ์ •๋ณด์™€ ์—ฐ/์›”/์ผ ์ •๋ณด์—†์ด, ์‹œ/๋ถ„/์ดˆ.
    • LocalDateTime : ์‹œ๊ฐ„๋Œ€ ์ •๋ณด์—†์ด, ์—ฐ/์›”/์ผ/์‹œ/๋ถ„/์ดˆ.
    • Instant : ์œ ๋‹‰์Šค ์—ํฌํฌ์‹œ๊ฐ„์„ ๊ธฐ์ค€์œผ๋กœ ํŠน์ • ์ง€์ ๊นŒ์ง€ ์‹œ๊ฐ„์„ ๋ฐ€๋ฆฌ์ดˆ๋กœ ํ‘œํ˜„.
      • ์œ ๋‹‰์Šค ์—ํฌํฌ์‹œ๊ฐ„ : 1970๋…„ 1์›” 1์ผ 0์‹œ 0๋ถ„ 0์ดˆ UTC
      • UTC ์„ธ๊ณ„ํ‘œ์ค€์‹œ / ๊ทธ๋ฆฌ๋‹ˆ์น˜ํ‘œ์ค€์‹œ / ํ•œ๊ตญ์‹œ๊ฐ„-9
  • ํŠน์ •์‹œ์ ๊ฐ„ ์‹œ๊ฐ„ ์ฐจ์ด๋ฅผ ํ‘œํ˜„

    • Duration : ์‹œ/๋ถ„/์ดˆ ๋‹จ์œ„๋กœ ํŠน์ • ์ง€์ ๊ฐ„ ์‹œ๊ฐ„ ํ‘œํ˜„.
      • LocalTime ์‚ฌ์šฉ๋ถˆ๊ฐ€, LocalDate/LocalDateTime ์‚ฌ์šฉ๊ฐ€๋Šฅ(1์ผ์„ 24์‹œ๊ฐ„์œผ๋กœ ํ‘œํ˜„)
    • Period : ์—ฐ/์›”/์ผ ๋‹จ์œ„๋กœ ํŠน์ • ์ง€์ ๊ฐ„ ์‹œ๊ฐ„ ํ‘œํ˜„.
      • LocalDate ์‚ฌ์šฉ๋ถˆ๊ฐ€, LocalTime/LocalDateTime ์‚ฌ์šฉ๊ฐ€๋Šฅ(24์‹œ๊ฐ„์„ 1์ผ๋กœ ํ‘œํ˜„)

LocalDate

๊ฐ์ฒด์ƒ์„ฑ ๋ฐ ์‚ฌ์šฉ๋ฐฉ๋ฒ•

LocalDate date = LocalDate.of(2017, 9, 21);
int year = date.getYear();
Month month = date.getMonth();
int day = date.getDayOfMonth();
DayOfWeek dow = date.getDayOfWeek();
LocalDate date2 = LocalDate.parse("2017-09-21");

๊ฐ์ฒด ๋ฉค๋ฒ„๋ณ€์ˆ˜ ์ ‘๊ทผ๋ฐฉ๋ฒ•

LocalDate nowDate = LocalDate.now();
System.out.println(nowDate);

//get๋ฉ”์„œ๋“œ์— ChronoField Enum์„ ๋„˜๊ฒจ๋„ ๋œ๋‹ค
int y = date.get(ChronoField.YEAR);
int m = date.get(ChronoField.MONTH_OF_YEAR);
int d = date.get(ChronoField.DAY_OF_MONTH);
System.out.println(y+" "+m+" "+d);

//ํ•ญ๋ชฉ๋งˆ๋‹ค ์ •์˜๋œ get๋ฉ”์„œ๋“œ๋ฅผ ํ˜ธ์ถœํ•ด๋„ ๋œ๋‹ค
int y2 = date.getYear();
int m2 = date.getMonthValue();
int d2 = date.getDayOfMonth();
System.out.println(y2+" "+m2+" "+d2);

์œ ์šฉํ•œ ๊ธฐ๋Šฅ

int len = date.lengthOfMonth(); //๋‹ฌ๋งˆ๋‹ค ์ผ ์ˆ˜
boolean leap = date.isLeapYear(); //์œค๋…„์—ฌ๋ถ€๋ฅผ ์•Œ ์ˆ˜ ์žˆ์Œ
System.out.println(month.getValue()); //๋‹ฌ์€ 1์›”๋ถ€ํ„ฐ 1, 12์›”์ด 12
System.out.println(dow.getValue()); //์š”์ผ์€ ์›”์š”์ผ๋ถ€ํ„ฐ 1, ์ผ์š”์ผ์ด 7

LocalTime

๊ฐ์ฒด์ƒ์„ฑ ๋ฐ ์‚ฌ์šฉ๋ฐฉ๋ฒ•

//LocalTime
LocalTime time = LocalTime.of(13, 45, 20);
int hour = time.getHour();
int minute = time.getMinute();
int second = time.getSecond();

//๋ฌธ์ž์—ด์„ ํŒŒ์‹ฑํ•ด์„œ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์Œ
LocalTime time2 = LocalTime.parse("13:45:20");

LocalDateTime

//LocalDateTime์€ ๋‚ ์งœ, ์‹œ๊ฐ„ ๋ชจ๋‘๋ฅผ ํ‘œํ˜„
LocalDateTime dt1 = LocalDateTime.of(2017, Month.SEPTEMBER, 21, 13, 45, 20);
System.out.println(Month.SEPTEMBER);

LocalTime, LocalDate๋ฅผ ๋ณ€ํ™˜ํ•  ์ˆ˜ ์žˆ๋‹ค.

LocalDateTime dt2 = LocalDateTime.of(date, time);
LocalDateTime dt3 = date.atTime(13, 45, 20);
LocalDateTime dt4 = date.atTime(time);
LocalDateTime dt5 = time.atDate(date);
LocalDate date3 = dt1.toLocalDate();
LocalTime time3 = dt1.toLocalTime();

Instant

Instant๋Š” ์‹œ๊ฐ„์„ ๋ฐ€๋ฆฌ์ดˆ๋‹จ์œ„๋กœ ํ‘œํ˜„ํ•œ๋‹ค.

//Instant
System.out.println(Instant.ofEpochSecond(3));
System.out.println(Instant.ofEpochSecond(3, 0));
System.out.println(Instant.ofEpochSecond(2, 1_000_000_000));
System.out.println(Instant.ofEpochSecond(4, -1_000_000_000));

์ธ์Šคํ„ดํŠธ์—์„œ ๋ฐ”๋กœ ์—ฐ/์›”/์ผ/์‹œ/๋ถ„/์ดˆ ์ •๋ณด๋ฅผ ์ฝ์œผ๋ ค๊ณ ํ•˜๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค. LocalDate ๋“ฑ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  ์ฝ์–ด์•ผ ํ•œ๋‹ค.

try{
    int day = Instant.now().get(ChronoField.DAY_OF_MONTH);
}catch(UnsupportedTemporalTypeException e){
    e.printStackTrace();
}

//๋ณ€ํ™˜ํ•  ๋•Œ๋Š” ์‹œ๊ฐ„๋Œ€์ •๋ณด๋ฅผ ์ง€์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค. ์‹œ๊ฐ„๋Œ€์ •๋ณด๋Š” ๋‹ค๋‹ค์Œ์ ˆ์—์„œ ๋‹ค๋ฃธ.
int day = DateTime.ofInstant(Instant.now(), ZoneOffset.UTC).get(ChronoField.DAY_OF_MONTH);

Duration/Period

Duration์€ ํŠน์ •์‹œ์ ๊ฐ„ ์‹œ๊ฐ„์ฐจ๋ฅผ ์‹œ/๋ถ„/์ดˆ๋กœ ํ‘œํ˜„ํ•˜๋ฏ€๋กœ LocalDate์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.

//Duration
LocalTime time1 = LocalTime.now();
LocalTime time2 = time1.plusHours(1);
LocalDate dateTime1 = LocalDate.now();
LocalDate dateTime2 = dateTime1.plusDays(1);
Instant instant1 = Instant.now();
Instant instant2 = instant1.plusMillis(1000);

Duration d1 = Duration.between(time1, time2);
System.out.println("d1: "+d1);
try{ //Duration์€ ์ดˆ์™€ ๋‚˜๋…ธ์ดˆ๋กœ ์‹œ๊ฐ„๋‹จ์œ„๋ฅผ ํ‘œํ˜„ํ•˜๋ฏ€๋กœ LocalDate๋Š” ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
    Duration d2 = Duration.between(dateTime1, dateTime2);
    System.out.println("d2: "+d2);
}catch(UnsupportedTemporalTypeException e){
    //e.printStackTrace();
}
Duration d3 = Duration.between(instant1, instant2);
System.out.println("d3: "+d3);

Period๋Š” ํŠน์ • ์‹œ์ ๊ฐ„ ์‹œ๊ฐ„์ฐจ๋ฅผ ์—ฐ/์›”/์ผ๋กœ ํ‘œํ˜„ํ•œ๋‹ค. ๋”ฐ๋ผ์„œ LocalTime์—๋Š” ์‚ฌ์šฉํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค. LocalDateTime์œผ๋กœ ๊ณ„์‚ฐํ•ด๋„ ์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค.

LocalDateTime ldt1 = LocalDateTime.now();
LocalDateTime ldt2 = ldt1.plusYears(1);

Duration test = Duration.between(ldt1, ldt2);
System.out.println("duration test: "+test);

//Period test2 = Period.between(ldt1, ldt2); //์˜ˆ์™ธ๋ฅผ ๋˜์ง„๋‹ค
Period test2 = Period.between(ldt1.toLocalDate(), ldt2.toLocalDate());
System.out.println("period test: "+test2);
//period test: P1Y

๋‹ค๋งŒ, Duration์œผ๋กœ LocalDateTime๊ฐ„ ์‹œ๊ฐ„์ฐจ๋ฅผ ๊ณ„์‚ฐํ•˜๋ฉด ์—ฐ/์›”/์ผ์„ ์‹œ๊ฐ„์œผ๋กœ ๋ณ€ํ™˜ํ•ด์„œ ์ถœ๋ ฅํ•œ๋‹ค.

LocalDateTime ldt1 = LocalDateTime.now();
LocalDateTime ldt2 = ldt1.plusYears(1);

Duration test = Duration.between(ldt1, ldt2);
System.out.println("duration test: "+test);
//duration test: PT8760H
  • Duration๊ณผ Period๊ฐ€ ๊ณตํ†ต์œผ๋กœ ์ œ๊ณตํ•˜๋Š” ๋ฉ”์„œ๋“œ

    ModernJavaDurationPeriodCommonMethod

12.2 ๋‚ ์งœ ์กฐ์ •, ํŒŒ์‹ฑ, ํฌ๋งคํŒ…

๋‚ ์งœ ์กฐ์ • : ์ ˆ๋Œ€์  with, ์ƒ๋Œ€์  plus/minus

//with์œผ๋กœ ๊ฐ’์„ ์ง€์ •
LocalDate date1 = LocalDate.of(2017, 9, 21);
LocalDate date2 = date1.withYear(2011);
LocalDate date3 = date2.withDayOfMonth(25);
LocalDate date4 = date3.with(ChronoField.MONTH_OF_YEAR, 2);

//plus, minus๋กœ ์—ฐ์‚ฐ
LocalDate date22 = date1.plusWeeks(1);
LocalDate date33 = date22.minusYears(1);
LocalDate date44 = date33.plus(6, ChronoUnit.MONTHS);
  • ๋‚ ์งœ/์‹œ๊ฐ„ ํด๋ž˜์Šค์˜ ๊ณตํ†ต ๋ฉ”์„œ๋“œ

    ModernJavaDateTimeCommonMethod

ํ€ด์ฆˆ12-1: LocalDate ์กฐ์ •

๋‹ค์Œ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ–ˆ์„ ๋•Œ date์˜ ๋ณ€์ˆซ๊ฐ’์€?

LocalDate date = LocalDate.of(2014, 3, 18);
date = date.with(ChronoField.MONTH_OF_YEAR, 9);
date = date.plusYears(2).minusDays(10);
date.withYear(2011);
์ •๋‹ต 2016-09-08

TemporalAdjusters๋กœ ๋‚ ์งœ์กฐ์ • ์ปค์Šคํ…€ ๋ฉ”์„œ๋“œ ๋งŒ๋“ค๊ธฐ

LocalDate date1 = LocalDate.now(); //2022-01-21
LocalDate date2 = date1.with(nextOrSame(DayOfWeek.SUNDAY)); //2022-01-23
LocalDate date3 = date2.with(lastDayOfMonth()); //2022-01-31
  • Temporal

    ModernJavaTemporalAdjusters

TemporalAdjuster ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ๊ตฌํ˜„ํ•œ ๊ฒƒ์ด TemporalAdjusters์ด๋‹ค. ์ปค์Šคํ…€์œผ๋กœ ์ง์ ‘ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค. ์ด๋ฅผํ…Œ๋ฉด ๋‹ค์Œ ๊ทผ๋ฌด์ผ์„ ๊ตฌํ•˜๋Š” TemporalAdjuster๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.

  • TemporalAdjuster๋ฅผ ํด๋ž˜์Šค๋กœ ๊ตฌํ˜„ํ•˜๊ณ  ์ธ์Šคํ„ด์Šค๋ฅผ ์ƒ์„ฑํ•ด ์ธ์ž๋กœ ๋„˜๊ธฐ๊ธฐ
LocalDate date = LocalDate.now().with(new NextWorkingDay());
import java.time.DayOfWeek;
import java.time.temporal.ChronoField;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;

public class NextWorkingDay implements TemporalAdjuster {
    @Override
    public Temporal adjustInto(Temporal temporal) {
        DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
        int dayToAdd = 1;
        if(dow == DayOfWeek.FRIDAY) dayToAdd = 3;
        else if(dow == DayOfWeek.SATURDAY) dayToAdd = 2;
        return temporal.plus(dayToAdd, ChronoUnit.DAYS);
    }
}
  • TemporalAdjuster๋ฅผ ๋žŒ๋‹ค๋กœ ๊ตฌํ˜„ํ•ด ์ธ์ž๋กœ ๋„˜๊ธฐ๊ธฐ
LocalDate date1 = LocalDate.now().with(
  temporal -> {
      DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
      int dayToAdd = 1;
      if(dow==DayOfWeek.FRIDAY) dayToAdd = 3;
      else if(dow==DayOfWeek.SATURDAY) dayToAdd = 2;
      return temporal.plus(dayToAdd, ChronoUnit.DAYS);
  }
);
  • ๋žŒ๋‹ค๋กœ ๊ตฌํ˜„ํ•œ TemporalAdjuster๋ฅผ ๋ณ€์ˆ˜์— ์ €์žฅํ–ˆ๋‹ค๊ฐ€ ์‚ฌ์šฉํ•˜๊ธฐ
TemporalAdjuster nextWorkingDay = TemporalAdjusters.ofDateAdjuster(
    temporal -> {
        DayOfWeek dow = DayOfWeek.of(temporal.get(ChronoField.DAY_OF_WEEK));
        int dayToAdd = 1;
        if(dow==DayOfWeek.FRIDAY) dayToAdd = 3;
        else if(dow==DayOfWeek.SATURDAY) dayToAdd = 2;
        return temporal.plus(dayToAdd, ChronoUnit.DAYS);
    }
);
LocalDate date2 = LocalDate.now().with(nextWorkingDay);

๋‚ ์งœ/์‹œ๊ฐ„ ์ถœ๋ ฅ๊ณผ ํŒŒ์‹ฑ

์ถœ๋ ฅํ•˜๊ธฐ

LocalDate date = LocalDate.of(2014, 3, 18);
System.out.println(date.format(DateTimeFormatter.BASIC_ISO_DATE));
//20140318
System.out.println(date.format(DateTimeFormatter.ISO_LOCAL_DATE));
//2014-03-18

ํŒŒ์‹ฑํ•˜๊ธฐ

LocalDate date2 = LocalDate.parse("20140318", DateTimeFormatter.BASIC_ISO_DATE);
LocalDate date3 = LocalDate.parse("2014-03-18", DateTimeFormatter.ISO_LOCAL_DATE);
System.out.println(date2);
System.out.println(date3);

ํฌ๋งท ์ •ํ•˜๊ธฐ

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy");
LocalDate date4 = LocalDate.now();
String formattedDate = date4.format(formatter);
System.out.println(formattedDate);
//21/01/2022

LocalDate date5 = LocalDate.parse(formattedDate, formatter);
System.out.println(date5);
//2022-01-21

ํฌ๋งท ์ •ํ•˜๊ณ , Locale์ง€์ •ํ•˜๊ธฐ

DateTimeFormatter timeFomatterItalian = DateTimeFormatter.ofPattern("dd/MMMM/yyyy", Locale.ITALIAN);
String formattedDateItalian = LocalDate.now().format(timeFomatterItalian);

DateTimeFormatter timeFomatterKorean = DateTimeFormatter.ofPattern("dd/MMMM/yyyy", Locale.KOREAN);
String formattedDateKorean = LocalDate.now().format(timeFomatterKorean);

System.out.println(formattedDateItalian); //21/gennaio/2022
System.out.println(formattedDateKorean); //21/1์›”/2022

๋ฉ”์„œ๋“œ ์ฒด์ธ ๋ฐฉ์‹์œผ๋กœ ํฌ๋งท์„ ์ •ํ•˜๊ธฐ

DateTimeFormatter koreanFormatter = new DateTimeFormatterBuilder()
        .appendLiteral("'")
        .appendText(ChronoField.YEAR)
        .appendLiteral(".")
        .appendText(ChronoField.MONTH_OF_YEAR)
        .appendLiteral(".")
        .appendText(ChronoField.DAY_OF_MONTH)
        .appendLiteral(".")
        .appendLiteral("(")
        .appendText(ChronoField.DAY_OF_WEEK)
        .appendLiteral(")")
        .parseCaseInsensitive()
        .toFormatter(Locale.KOREA);
String formattedDateKo2 = LocalDate.now().format(koreanFormatter);
System.out.println(formattedDateKo2);
//'2022.1์›”.21.(๊ธˆ์š”์ผ)

12.3 ๋‹ค์–‘ํ•œ ์‹œ๊ฐ„๋Œ€์™€ ์บ˜๋ฆฐ๋” ํ™œ์šฉ ๋ฐฉ๋ฒ•

ZonedDateTime

  • ZonedDateTime : ์‹œ๊ฐ„๋Œ€ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ๋‚ ์งœ, ์‹œ๊ฐ„ ์ •๋ณด

    ModernJavaZonedDateTimeConcepts

ZoneId romeZone = ZoneId.of("Europe/Rome");
ZoneId korZone = ZoneId.of("Asia/Tokyo");
LocalDateTime dateTime = LocalDateTime.now();

ZonedDateTime zdt2 = dateTime.atZone(romeZone);
System.out.println(zdt2); //ํ•œ๊ตญ์‹œ๊ฐ„ ๊ธฐ์ค€ ๋กœ๋งˆ์‹œ๊ฐ„๋Œ€๋กœ ๋ณ€ํ™˜ํ•ด์คŒ > ์™œ?
zdt2 = dateTime.atZone(korZone);
System.out.println(zdt2); //ํ•œ๊ตญ์‹œ๊ฐ„๋Œ€๋กœ ๋ณ€ํ™˜ํ•ด์คŒ
  • ์—ฌ๊ธฐ์„œ ์˜๋ฌธ, LocalDateTime์„ ZonedDateTime์œผ๋กœ ๋ฐ”๊ฟ€ ๋•Œ ์™œ ๊ธฐ์ค€์‹œ๊ฐ„์„ ํ•œ๊ตญ์‹œ๊ฐ„์œผ๋กœ ์žก์•˜์„๊นŒ, ๊ทธ๋ฆฌ๊ณ  ๊ทธ ๊ณผ์ •์€ ์–ด๋–ป๊ฒŒ ์ด๋ค„์งˆ๊นŒ?
    • ๋‘๋ฒˆ์งธ ์ธ์ˆ˜๋กœ ๊ธฐ์ค€ ์‹œ๊ฐ„๋Œ€๋ฅผ ๋„˜๊ธธ ์ˆ˜ ์žˆ๋‹ค.
    • ์—†๋‹ค๋ฉด ZoneRules์— ์ •์˜๋œ ๊ธฐ์ค€๋Œ€๋กœ ํ•ด๋‹น์‹œ๊ฐ์— ๋งž๋Š” ์‹œ๊ฐ„๋Œ€๋ฅผ ์ฐพ์•„ ๊ธฐ์ค€ ์‹œ๊ฐ„๋Œ€๋กœ ์‚ผ๋Š”๋‹ค(UTC๋ฅผ ๊ตฌํ•˜๊ณ  ์–ผ๋งˆ๋‚˜ ์ฐจ์ด๋‚˜๋Š”์ง€ ํ™•์ธํ•œ๋‹ค.)
    • ๊ทธ๋ž˜์„œ ํ•œ๊ตญ์—์„œ ์ƒ์„ฑํ•œ LocalDateTime ๊ฐ์ฒด๋ฅผ ๋Ÿฐ๋˜์—์„œ ZonedDateTime์œผ๋กœ ๋ฐ”๊พผ๋‹ค๋ฉด ์˜๋„ํ•˜์ง€ ์•Š์€ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
//ํ˜ธํ™˜์„ฑ์„ ์œ„ํ•ด Instant๋กœ ์ž‘์—…ํ•˜๋Š”๊ฒƒ์ด ์œ ๋ฆฌ
LocalDateTime dt = LocalDateTime.ofInstant(Instant.now(), ZoneOffset.UTC);
LocalDateTime dt2 = LocalDateTime.ofInstant(Instant.now(), ZoneId.of("Europe/Rome"));
LocalDateTime dt3 = LocalDateTime.ofInstant(Instant.now(), ZoneId.of("Asia/Tokyo"));
System.out.println(dt); //2022-01-21T10:47:21.983854600
System.out.println(dt2); //2022-01-21T11:47:21.983854600
System.out.println(dt3); //2022-01-21T11:47:21.983854600

์‹œ๊ฐ„๋Œ€๋ณ„ ํ˜ธํ™˜์„ฑ์„ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด Instant๋กœ ์ž‘์—…ํ•˜๋Š” ๊ฒƒ์ด ์œ ๋ฆฌ.

๋Œ€์•ˆ์บ˜๋ฆฐ๋” ์‹œ์Šคํ…œ : ์ผ๋ณธ๋‹ฌ๋ ฅ, ์ด์Šฌ๋žŒ๋ ฅ ๋“ฑ

์ผ๋ณธ๋‹ฌ๋ ฅ ๊ณ„์‚ฐํ•˜๊ธฐ.

LocalDate date = LocalDate.of(2014, Month.MARCH, 18);
JapaneseDate japaneseDate = JapaneseDate.from(date);
System.out.println(japaneseDate); //Japanese Heisei 26-03-18

์ด์Šฌ๋žŒ๋ ฅ ๊ณ„์‚ฐํ•˜๊ธฐ.

HijrahDate ramadanDate = HijrahDate.now()
        .with(ChronoField.DAY_OF_MONTH, 1)
        .with(ChronoField.MONTH_OF_YEAR, 9);
System.out.println("Ramadan starts on " + IsoChronology.INSTANCE.date(ramadanDate)
        + " and ends on" + IsoChronology.INSTANCE.date(ramadanDate.with(TemporalAdjusters.lastDayOfMonth())));

๋งˆ์•ผ๋‹ฌ๋ ฅ, ํƒœ์Œํƒœ์–‘๋ ฅ ๋“ฑ ์ง€์—ญํ™”๋œ ๋‹ฌ๋ ฅ ์‹œ์Šคํ…œ์„ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค. ๋‹ค๋งŒ, 1๋…„์ด 12๊ฐœ์›”, 1๋‹ฌ์€ 31์ผ ์ดํ•˜, 1๋…„์ด ์ •ํ•ด์ง„ ์ˆ˜์˜ ๋‹ฌ๋กœ ์ด๋ฃจ์–ด์ง„๋‹ค๋Š” ์ผ๋ฐ˜์ ์ธ ๊ฐ€์ •์„ ์ ์šฉํ•  ์ˆ˜ ์—†๋‹ค. ๋”ฐ๋ผ์„œ ํ”„๋กœ๊ทธ๋žจ ์ž…์ถœ๋ ฅ์„ ์ง€์—ญํ™”ํ•˜๋Š” ์ƒํ™ฉ์„ ์ œ์™ธํ•˜๋ฉด LocalDate๋ฅผ ์‚ฌ์šฉํ•ด์•ผ ํ•œ๋‹ค.

Chronology japaneseChronology = Chronology.ofLocale(Locale.JAPAN);
ChronoLocalDate now = japaneseChronology.dateNow();
System.out.println(now);

The Problem with Time & Timezones - Computerphile

  • (10๋ถ„) The Problem with Time & Timezones - Computerphile - YouTube

  • ๊ฐ„๋‹จํ•œ ์˜ˆ์‹œ

    • ์œจ๋ฆฌ์šฐ์Šค๋ ฅ์—์„œ ๊ทธ๋ ˆ๊ณ ๋ฆฌ๋ ฅ์œผ๋กœ ๋ฐ”๊ฟ€ ๋•Œ, ์˜ค์ฐจ๋ฅผ ์กฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด ์—ดํ˜์„ ๊ฑด๋„ˆ๋›ฐ์—ˆ๋‹ค.
      • ๋‚˜๋ผ๋งˆ๋‹ค ๊ทธ๋ ˆ๊ณ ๋ฆฌ๋ ฅ์„ ๋ฐ›์•„๋“ค์ธ ์‹œ๊ธฐ๊ฐ€ ๋‹ค๋ฅด๋‹ค.
    • ๊ฐ™์€ ์žฅ์†Œ์—์„œ ๋‹ค๋ฅธ ์‹œ๊ฐ„๋Œ€๋ฅผ ์“ด๋‹ค.
      • ์ด์Šค๋ผ์—˜์˜ ์œ ๋Œ€์ธ๊ณผ ํŒ”๋ ˆ์Šคํƒ€์ธ๋ผ๋ฆฌ
      • ๋ฏธ๊ตญ ๋‚ด ์ธ๋””์–ธ๋ณดํ˜ธ๊ตฌ์—ญ
    • ์ผ๋ถ€ ๊ตญ๊ฐ€์—์„œ ์—ฌ๋ฆ„์— ํ•œ์‹œ๊ฐ„ ๋‹น๊ฒจ ์ƒํ™œํ•˜๋Š” ์„œ๋จธํƒ€์ž„์„ ์ ์šฉํ•œ๋‹ค.
      • ๊ฐ™์€ ๊ตญ๊ฐ€๋ผ๋„ ์„œ๋จธํƒ€์ž„ ์ ์šฉ์—ฌ๋ถ€๊ฐ€ ์ง€์—ญ์— ๋”ฐ๋ผ ๋‹ฌ๋ผ์ง„๋‹ค.
      • ๋‚จ๋ฐ˜๊ตฌ์™€ ๋ถ๋ฐ˜๊ตฌ์™€ ๊ณ„์ ˆ์ด ๋ฐ˜๋Œ€์ด๋ฏ€๋กœ, ๋‚จ๋ฐ˜๊ตฌ๋Š” ์„œ๋จธํƒ€์ž„์„ 11์›”์— ์ ์šฉํ•œ๋‹ค.
    • ์ผ๋ถ€ ๊ตญ๊ฐ€๋Š” ์†Œ์† ์‹œ๊ฐ„๋Œ€๋ฅผ ๋ณ€๊ฒฝํ•œ ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค.
    • ๋‹ฌ๋ ฅ์˜ ์˜ค์ฐจ๋ฅผ ์กฐ์ •ํ•˜๊ธฐ ์œ„ํ•ด '์œค์ดˆ'๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค.
      • ์œค์ดˆ๊ฐ€ ์‚ฝ์ž…๋œ ๋‚ ์˜ ๋งˆ์ง€๋ง‰์„ 59 / 59 / 00์œผ๋กœ ํ•˜๋ฉด 1์ดˆ๋งŒํผ์˜ ์‹œ๊ฐ„ ๋”œ๋ ˆ์ด๊ฐ€ ์ƒ๊ธด๋‹ค.
      • ์œค์ดˆ๊ฐ€ ์‚ฝ์ž…๋œ ๋‚ ์˜ ๋งˆ์ง€๋ง‰์„ 59 / 60 / 00์œผ๋กœ ํ•˜๋ฉด ๋ชจ๋“  ์‹œ๊ฐ„์ฒ˜๋ฆฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์žฌ์ •์˜ํ•ด์•ผ ํ•œ๋‹ค.
      • ์œค์ดˆ๋ฅผ 24 * 60 * 60์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ์œค์ดˆ๊ฐ€ ์‚ฝ์ž…๋œ ๋‚ ์€ 1์ดˆ๋งˆ๋‹ค a๋ฐ€๋ฆฌ์ดˆ๋ฅผ ๋”ํ•ด์ฃผ๋ฉด, ์‹œ๊ฐ„๋™๊ธฐํ™”/์‹œ๊ฐ„์ฒ˜๋ฆฌ ๋ฌธ์ œ๋Š” ํ•ด๊ฒฐ๋˜๋‚˜ 1์ดˆ๊ฐ€ ๋ถ€์ •ํ™•ํ•ด์ง„๋‹ค.
  • ํ•ฉ๋ฆฌ์ ์ธ ๋Œ€์•ˆ : joda-time ๋“ฑ ์ด๋ฏธ ๊ฒ€์ฆ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , ์œ„์—์„œ ์–ธ๊ธ‰ํ•œ ๋ฌธ์ œ๋ฅผ ํ˜ผ์ž ํ•ด๊ฒฐํ•˜๋ ค๋Š” ์ƒ๊ฐ์€ ๋ฒ„๋ฆฐ๋‹ค.

โš ๏ธ **GitHub.com Fallback** โš ๏ธ