Programing

LocalDateTime으로 날짜를 구문 분석 / 형식화하는 방법은 무엇입니까?

lottogame 2020. 3. 14. 10:01
반응형

LocalDateTime으로 날짜를 구문 분석 / 형식화하는 방법은 무엇입니까? (자바 8)


Java 8 은 날짜 및 시간 작업을위한 새로운 java.time API를 추가했습니다 ( JSR 310 ).

날짜와 시간이 문자열로 있습니다 (예 :) "2014-04-08 12:30". LocalDateTime주어진 문자열에서 인스턴스를 어떻게 얻을 수 있습니까?

LocalDateTime객체 작업을 마친 후 : LocalDateTime인스턴스를 위에 표시된 것과 같은 형식의 문자열로 다시 변환하려면 어떻게 해야합니까?


구문 분석 날짜 및 시간

LocalDateTime문자열에서 객체 를 만들려면 정적 LocalDateTime.parse()메서드를 사용할 수 있습니다 . 문자열과 DateTimeFormatter매개 변수로 사용됩니다. DateTimeFormatter날짜 / 시간 패턴을 지정하는 데 사용됩니다.

String str = "1986-04-08 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);

날짜 및 시간 형식

형식화 된 문자열을 LocalDateTime객체로 만들려면 format()방법을 사용할 수 있습니다 .

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"

에 상수로 미리 정의 된 몇 가지 일반적으로 사용되는 날짜 / 시간 형식이 있습니다 DateTimeFormatter. 예를 들어 :를 사용 DateTimeFormatter.ISO_DATE_TIME하여 LocalDateTime인스턴스를 위에서 형식화 하면 string이 "1986-04-08T12:30:00"됩니다.

parse()format()방법은 모든 날짜 / 시간 관련 개체 사용할 수 있습니다 (예를 들어, LocalDate또는 ZonedDateTime)


ISO-8601 형식 인 경우 패턴을 제공하지 않고 LocalDate.parse()또는 LocalDateTime.parse()사용할 수 있습니다 .StringString

예를 들어

String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
System.out.println("Date: " + aLD);

String strDatewithTime = "2015-08-04T10:11:30";
LocalDateTime aLDT = LocalDateTime.parse(strDatewithTime);
System.out.println("Date with Time: " + aLDT);

출력 ,

Date: 2015-08-04
Date with Time: 2015-08-04T10:11:30

DateTimeFormatter다른 날짜 패턴을 처리해야하는 경우에만 사용하십시오 . 예를 들어 dd MMM uuuu 는 해당 월의 일 (2 자리), 해당 월 이름의 3 자 (Jan, Feb, Mar, ...)를 나타냅니다. 그리고 네 자리 연도 :

DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
String anotherDate = "04 Aug 2015";
LocalDate lds = LocalDate.parse(anotherDate, dTF);
System.out.println(anotherDate + " parses to " + lds);

산출

04 Aug 2015 parses to 2015-08-04

또한 DateTimeFormatter객체가 양방향 이라는 것을 기억하십시오 . 입력과 형식 출력을 구문 분석 할 수 있습니다.

String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
System.out.println(aLD + " formats as " + dTF.format(aLD));

산출

2015-08-04 formats as 04 Aug 2015

(완전한 참조 포맷 및 구문 분석 DateFormatter에 대한 패턴의 목록 )

  Symbol  Meaning                     Presentation      Examples
  ------  -------                     ------------      -------
   G       era                         text              AD; Anno Domini; A
   u       year                        year              2004; 04
   y       year-of-era                 year              2004; 04
   D       day-of-year                 number            189
   M/L     month-of-year               number/text       7; 07; Jul; July; J
   d       day-of-month                number            10

   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
   Y       week-based-year             year              1996; 96
   w       week-of-week-based-year     number            27
   W       week-of-month               number            4
   E       day-of-week                 text              Tue; Tuesday; T
   e/c     localized day-of-week       number/text       2; 02; Tue; Tuesday; T
   F       week-of-month               number            3

   a       am-pm-of-day                text              PM
   h       clock-hour-of-am-pm (1-12)  number            12
   K       hour-of-am-pm (0-11)        number            0
   k       clock-hour-of-am-pm (1-24)  number            0

   H       hour-of-day (0-23)          number            0
   m       minute-of-hour              number            30
   s       second-of-minute            number            55
   S       fraction-of-second          fraction          978
   A       milli-of-day                number            1234
   n       nano-of-second              number            987654321
   N       nano-of-day                 number            1234000000

   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

   p       pad next                    pad modifier      1

   '       escape for text             delimiter
   ''      single quote                literal           '
   [       optional section start
   ]       optional section end
   #       reserved for future use
   {       reserved for future use
   }       reserved for future use

위의 두 답변 모두 문자열 패턴에 관한 질문을 잘 설명합니다. 그러나 ISO 8601 로 작업하는 경우 DateTimeFormatterLocalDateTime이 이미 준비되어 있으므로 적용 할 필요가 없습니다 .

LocalDateTime을 표준 시간대 ISO8601 문자열로 변환

LocalDateTime ldt = LocalDateTime.now(); 
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC); //you might use a different zone
String iso8601 = zdt.toString();

ISO8601 문자열에서 LocalDateTime으로 다시 변환

String iso8601 = "2016-02-14T18:32:04.150Z";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601);
LocalDateTime ldt = zdt.toLocalDateTime();

날짜와 시간이 포함 된 문자열을 특정 시점으로 구문 분석하는 것은 (Java에서 " Instant"라고 함) 매우 복잡합니다. Java는 이것을 여러 번 반복하여 다루어 왔습니다. 최신 하나 java.timejava.time.chrono, 커버 거의 모든 요구 (제외 시간 팽창 시킴 :)).

그러나 이러한 복잡성은 많은 혼란을 초래합니다.

날짜 구문 분석을 이해하는 핵심은 다음과 같습니다.

왜 Java가 날짜를 파싱하는 방법이 많은가?

  1. 시간을 측정하기위한 여러 시스템이 있습니다. 예를 들어, 역사적인 일본 달력은 각 황제 또는 왕조의 통치 기간에서 파생되었습니다. 그런 다음 UNIX 타임 스탬프가 있습니다. 다행히도 (비즈니스) 전 세계가 같은 것을 사용했습니다.
  2. 역사적으로 시스템은 여러 가지 이유로 전환되었습니다 . 예를 들어 율리우스 력 (Julian calendar)에서 1582 년 그레고리력 (Gregorian calendar)까지. 따라서 그 전에 '서부'날짜는 다르게 취급되어야한다.
  3. 물론 변경 사항은 한 번에 발생하지 않았습니다. 달력은 일부 종교와 유럽의 다른 지역의 헤드 쿼트에서 나왔기 때문에 다른식이 요법을 믿었습니다. 예를 들어 독일은 1700 년까지 전환하지 않았습니다.

... 그리고 왜 LocalDateTime, ZonedDateTime외. 너무 복잡한

  1. 있다 시간대 . 표준 시간대는 기본적으로 지구 표면의 "스트라이프" * [1] 이며, 권한을 가진 기관은 시간 오프셋이있는 시점과 동일한 규칙을 따릅니다. 여기에는 여름철 규칙이 포함됩니다.
    시간대는 다양한 영역에 대해 시간이 지남에 따라 변경되며, 주로 누가 정복했는지에 따라 다릅니다. 한 시간대의 규칙도 시간이 지남에 따라 변경 됩니다.

  2. 시간 오프셋이 있습니다. 표준 시간대는 "프라하"일 수 있지만 여름 시간 오프셋과 겨울 시간 오프셋이 있기 때문에 표준 시간대와 동일하지 않습니다.
    시간대가 포함 된 타임 스탬프를 받으면 해당 연도의 일부에 따라 오프셋이 달라질 수 있습니다. 윤기 시간 동안 타임 스탬프는 두 번 다른 시간을 의미 할 수 있으므로 추가 정보 없이는 신뢰할 수 없습니다. 변환.
    참고 : 타임 스탬프 란 "선택적으로 시간대 및 / 또는 시간 오프셋이있는 날짜 및 / 또는 시간을 포함하는 문자열"을 의미합니다.

  3. 여러 시간대는 특정 기간 동안 동일한 시간 오프셋을 공유 할 수 있습니다. 예를 들어 서머 타임 오프셋이 적용되지 않은 경우 GMT / UTC 시간대는 "런던"시간대와 동일합니다.

좀 더 복잡하게 만들려면 (그러나 사용 사례에 그렇게 중요하지는 않습니다) :

  1. 과학자들은 지구의 역 동성을 관찰합니다. 이를 바탕으로 개별 연도 말에 초를 추가합니다. (그래서 2040-12-31 24:00:00유효한 날짜 - 시간이 될 수 있습니다.) 이것은 메타 데이터를 정기적으로 업데이트해야 시스템이 바로 날짜 변환을 위해 사용하는. 예를 들어 Linux에서는 이러한 새 데이터를 포함하여 Java 패키지를 정기적으로 업데이트합니다.
  2. 업데이트가 항상 과거 및 미래 타임 스탬프에 대해 이전 동작을 유지하지는 않습니다. 따라서 일부 시간대 변경을 기준으로 두 타임 스탬프를 구문 분석 하면 서로 다른 버전의 소프트웨어에서 실행될 때 다른 결과를 얻을 수 있습니다. 이는 영향을받는 시간대와 다른 시간대를 비교하는 데에도 적용됩니다.

    이로 인해 소프트웨어에 버그가 발생하면 UNIX 타임 스탬프 와 같이 복잡한 규칙이없는 타임 스탬프를 사용하는 것이 좋습니다.

  3. 미래 날짜의 경우 7로 인해 날짜를 정확하게 변환 할 수 없습니다. 예를 들어 현재 구문 분석은 8524-02-17 12:00:00향후 구문 분석에서 몇 초가 걸릴 수 있습니다.

이를위한 JDK의 API는 현대의 요구와 함께 발전했습니다.

  • 초기 Java 릴리스에는 java.util.Date연도, 월, 일 및 시간이 있다고 가정하고 약간 순진한 접근 방식이있었습니다. 이것은 빨리 충분하지 않았다.
  • 또한 데이터베이스의 요구 사항은 매우 다르기 때문에 java.sql.Date자체 제한 사항이 있지만 매우 초기 에 도입되었습니다.
  • 다른 캘린더와 시간대를 모두 다루지 않았으므로 CalendarAPI가 도입되었습니다.
  • 이것은 여전히 ​​표준 시간대의 복잡성을 다루지 않았습니다. 그러나 위 API의 혼합은 실제로 작업하기가 어려웠습니다. 따라서 Java 개발자가 글로벌 웹 응용 프로그램 작업을 시작하면서 JodaTime과 같은 대부분의 사용 사례를 대상으로하는 라이브러리가 빠르게 인기를 얻었습니다. JodaTime은 약 10 년 동안 사실상의 표준이었습니다.
  • 그러나 JDK는 JodaTime과 통합되지 않았으므로 작업이 약간 번거로 웠습니다. 따라서 JSR-310 은이 문제에 접근하는 방법에 대한 매우 긴 토론 끝에 주로 JodaTime을 기반 으로 만들어졌습니다 .

Java에서 처리하는 방법 java.time

타임 스탬프를 구문 분석 할 유형 결정

타임 스탬프 문자열을 사용할 때는 어떤 정보가 들어 있는지 알아야합니다. 이것이 중요한 포인트입니다. 이 권한을 얻지 못하면 "즉시 만들 수 없음"또는 "영역 오프셋 누락"또는 "알 수없는 영역 ID"등과 같은 예외적 인 예외가 발생합니다.

날짜와 시간이 포함되어 있습니까?

  1. 시간 오프셋이 있습니까?
    시간 오프셋이 +hh:mm부품입니다. 경우에 따라 '줄루 시간', 표준시 또는 그리니치 표준시 +00:00로 대체 될 수 있습니다 . 또한 시간대를 설정합니다. 이 타임 스탬프에는을 사용 합니다.ZUTCGMT
    OffsetDateTime

  2. 시간대가 있습니까?
    이 타임 스탬프에는을 사용 ZonedDateTime합니다.
    영역은 다음 중 하나로 지정됩니다.

    • 이름 ( "프라하", "태평양 표준시", "PST") 또는
    • "zone ID"( "America / Los_Angeles", "Europe / London")는 java.time.ZoneId로 표시됩니다 .

    시간대 목록은 ICAAN이 지원 하는 "TZ 데이터베이스"에 의해 컴파일됩니다 .

    ZoneId의 javadoc 에 따르면 영역 ID를 어떻게 든 지정 Z하고 오프셋 으로 지정할 수 있습니다 . 이것이 실제 영역에 어떻게 매핑되는지 잘 모르겠습니다. TZ 만있는 타임 스탬프가 윤초 시간 오프셋 변경에 속하면 모호하며 해석이 적용 ResolverStyle됩니다 (아래 참조).

  3. 이 둘 다 없으면 누락 된 컨텍스트가 가정되거나 무시됩니다. 그리고 소비자는 결정해야합니다. 따라서 누락 된 정보를 추가하여 구문 분석 LocalDateTime하고 변환해야 OffsetDateTime합니다.

    • UTC 시간 이라고 가정 할 수 있습니다 . UTC 오프셋을 0 시간으로 추가하십시오.
    • 전환이 발생한 시점 이라고 가정 할 수 있습니다 . 시스템 시간대를 추가하여 변환하십시오.
    • 무시 하고 그대로 사용할 수 있습니다 . 예를 들어 두 번 비교하거나 빼는 데 유용합니다 (참조 Duration). 모르거나 실제로 중요하지 않은 경우 (예 : 로컬 버스 일정).

부분 시간 정보

  • 타임 스탬프가 포함 된 내용을 바탕으로, 당신이 취할 수 LocalDate, LocalTime, OffsetTime, MonthDay, Year, 또는 YearMonth그것에서.

전체 정보가 있으면를 얻을 수 있습니다 java.time.Instant. 또한 내부적으로 OffsetDateTime사이를 변환하는 데 사용됩니다 ZonedDateTime.

그것을 파싱하는 방법을 알아 내십시오.

DateTimeFormatter타임 스탬프 문자열과 형식을 문자열로 구문 분석 할 수 있는 광범위한 설명서 가 있습니다.

미리 만들어진 DateTimeFormatter 더보기 간략히 모든 표준 타임 스탬프 형식을 포함해야한다. 예를 들어, ISO_INSTANT구문 분석 할 수 있습니다 2011-12-03T10:15:30.123457Z.

특별한 형식이있는 경우 고유 한 DateTimeFormatter (파서이기도 함)를 만들있습니다 .

private static final DateTimeFormatter TIMESTAMP_PARSER = new DateTimeFormatterBuilder()
   .parseCaseInsensitive()
   .append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SX"))
   .toFormatter();

의 소스 코드를보고를 사용하여 소스 코드를 DateTimeFormatter작성하는 방법에 대해 영감을 얻는 것이 좋습니다 DateTimeFormatterBuilder. 또한 ResolverStyle파서가 형식 및 모호한 정보에 대해 LENIENT, SMART 또는 STRICT인지 여부를 제어 하는 방법도 살펴보십시오 .

임시 접근 자

이제 빈번한 실수는의 복잡성에 들어가는 것입니다 TemporalAccessor. 개발자가 작업하는 방식에서 비롯된 것입니다 SimpleDateFormatter.parse(String). 오른쪽, DateTimeFormatter.parse("...")당신을 제공합니다 TemporalAccessor.

// No need for this!
TemporalAccessor ta = TIMESTAMP_PARSER.parse("2011-... etc");

그러나 이전 섹션의 지식을 갖추고 있으면 필요한 유형으로 편리하게 구문 분석 할 수 있습니다.

OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z", TIMESTAMP_PARSER);

실제로 DateTimeFormatter어느 쪽도 필요하지 않습니다 . 구문 분석하려는 유형에는 parse(String)메소드가 있습니다.

OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z");

에 관해서 TemporalAccessor는 문자열에 어떤 정보가 있는지 모호하고 런타임에 결정하려는 경우 사용할 수 있습니다.

나는 당신의 영혼에 대한 이해의 빛을 비추기를 바랍니다 :)

참고 : java.timeJava 6 및 7 : BackTen-Backport 백 포트가 있습니다 . 안드로이드에는 ThreeTenABP가 있습니다.

[1] 그것들은 줄무늬가 아니라 이상한 극단도 있습니다. 예를 들어, 일부 인접한 태평양 섬 에는 +14 : 00 및 -11 : 00 시간대가 있습니다. 즉, 한 섬에는 5 월 1 일 오후 3시, 다른 섬에는 아직 4 월 12 일 오후 4시 30 분이 있습니다 (정확하게 계산 된 경우).

참고 URL : https://stackoverflow.com/questions/22463062/how-to-parse-format-dates-with-localdatetime-java-8

반응형