ISO 8601 호환 문자열을 java.util.Date로 변환


668

ISO 8601 형식의 문자열을 로 변환하려고 합니다 java.util.Date.

yyyy-MM-dd'T'HH:mm:ssZ로케일 (샘플 비교)과 함께 사용 하면 패턴 이 ISO8601을 준수한다는 것을 알았습니다 .

그러나를 사용하면 java.text.SimpleDateFormat올바른 형식의 String을 변환 할 수 없습니다 2010-01-01T12:00:00+01:00. 2010-01-01T12:00:00+0100콜론없이 먼저로 변환해야 합니다.

현재 솔루션은

SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.GERMANY);
String date = "2010-01-01T12:00:00+01:00".replaceAll("\\+0([0-9]){1}\\:00", "+0$100");
System.out.println(ISO8601DATEFORMAT.parse(date));

분명히 그렇게 좋지 않습니다. 내가 누락되었거나 더 나은 해결책이 있습니까?


대답

JuanZe의 의견 덕분에 Joda-Time 마술을 발견했으며 여기에도 설명되어 있습니다 .

그래서 해결책은

DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));

또는 간단히 말하면 생성자를 통해 기본 파서를 사용하십시오.

DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;

나에게 이것은 좋다.


243
"Use JodaTime"답변을 많이받을 준비를하십시오 ...
JuanZe

3
@ Ice09 : DateTimeFormat에 대한 API 설명서가 정확하면 (JoDa 설명서가 잘못되거나 잘못되었거나 불완전 할 수 있음), 자신의 "답변"에 사용한 패턴이 ISO8601과 호환되지 않습니다.
jarnbjo

21
이것이 언제 추가되었는지 확실하지 않지만 'X'는 SimpleDateFormat 내 에서이 문제를 해결하는 것으로 보입니다. "yyyy-MM-dd'T'HH : mm : ssX"패턴은 질문의 예제를 성공적으로 구문 분석합니다.
mlohbihler

12
'X'는 Java 7부터 사용할 수 있습니다.
Lars Grammel

3
Java 8을 사용하면 쉬워집니다! 아래 답변에 Adam의 숨겨진 보석이 있습니다. stackoverflow.com/a/27479533/1262901
Fabian Keller

답변:


477

불행히도 SimpleDateFormat (Java 6 이하)에 사용 가능한 시간대 형식 은 ISO 8601을 준수 하지 않습니다 . SimpleDateFormat은 "GMT + 01 : 00"또는 "+0100"과 같은 시간대 문자열을 이해하며 RFC # 822 에 따른 문자열 입니다.

Java 7이 ISO 8601에 따라 시간대 디스크립터에 대한 지원을 추가하더라도 SimpleDateFormat은 선택적 파트를 지원하지 않으므로 완전한 날짜 문자열을 올바르게 구문 분석 할 수 없습니다.

regexp를 사용하여 입력 문자열을 다시 포맷하는 것은 분명히 하나의 가능성이지만 대체 규칙은 질문처럼 간단하지 않습니다.

  • 일부 시간대는 UTC 이외의 정규 시간이 아니므로 문자열이 반드시 ": 00"으로 끝나는 것은 아닙니다.
  • ISO8601은 시간대에 포함 된 시간 만 허용하므로 "+01"은 "+01 : 00"과 같습니다.
  • ISO8601에서는 "Z"를 사용하여 "+00 : 00"대신 UTC를 나타낼 수 있습니다.

JAXB가 XML 스키마 스펙에 따라 ISO8601 날짜 문자열을 구문 분석 할 수 있어야하므로 더 쉬운 솔루션은 JAXB에서 데이터 유형 변환기를 사용하는 것입니다. 객체 javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")를 제공하고 Calendar객체가 필요한 경우 getTime ()을 사용할 수 있습니다 Date.

아마도 Joda-Time 을 사용할 수도 있지만 왜 그렇게 신경 써야할지 모르겠습니다.


18
JAXB 솔루션은 정말 창의적인 접근 방식입니다! 그것은 또한 효과가 있으며 샘플로 테스트했습니다. 그러나 문제에 직면하고 JodaTime을 사용할 수있는 사람에게는 더 자연 스럽기 때문에 사용하는 것이 좋습니다. 그러나 솔루션에는 추가 라이브러리가 필요하지 않습니다 (적어도 Java 6에서는).
Ice09

36
반대는 다음과 같습니다. Calendar c = GregorianCalendar.getInstance (); c.setTime (aDate); return javax.xml.bind.DatatypeConverter.printDateTime (c);
Alexander Ljungberg

4
실제로 너무 간단한 b / c는 아니지만 jaxb datatypeConverter를 초기화해야합니다. DataTypeConverterImpl이 내부적으로했던 것처럼 DatatypeFactory를 직접 사용했습니다. 두통 이군
gtrak

3
@Simon : 아니요. 시간대는 물론 무시되지 않습니다. 당신은 뭔가 잘못하고 있어야합니다. 문자를 몇 개 이상 입력하고 실제로 무엇을하는지 알려 주면 누군가가 설명 할 수 있습니다.
jarnbjo

4
@jarnbjo 당신은 joda-time보다 표준, 1.8 이전의 자바 날짜 클래스를 선호하는 사람 중 처음이자 유일한 사람입니다. 나는 특히 가증 한 표준 api와 비교할 때 joda-time이 문자 그대로의 기쁨을 찾습니다.
NimChimpsky

245

Java 7 문서축복하는 방식 :

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
String string1 = "2001-07-04T12:08:56.235-0700";
Date result1 = df1.parse(string1);

DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
String string2 = "2001-07-04T12:08:56.235-07:00";
Date result2 = df2.parse(string2);

당신은 섹션에서 더 많은 예제를 찾을 수 있습니다 에서 SimpleDateFormat에의 javadoc는 .

UPD 02/13/2020 : Java 8에서이를 수행 하는 완전히 새로운 방법 이 있습니다


7
귀하의 답변으로 MongoDB의 ISODate를 현지 날짜로 변환 할 수있었습니다. 문안 인사.
푸른 하늘

9
@ b.long Java는 이러한 ISO 8601 호환 형식에 상수 이상을 추가했습니다. Java는 이러한 형식에 대한 기본 제공 기본 지원을 포함하여 날짜-시간 작업을위한 완전히 새로운 프레임 워크를 얻었습니다. Joda-Time 에서 영감을 얻은 java.util.Date, .Calendar 및 SimpleDateFormat 클래스를 대체하는 Java 8 의 새로운 java.time프레임 워크 를 참조하십시오 .
Basil Bourque

2
이것이 날짜 형식을 미리 알아야한다는 것을 의미하지 않습니까? 당신이 동의하는 경우 string1string2하지만 당신이 얻을 것이다 모른다.
Timmmm

16
'Z'는 따옴표로 묶어야합니다
kervin

7
@kervin Z가 따옴표로 묶인 경우 포맷터가 문자 Z를 구체적으로 찾지 않습니까? 날짜 문자열이 UTC로 발생한 경우 Z를 인용하면 우연의 일치로만 작동하는 것 같습니다.
spaaarky21

201

좋아,이 질문에 이미 답변되었지만 어쨌든 내 답변을 삭제하겠습니다. 누군가를 도울 수 있습니다.

Android (API 7) 솔루션을 찾고 있습니다.

  • Joda는 의문의 여지가 없었습니다-그것은 거대하고 초기화가 느려집니다. 또한 특정 목적을 위해 큰 과잉으로 보였다.
  • 관련 답변은 javax.xmlAndroid API 7에서 작동하지 않습니다.

이 간단한 클래스를 구현했습니다. 가장 일반적인 형식 의 ISO 8601 문자열 다루지 경우에 따라 충분해야합니다 (입력 형식 확실 할 경우 ).

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

/**
 * Helper class for handling a most common subset of ISO 8601 strings
 * (in the following format: "2008-03-01T13:00:00+01:00"). It supports
 * parsing the "Z" timezone, but many other less-used features are
 * missing.
 */
public final class ISO8601 {
    /** Transform Calendar to ISO 8601 string. */
    public static String fromCalendar(final Calendar calendar) {
        Date date = calendar.getTime();
        String formatted = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
            .format(date);
        return formatted.substring(0, 22) + ":" + formatted.substring(22);
    }

    /** Get current date and time formatted as ISO 8601 string. */
    public static String now() {
        return fromCalendar(GregorianCalendar.getInstance());
    }

    /** Transform ISO 8601 string to Calendar. */
    public static Calendar toCalendar(final String iso8601string)
            throws ParseException {
        Calendar calendar = GregorianCalendar.getInstance();
        String s = iso8601string.replace("Z", "+00:00");
        try {
            s = s.substring(0, 22) + s.substring(23);  // to get rid of the ":"
        } catch (IndexOutOfBoundsException e) {
            throw new ParseException("Invalid length", 0);
        }
        Date date = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ").parse(s);
        calendar.setTime(date);
        return calendar;
    }
}

성능 참고 사항 : Android 2.1 의 버그 를 피하기 위해 매번 새로운 SimpleDateFormat을 인스턴스화 합니다. 내가 그랬던 것처럼 이 수수께끼를보십시오 . 다른 Java 엔진의 경우 스레드를 안전하게하기 위해 ThreadLocal을 사용하여 개인 정적 필드에 인스턴스를 캐시 할 수 있습니다.


2
아마도 이것은 자체 답변과 함께 자체 문제로 제기되었을 것입니까?
Thorbear

5
이 답변을 찾을 때 내가 처음 봤던 페이지 였으므로 적합 해 보였습니다. 대부분의 Java 개발자에게 Android는 정확히 Java가 아닙니다. 그러나 대부분의 경우 하나는 다른 것과 동일하게 작동하므로 많은 Android 개발자가 이것을 찾을 때 "java"를 검색합니다.
wrygiel

1
이것은 밀리 초 해상도를 설명하지 않습니다. 이것은 쉽게 추가 할 수 있습니다.
스카이 켈지

6
분수 초 동안 .SSS를 추가해야했지만 큰 효과가 있습니다. 왜 당신은 s = s.substring(0, 22) + s.substring(23);-나는 이것에 요점을
Dori

1
input = input.replaceAll ( "[Zz]", "+0000"); 하위 문자열 작업을 피할 수 있습니다.
Javanator

115

java.time

java.time의 API (나중에 자바 8에 내장)를 좀 더 쉽게이 있습니다.

마지막에 (Zulu 의 경우와 같이) 입력이 UTC 이면 클래스를 구문 분석 할 수 있습니다.ZInstant

java.util.Date date = Date.from( Instant.parse( "2014-12-12T10:39:40Z" ));

입력이 끝에 (Zulu)로 표시된 UTC 가 아닌 다른 UTC에서 오프셋 값일 수있는 경우 클래스를 사용하여 구문 분석하십시오.ZOffsetDateTime

OffsetDateTime odt = OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" );

그런 다음을 추출하고을 호출 Instant하여 java.util.Date으로 변환하십시오 from.

Instant instant = odt.toInstant();  // Instant is always in UTC.
java.util.Date date = java.util.Date.from( instant );

8
이 답변은 너무 열심히 일하고 있습니다. 정의에 의한 java.util.Date에는 시간대가 없습니다. 따라서 모든 표준 시간대 관련 코드가 필요하지 않습니다 : LocalDateTimeand ZoneIdand atZone. 이 간단한 한 줄 할 것입니다 :java.util.Date date = Date.from( ZonedDateTime.parse( "2014-12-12T10:39:40Z" ).toInstant() );
바질 우르 큐에게

5
@BasilBourque 이것은 불필요하게 복잡하다 : Date.from(Instant.parse("2014-12-12T10:39:40Z" ));충분하다.
assylias

3
@assylias 당신은 정확하지만 날짜 문자열이 UTC 영역 일 때만 작동합니다. ISO8601은 모든 시간대를 허용합니다.
Adam

2
@ 아담 내 나쁜-나는 그 질문이 당신의 예보다 더 일반적이라는 것을 몰랐습니다. 부수적으로 OffsetDateTime표준 시간대 정보를 포함하지 않고 오프셋 만 포함하는 ISO8601을 구문 분석하기에 충분합니다.
assylias

1
@assylias Instant파싱 에 대한 귀하의 의견에 감사드립니다 . 이 특정 질문에 충분하지는 않지만 지적해야 할 중요한 차이점입니다. 그래서 코드의 두 번째 예를 추가했습니다. 죄송합니다. 이것이 원래 내 답변이 아님을 알았습니다. 아담이 승인하기를 바랍니다.
바질 부르 케

67

잭슨 데이터 바인딩 라이브러리는 또한이 ISO8601DateFormat 클래스 에서 그 (실제 구현하지 ISO8601Utils을 .

ISO8601DateFormat df = new ISO8601DateFormat();
Date d = df.parse("2010-07-28T22:25:51Z");

이 날짜를 구문 분석하지 못했습니다 : 2015-08-11T13:10:00. 나는 얻는다 String index out of range: 19. 코드를 보면 밀리 초와 시간대를 지정해야합니다. 그것들은 선택 사항이어야합니다.
Timmmm

2
설명서를 인용하기 위해 구문 분석 형식은 다음과 같습니다 [yyyy-MM-dd|yyyyMMdd][T(hh:mm[:ss[.sss]]|hhmm[ss[.sss]])]?[Z|[+-]hh:mm]]. 다시 말해, 밀리 초는 선택 사항이지만 시간대는 필수입니다.
david_p

2
아 네, 사실 그것은 당신이 옳은 것 같습니다. 여전히 ISO8601을 사용하면 시간대를 생략하여 여전히 틀릴 수 있습니다. JodaTime은 다음과 같이 작동합니다.new DateTime("2015-08-11T13:10:00").toDate()
Timmmm

3
해당 클래스는 더 이상 사용되지 않으며 새 클래스는 StdDateFormat입니다. 그렇지 않으면 동일하게 작동합니다.
JohnEye

51

tl; dr

OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" )

java.time 사용

Java 8 이상의 새로운 java.time 패키지는 Joda-Time에서 영감을 받았습니다.

OffsetDateTime클래스는 함께 타임 라인에 잠시 나타냅니다 부터 UTC 오프셋 이 아닌 시간대를.

OffsetDateTime odt = OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" );

호출 toString하면 표준 ISO 8601 형식으로 문자열이 생성됩니다.

2010-01-01T12 : 00 + 01 : 00

UTC 렌즈를 통해 동일한 값을 보려면를 추출 Instant하거나 오프셋을에서 +01:00로 조정하십시오 00:00.

Instant instant = odt.toInstant();  

…또는…

OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC );

원하는 경우 시간대를 조정하십시오. 시간대 의 역사 오프셋로부터 - UTC 예컨대 일광 절약 시간 (DST) 등의 변형을 처리하는 일련의 규칙으로, 영역에 대한 값. 따라서 가능할 때마다 단순한 오프셋이 아닌 시간대를 적용하십시오.

ZonedDateTime zonedDateTimeMontréal = odt.atZoneSameInstant( ZoneId.of( "America/Montreal" ) );

java.time에 대하여

java.time의 프레임 워크는 나중에 자바 8에 내장되어 있습니다. 이 클래스는 까다로운 기존에 대신 기존 과 같은 날짜 - 시간의 수업을 java.util.Date, Calendar, SimpleDateFormat.

Joda 타임 프로젝트는 지금에 유지 관리 모드 의로 마이그레이션을 조언 java.time의 클래스.

자세한 내용은 Oracle Tutorial을 참조하십시오 . 많은 예제와 설명을 보려면 스택 오버플로를 검색하십시오. 사양은 JSR 310 입니다.

java.time 객체를 데이터베이스와 직접 교환 할 수 있습니다 . JDBC 4.2 이상을 준수 하는 JDBC 드라이버를 사용하십시오 . 문자열이 필요없고 수업이 필요 없습니다 .java.sql.*

java.time 클래스는 어디서 구할 수 있습니까?

ThreeTen - 추가 프로젝트 추가 클래스와 java.time를 확장합니다. 이 프로젝트는 향후 java.time에 추가 될 수있는 입증 된 근거입니다. 당신은 여기에 몇 가지 유용한 클래스와 같은 찾을 수 있습니다 Interval, YearWeek, YearQuarter, 그리고 .



27

Java 버전 7의 경우

http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html Oracle 문서를 따를 수 있습니다.

X-ISO 8601 시간대에 사용

TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
df.setTimeZone(tz);
String nowAsISO = df.format(new Date());

System.out.println(nowAsISO);

DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
//nowAsISO = "2013-05-31T00:00:00Z";
Date finalResult = df1.parse(nowAsISO);

System.out.println(finalResult);

이것은 시간대가 필요하다는 것을 의미 합니다 . ISO 8601에 따르면 옵션입니다. 초 등도 마찬가지입니다. 따라서 이것은 ISO 8601의 특정 부분 집합 만 분석합니다.
Timmmm

1
자바 1.8로 좋은 작품
티아고 페레이라

20

DatatypeConverter 솔루션이 모든 VM에서 작동하지는 않습니다. 다음은 나를 위해 작동합니다.

javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime()

joda가 기본적으로 작동하지 않는다는 것을 알았습니다 (특히 날짜와 시간대를 위에서 지정한 예에서 유효해야 함)


15

나는 우리가 사용해야한다고 생각

DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")

날짜 2010-01-01T12:00:00Z


5
왜 76 개의 공감대에 허용되는 대답을 포함하여 다른 것보다 더 나은 대답입니까?
Erick Robertson

3
@ErickRobertson : 간단하고 유연하며 유연하며 전환이 없으며 대부분의 사람들은 시간대를 신경 쓰지 않습니다.
TWiStErRob

7
시간대를 신경 쓰지 않으면 시간을 다루는 것이 중요하지 않습니다!
Dori

16
이것은 시간대를 완전히 무시 합니다. 이것이 일어나고 있다는 것을 깨달을 때까지 이것을 사용했기 때문에 JodaTime으로 전환했습니다.
Joshua Pinter

3
시간대를 버리면 어느 시점에서 오류가 발생합니다.
Bart van Kuik

11

Java 8부터는 공식적으로 지원되는 완전히 새로운 방법이 있습니다.

    String s = "2020-02-13T18:51:09.840Z";
    TemporalAccessor ta = DateTimeFormatter.ISO_INSTANT.parse(s);
    Instant i = Instant.from(ta);
    Date d = Date.from(i);

2
문자열이 인스턴트 형식이고 후행 Z이 오프셋 인 경우이를 명시 적으로 지정할 필요가 없습니다. 그냥 Instant i = Instant.parse(s);. 질문의 문자열에는 +01:00이 경우 DateTimeFormatter.ISO_INSTANT작동하지 않습니다 (적어도 Java 11에서는 작동하지 않음).
Ole VV

2
@ OleV.V. ( docs.oracle.com/javase/8/docs/api/java/time/format/… ) ISO_OFFSET_DATE_TIME와 같이 오프셋으로 날짜를 형식화 하는 데 사용할 수 있습니다.+01:00
Lucas Basquerotto

1
사실입니다, @LucasBasquerotto. 해당 포맷터를 명시 적으로 언급하지는 않았지만 AdamBasil Bourque 의 답변 이미 비슷한 것을 수행합니다.
Ole VV

10

ISO8601 타임 스탬프를 구문 분석하는 또 다른 매우 간단한 방법은 다음을 사용하는 것입니다 org.apache.commons.lang.time.DateUtils.

import static org.junit.Assert.assertEquals;

import java.text.ParseException;
import java.util.Date;
import org.apache.commons.lang.time.DateUtils;
import org.junit.Test;

public class ISO8601TimestampFormatTest {
  @Test
  public void parse() throws ParseException {
    Date date = DateUtils.parseDate("2010-01-01T12:00:00+01:00", new String[]{ "yyyy-MM-dd'T'HH:mm:ssZZ" });
    assertEquals("Fri Jan 01 12:00:00 CET 2010", date.toString());
  }
}

6

java.time

Java 8에서는 java.time.ZonedDateTime 클래스와 해당 정적 parse(CharSequence text)메소드를 사용할 수 있습니다 .


질문의 입력 문자열에는 표준 시간대가 아닌 UTC에서 오프셋 만 있습니다. 그래서 Instant하고 ZonedDateTime있으며, 여기에 적절하지 ZonedDateTime.
Basil Bourque

6

Java 7+에 대한 해결 방법은 SimpleDateFormat을 사용하는 것입니다.
DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);

이 코드는 다음과 같이 ISO8601 형식을 구문 분석 할 수 있습니다.

  • 2017-05-17T06:01:43.785Z
  • 2017-05-13T02:58:21.391+01:00

그러나 Java6에서는 문자를 SimpleDateFormat이해하지 못하고 X던질 것입니다.
IllegalArgumentException: Unknown pattern character 'X'
ISO8601 날짜를 Java 6에서 읽을 수있는 형식으로 정규화해야합니다 SimpleDateFormat.

public static Date iso8601Format(String formattedDate) throws ParseException {
    try {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX", Locale.US);
        return df.parse(formattedDate);
    } catch (IllegalArgumentException ex) {
        // error happen in Java 6: Unknown pattern character 'X'
        if (formattedDate.endsWith("Z")) formattedDate = formattedDate.replace("Z", "+0000");
        else formattedDate = formattedDate.replaceAll("([+-]\\d\\d):(\\d\\d)\\s*$", "$1$2");
        DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.US);
        return df1.parse(formattedDate);
    }
}

Java 6에서 오류가 발생할 때 [ Zwith +0000] 또는 [ +01:00with +0100] 를 대체하는 위의 방법 (Java 버전을 감지하고 try / catch를 if 문으로 대체 할 수 있음)


아니, 같은 귀찮은 된 날짜 - 시간의 수업 Date과는 SimpleDateFormat제대로 혼란, 설계 및 결함이 있습니다. Java 8 이상에 내장 된 java.time 클래스로 대체 된 레거시입니다. Java 6 및 Java 7의 경우 많은 java.time 기능이 ThreeTen-Backport 프로젝트 에서 백 포트됩니다 . 레거시 클래스를 사용하는 것보다 해당 라이브러리를 앱에 추가하는 것이 훨씬 좋습니다. java.time의 한 줄 솔루션 :OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" )
Basil Bourque

5

나는 같은 문제에 직면하여 다음 코드로 해결했다.

 public static Calendar getCalendarFromISO(String datestring) {
    Calendar calendar = Calendar.getInstance(TimeZone.getDefault(), Locale.getDefault()) ;
    SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());
    try {
        Date date = dateformat.parse(datestring);
        date.setHours(date.getHours() - 1);
        calendar.setTime(date);

        String test = dateformat.format(calendar.getTime());
        Log.e("TEST_TIME", test);

    } catch (ParseException e) {
        e.printStackTrace();
    }

    return calendar;
}

내가 사용했던 이전 SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ", Locale.getDefault());

그러나 나중에 나는 예외의 주요 원인이이었다 발견 yyyy-MM-dd'T'HH:mm:ss.SSSZ,

그래서 나는 사용했다

SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.getDefault());

그것은 나를 위해 잘 작동했습니다.


Joda-time, XML API 또는 다른 것을 사용하지 않고도 필요한 것. 올바른 패턴입니다.
Philippe Gioseffi


4

Java는 여기에 훌륭한 답변이 보여주는 것처럼 날짜-시간을 구문 분석하는 수십 가지 방법이 있습니다. 그러나 놀랍게도 Java의 시간 클래스 중 어느 것도 ISO 8601을 완전히 구현하지 않습니다!

자바 8을, 내가 권하고 싶습니다 :

ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());

UTC와 "2017-09-13T10 : 36 : 40Z"또는 "2017-09-13T10 : 36 : 40 + 01 : 00"과 같은 오프셋으로 예제를 처리합니다. 대부분의 사용 사례에 적용됩니다.

그러나 같은 예를 처리하지 않습니다 "2017-09-13T10을 : 36 : 40 + 01",하는 것입니다 유효한 ISO 8601 날짜 - 시간.
또한 단지 날짜, 예를 들어 "2017년 9월 13일"을 처리하지 않습니다.

그것들을 처리해야한다면, 먼저 정규 표현식을 사용하여 구문을 알아내는 것이 좋습니다.

ISO의 좋은 목록이 코너의 경우 많은 8601 예 여기 있습니다 : https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/을 난 모든 클래스에 대처할 수있는 Java 클래스를 인식하지 못합니다.


OffsetDateTime날짜 시간과 오프셋을 더 잘 일치시킵니다.
Ole VV

안녕하세요 @ OleV.V. 제안 해 주셔서 감사합니다. 슬프게도 번호 : OffsetDateTime.parse ()는 예를 들어, 여러 유효한 ISO 8601 문자열 ": 36 : 2017-09-13T10 40 + 01"예외가 발생하지 않습니다 또는 "2017년 9월 13일을"
다니엘 Winterstein

나는 OffsetDateTime당신이 다루는 예제를 처리 한다고 말하고 싶었 습니다 ZonedDateTime. 나는 그것이 그렇지 않은 예제를 ZonedDateTime다루지 않는다고 생각합니다. 그런 의미에서 그것은 개선되지 않습니다 (그러나 더 나쁘지 않습니다). 미안, 나는 명확하지 않았다.
Ole VV

1
이것은 상황에 따라 2020 년에 받아 들여진 대답이어야합니다.
slashCoder

3

Apache Jackrabbit 는 날짜를 유지하기 위해 ISO 8601 형식을 사용하며,이를 파싱하는 도우미 클래스가 있습니다.

org.apache.jackrabbit.util.ISO8601

jackrabbit-jcr-commons 와 함께 제공 됩니다.


Jackrabbit의 하위 집합이 작동 할 수 있지만 본격적인 목적으로 구축 된 라이브러리를 사용하는 것이 더 합리적입니다. Java에서는 Joda-Time 또는 java.time을 의미합니다.
Basil Bourque

3

다른 사람들이 언급했듯이 Android는 SDK에 포함 된 클래스를 사용하여 ISO 8601 날짜 구문 분석 / 서식을 지원하는 좋은 방법이 없습니다. 이 코드를 여러 번 작성 했으므로 ISO 8601 및 RFC 1123 날짜 형식 및 구문 분석을 지원하는 DateUtils 클래스가 포함 된 Gist를 마침내 만들었습니다. 요지는 또한 그것이 지원하는 것을 보여주는 테스트 케이스를 포함합니다.

https://gist.github.com/mraccola/702330625fad8eebe7d3


2

JAVA 1.7 용 SimpleDateFormat에는 ISO 8601 형식에 대한 멋진 패턴이 있습니다.

클래스 SimpleDateFormat

여기 내가 한 일이 있습니다.

Date d = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
         Locale.ENGLISH).format(System.currentTimeMillis());

2
Z형식 문자열에서 ISO 8601 시간대가 아닌 경우 ISO 8601 시간대 를 원하면 X(또는 XX또는 XXX)를 사용해야합니다
Vojta

D는 String 유형이다
팀 아동

1

다음과 같이하십시오 :

public static void main(String[] args) throws ParseException {

    String dateStr = "2016-10-19T14:15:36+08:00";
    Date date = javax.xml.bind.DatatypeConverter.parseDateTime(dateStr).getTime();

    System.out.println(date);

}

출력은 다음과 같습니다.

수 10 월 19 일 15:15:36 CST 2016


1

같은 사용 문자열 LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)


1

하나의 Java 라이브러리조차도 https://en.wikipedia.org/wiki/ISO_8601에 따라 모든 ISO 8601 날짜 형식을 지원하지는 않습니다 . Joda DateTime은 대부분을 지원했지만 전부는 아니므로 모든 것을 처리하기 위해 사용자 정의 논리를 추가했습니다. 여기 내 구현이 있습니다.

import java.text.ParseException;
import java.util.Date;

import org.apache.commons.lang3.time.DateUtils;
import org.joda.time.DateTime;

public class ISO8601DateUtils {
	
	/**
	 * It parses all the date time formats from https://en.wikipedia.org/wiki/ISO_8601 and returns Joda DateTime.
	 * Zoda DateTime does not support dates of format 20190531T160233Z, and hence added custom logic to handle this using SimpleDateFormat.
	 * @param dateTimeString ISO 8601 date time string
	 * @return
	 */
	public static DateTime parse(String dateTimeString) {
		try {
			return new DateTime( dateTimeString );
		} catch(Exception e) {
			try {
				Date dateTime = DateUtils.parseDate(dateTimeString, JODA_NOT_SUPPORTED_ISO_DATES);
				return new DateTime(dateTime.getTime());
			} catch (ParseException e1) {
				throw new RuntimeException(String.format("Date %s could not be parsed to ISO date", dateTimeString));
			}
		}
	}
  
  	private static String[] JODA_NOT_SUPPORTED_ISO_DATES = new String[] {
			// upto millis
			"yyyyMMdd'T'HHmmssSSS'Z'",
			"yyyyMMdd'T'HHmmssSSSZ",
			"yyyyMMdd'T'HHmmssSSSXXX",
			
			"yyyy-MM-dd'T'HHmmssSSS'Z'",
			"yyyy-MM-dd'T'HHmmssSSSZ",
			"yyyy-MM-dd'T'HHmmssSSSXXX",
			
			// upto seconds
			"yyyyMMdd'T'HHmmss'Z'",
			"yyyyMMdd'T'HHmmssZ",
			"yyyyMMdd'T'HHmmssXXX",
			
			"yyyy-MM-dd'T'HHmmss'Z'", 
			"yyyy-MM-dd'T'HHmmssZ",
			"yyyy-MM-dd'T'HHmmssXXX",
			
			// upto minutes
			"yyyyMMdd'T'HHmm'Z'",
			"yyyyMMdd'T'HHmmZ",
			"yyyyMMdd'T'HHmmXXX",

			"yyyy-MM-dd'T'HHmm'Z'",
			"yyyy-MM-dd'T'HHmmZ",
			"yyyy-MM-dd'T'HHmmXXX",
			
			//upto hours is already supported by Joda DateTime
	};
}


1

조금 테스트하는 방법 ISO8601의 날짜를 구문 분석하는 방법과 LocalDateTime이 DSTS을 처리하지 않는 것을 알 수있다.

 @Test
    public void shouldHandleDaylightSavingTimes() throws ParseException {

        //ISO8601 UTC date format
        SimpleDateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");

        // 1 hour of difference between 2 dates in UTC happening at the Daylight Saving Time
        Date d1 = utcFormat.parse("2019-10-27T00:30:00.000Z");
        Date d2 = utcFormat.parse("2019-10-27T01:30:00.000Z");

        //Date 2 is before date 2
        Assert.assertTrue(d1.getTime() < d2.getTime());
        // And there is 1 hour difference between the 2 dates
        Assert.assertEquals(1000*60*60, d2.getTime() - d1.getTime());

        //Print the dates in local time
        SimpleDateFormat localFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm z Z", Locale.forLanguageTag("fr_CH"));
        localFormat.setTimeZone(TimeZone.getTimeZone("Europe/Zurich"));

        //Both dates are at 02h30 local time (because of DST), but one is CEST +0200 and the other CET +0100 (clock goes backwards)
        Assert.assertEquals("2019-10-27 02:30 CEST +0200", localFormat.format(d1));
        Assert.assertEquals("2019-10-27 02:30 CET +0100", localFormat.format(d2));

        //Small test that shows that LocalDateTime does not handle DST (and should not be used for storing timeseries data)
        LocalDateTime ld1 = LocalDateTime.ofInstant(d1.toInstant(), ZoneId.of("Europe/Zurich"));
        LocalDateTime ld2 = LocalDateTime.ofInstant(d2.toInstant(), ZoneId.of("Europe/Zurich"));

        //Note that a localdatetime does not handle DST, therefore the 2 dates are the same
        Assert.assertEquals(ld1, ld2);

        //They both have the following local values
        Assert.assertEquals(2019, ld1.getYear());
        Assert.assertEquals(27, ld1.getDayOfMonth());
        Assert.assertEquals(10, ld1.getMonthValue());
        Assert.assertEquals(2, ld1.getHour());
        Assert.assertEquals(30, ld1.getMinute());
        Assert.assertEquals(0, ld1.getSecond());

    }

3
참고로, 매우 귀찮은 날짜-시간 수업 java.util.Date , java.util.Calendar그리고 java.text.SimpleDateFormat지금 기존 에 의해 대체, java.time의 나중에 자바 8에 내장 된 클래스. Oracle의 Tutorial 참조하십시오 .
Basil Bourque

LocalDateTime표준 시간대를 전혀 처리하지 않으므로 서머 타임 (DST)을 처리하지 않는 것이 맞습니다 . 이를 위해 우리는 필요합니다 ZonedDateTime. 제안 Date하고 SimpleDateFormat— IMHO 나쁘다.
Ole VV

1
실제로 ZonedDateTime이 작동합니다. 그리고 java.time.Instant는 DST를 처리하는 좋은 대안입니다. 나는 java.util.Date가 더 이상 사용되지 않으며 사용되어서는 안된다는 것을 알고 있지만 원래 질문에 대답하고있었습니다. 8601의 문자열을 java.util.date로 변환하는 방법 ...
ddtxra

0

비슷한 요구 사항이있었습니다. 정확한 형식을 미리 몰라도 ISO8601 호환 날짜를 구문 분석 할 수 있어야했으며 Android에서도 작동하는 간단한 솔루션을 원했습니다.

내 요구를봤을 때 나는이 질문을 우연히 발견하고 AFAIU, 내 대답에 완전히 맞는 대답이 없다는 것을 알았습니다. 그래서 jISO8601을 개발 하여 maven central에 푸시했습니다.

당신을 추가하십시오 pom.xml:

<dependency>
  <groupId>fr.turri</groupId>
  <artifactId>jISO8601</artifactId>
  <version>0.2</version>
</dependency>

그리고 당신은 갈 수 있습니다 :

import fr.turri.jiso8601.*;
...
Calendar cal = Iso8601Deserializer.toCalendar("1985-03-04");
Date date = Iso8601Deserializer.toDate("1985-03-04T12:34:56Z");

도움이되기를 바랍니다.


0

이와 같은 날짜를 형식화하기 위해 다음이 Java 6 기반 응용 프로그램에서 효과적이었습니다. thymeleaf 프로젝트에는 누락 된 콜론을 삽입 하는 DateFormat클래스 가 있습니다 JacksonThymeleafISO8601DateFormat.

https://github.com/thymeleaf/thymeleaf/blob/40d27f44df7b52eda47d1bc6f1b3012add6098b3/src/main/java/org/thymeleaf/standard/serializer/StandardJavaScriptSerializer.java

ECMAScript 날짜 형식 호환을 위해 사용했습니다.


-1

기본 기능 제공 : @wrygiel.

이 기능은 ISO8601 형식을 오프셋 값을 처리 할 수있는 Java Date로 변환 할 수 있습니다. ISO 8601정의에 따라 오프셋은 다른 형식으로 언급 될 수 있습니다.

±[hh]:[mm]
±[hh][mm]
±[hh]

Eg:  "18:30Z", "22:30+04", "1130-0700", and "15:00-03:30" all mean the same time. - 06:30PM UTC

이 클래스에는 변환 할 정적 메소드가 있습니다.

  • ISO8601 문자열을 Date (Local TimeZone) 객체로
  • ISO8601 문자열 날짜
  • 일광 절약 시간이 자동으로 계산됩니다

샘플 ISO8601 문자열

/*       "2013-06-25T14:00:00Z";
         "2013-06-25T140000Z";
         "2013-06-25T14:00:00+04";
         "2013-06-25T14:00:00+0400";
         "2013-06-25T140000+0400";
         "2013-06-25T14:00:00-04";
         "2013-06-25T14:00:00-0400";
         "2013-06-25T140000-0400";*/


public class ISO8601DateFormatter {

private static final DateFormat DATE_FORMAT_1 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
private static final DateFormat DATE_FORMAT_2 = new SimpleDateFormat("yyyy-MM-dd'T'HHmmssZ");
private static final String UTC_PLUS = "+";
private static final String UTC_MINUS = "-";

public static Date toDate(String iso8601string) throws ParseException {
    iso8601string = iso8601string.trim();
    if(iso8601string.toUpperCase().indexOf("Z")>0){
        iso8601string = iso8601string.toUpperCase().replace("Z", "+0000");
    }else if(((iso8601string.indexOf(UTC_PLUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_PLUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_PLUS), UTC_PLUS);
    }else if(((iso8601string.indexOf(UTC_MINUS))>0)){
        iso8601string = replaceColon(iso8601string, iso8601string.indexOf(UTC_MINUS));
        iso8601string = appendZeros(iso8601string, iso8601string.indexOf(UTC_MINUS), UTC_MINUS);
    }

    Date date = null;
    if(iso8601string.contains(":"))
        date = DATE_FORMAT_1.parse(iso8601string);
    else{
        date = DATE_FORMAT_2.parse(iso8601string);
    }
    return date;
}

public static String toISO8601String(Date date){
    return DATE_FORMAT_1.format(date);
}

private static String replaceColon(String sourceStr, int offsetIndex){
    if(sourceStr.substring(offsetIndex).contains(":"))
        return sourceStr.substring(0, offsetIndex) + sourceStr.substring(offsetIndex).replace(":", "");
    return sourceStr;
}

private static String appendZeros(String sourceStr, int offsetIndex, String offsetChar){
    if((sourceStr.length()-1)-sourceStr.indexOf(offsetChar,offsetIndex)<=2)
        return sourceStr + "00";
    return sourceStr;
}

}


2
조심하십시오-DateFormat과 파생 클래스는 멀티 스레드와 호환되지 않습니다! DATE_FORMAT_1 및 DATE_FORMAT_2와 같은 정적 SimpleDateFormat 객체를 사용하면 ISO8601DateFormatter 함수를 호출하는 여러 스레드가 동일한 DateFormat 객체를 공유하게됩니다. 이로 인해 데이터가 손상되고 DateFormat 호출에서 잘못된 날짜가 반환됩니다. 이 문제를 해결하려면 패턴 문자열을 상수로 만들고 필요할 때마다 로컬 SimpleDateFormat 변수를 만들어야합니다. 이렇게하면 각 객체가 하나의 스레드에서만 사용됩니다.
Theo

스레드 안전을위한 더 나은 수정은 스레드 안전을 위해 작성된 날짜-시간 라이브러리를 대신 사용하는 것입니다. Java에서 해당 세계는 Joda-Time 또는 java.time입니다.
Basil Bourque

-1

이것은 나에게 가장 잘 작동하는 것 같습니다.

public static Date fromISO8601_( String string ) {

    try {
            return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ssXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid ISO8601", e);
    }


}

JavaScript 날짜 문자열을 Java로 변환해야합니다. 위의 작업이 권장 사항과 일치한다는 것을 알았습니다. 가까운 SimpleDateFormat을 사용하는 몇 가지 예가 있었지만 다음과 같이 권장되는 하위 집합이 아닌 것 같습니다.

http://www.w3.org/TR/NOTE-datetime

PLIST 및 JavaScript Strings에서 지원되며 필요한 것입니다.

이것은 ISO8601 문자열의 가장 일반적인 형태이며 좋은 하위 세트 인 것 같습니다.

그들이주는 예는 다음과 같습니다.

1994-11-05T08:15:30-05:00 corresponds 
November 5, 1994, 8:15:30 am, US Eastern Standard Time.

 1994-11-05T13:15:30Z corresponds to the same instant.

또한 빠른 버전이 있습니다.

final static int SHORT_ISO_8601_TIME_LENGTH =  "1994-11-05T08:15:30Z".length ();
                                            // 01234567890123456789012
final static int LONG_ISO_8601_TIME_LENGTH = "1994-11-05T08:15:30-05:00".length ();


public static Date fromISO8601( String string ) {
    if (isISO8601 ( string )) {
        char [] charArray = Reflection.toCharArray ( string );//uses unsafe or string.toCharArray if unsafe is not available
        int year = CharScanner.parseIntFromTo ( charArray, 0, 4 );
        int month = CharScanner.parseIntFromTo ( charArray, 5, 7 );
        int day = CharScanner.parseIntFromTo ( charArray, 8, 10 );
        int hour = CharScanner.parseIntFromTo ( charArray, 11, 13 );

        int minute = CharScanner.parseIntFromTo ( charArray, 14, 16 );

        int second = CharScanner.parseIntFromTo ( charArray, 17, 19 );

        TimeZone tz ;

         if (charArray[19] == 'Z') {

             tz = TimeZone.getTimeZone ( "GMT" );
         } else {

             StringBuilder builder = new StringBuilder ( 9 );
             builder.append ( "GMT" );
             builder.append( charArray, 19, LONG_ISO_8601_TIME_LENGTH - 19);
             String tzStr = builder.toString ();
             tz = TimeZone.getTimeZone ( tzStr ) ;

         }
         return toDate ( tz, year, month, day, hour, minute, second );

    }   else {
        return null;
    }

}

...

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}


public static boolean isISO8601( String string ) {
      boolean valid = true;

      if (string.length () == SHORT_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == 'Z');

      } else if (string.length () == LONG_ISO_8601_TIME_LENGTH) {
          valid &=  (string.charAt ( 19 )  == '-' || string.charAt ( 19 )  == '+');
          valid &=  (string.charAt ( 22 )  == ':');

      } else {
          return false;
      }

    //  0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4
    // "1 9 9 4 - 1 1 - 0 5 T 0 8 : 1 5 : 3 0 - 0 5 : 0 0

    valid &=  (string.charAt ( 4 )  == '-') &&
                (string.charAt ( 7 )  == '-') &&
                (string.charAt ( 10 ) == 'T') &&
                (string.charAt ( 13 ) == ':') &&
                (string.charAt ( 16 ) == ':');

    return valid;
}

나는 그것을 벤치마킹하지는 않았지만 꽤 빠를 것이라고 생각한다. 작동하는 것 같습니다. :)

@Test
public void testIsoShortDate() {
    String test =  "1994-11-05T08:15:30Z";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}

@Test
public void testIsoLongDate() {
    String test =  "1994-11-05T08:11:22-05:00";

    Date date = Dates.fromISO8601 ( test );
    Date date2 = Dates.fromISO8601_ ( test );

    assertEquals(date2.toString (), date.toString ());

    puts (date);
}

-2

많은 사람들이 원하는 것은 JSON 날짜 문자열을 구문 분석하는 것입니다. 이 페이지를 방문하면 JavaScript JSON 날짜를 Java 날짜로 변환 할 수 있습니다.

JSON 날짜 문자열의 모양을 표시하려면 다음을 수행하십시오.

    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)

JSON 날짜 문자열은 2013-12-14T01 : 55 : 33.412Z입니다.

날짜는 JSON 사양으로 다루지 않지만 위의 내용은 매우 구체적인 ISO 8601 형식이지만 ISO_8601은 훨씬 더 크며 매우 중요한 부분이지만 단순한 하위 집합입니다.

참조 http://www.json.org 참조 http://en.wikipedia.org/wiki/ISO_8601 참조 http://www.w3.org/TR/NOTE-datetime을

그것이 일어날 때 JSON 파서와 PLIST 파서는 둘 다 ISO-8601을 사용하지만 같은 비트는 사용하지 않았습니다.

/*
    var d=new Date();
    var s = JSON.stringify(d);

    document.write(s);
    document.write("<br />"+d);


    "2013-12-14T01:55:33.412Z"
    Fri Dec 13 2013 17:55:33 GMT-0800 (PST)


 */
@Test
public void jsonJavaScriptDate() {
    String test =  "2013-12-14T01:55:33.412Z";

    Date date = Dates.fromJsonDate ( test );
    Date date2 = Dates.fromJsonDate_ ( test );

    assertEquals(date2.toString (), "" + date);

    puts (date);
}

내 프로젝트 에서이 작업을 수행하는 두 가지 방법을 썼습니다. 하나의 표준, 하나의 빠른.

JSON 날짜 문자열은 ISO 8601의 매우 구체적인 구현입니다 ....

(다른 답변을 다른 답변에 게시하여 다른 ISO 8601 형식의 PLIST 날짜에 작동해야합니다).

JSON 날짜는 다음과 같습니다.

public static Date fromJsonDate_( String string ) {

    try {

        return new SimpleDateFormat ( "yyyy-MM-dd'T'HH:mm:ss.SSSXXX").parse ( string );
    } catch ( ParseException e ) {
        return Exceptions.handle (Date.class, "Not a valid JSON date", e);
    }


}

PLIST 파일 (ASCII non GNUNext)도 ISO 8601을 사용하지만 밀리 초는 사용하지 않으므로 ISO-8601 날짜가 모두 같은 것은 아닙니다. (적어도 나는 아직 milis를 사용하는 것을 찾지 못했고 파서는 시간대를 완전히 건너 뛰었습니다.)

이제 빠른 버전 (Boon에서 찾을 수 있음)이 있습니다.

public static Date fromJsonDate( String string ) {

    return fromJsonDate ( Reflection.toCharArray ( string ), 0, string.length () );

}

Reflection.toCharArray는 사용 가능한 경우 안전하지 않지만 기본값은 string.toCharArray입니다.

Reflection.toCharArray (string)를 string.toCharArray ()로 바꾸면 예제에서 벗어날 수 있습니다.

public static Date fromJsonDate( char[] charArray, int from, int to ) {

    if (isJsonDate ( charArray, from, to )) {
        int year = CharScanner.parseIntFromTo ( charArray, from + 0, from + 4 );
        int month = CharScanner.parseIntFromTo ( charArray,  from +5,  from +7 );
        int day = CharScanner.parseIntFromTo ( charArray,  from +8,  from +10 );
        int hour = CharScanner.parseIntFromTo ( charArray,  from +11,  from +13 );

        int minute = CharScanner.parseIntFromTo ( charArray,  from +14,  from +16 );

        int second = CharScanner.parseIntFromTo ( charArray,  from +17,  from +19 );

        int miliseconds = CharScanner.parseIntFromTo ( charArray,  from +20,  from +23 );

        TimeZone tz = TimeZone.getTimeZone ( "GMT" );


        return toDate ( tz, year, month, day, hour, minute, second, miliseconds );

    }   else {
        return null;
    }

}

isJsonDate는 다음과 같이 구현됩니다.

public static boolean isJsonDate( char[] charArray, int start, int to ) {
    boolean valid = true;
    final int length = to -start;

    if (length != JSON_TIME_LENGTH) {
        return false;
    }

    valid &=  (charArray [ start + 19 ]  == '.');

    if (!valid) {
        return false;
    }


    valid &=  (charArray[  start +4 ]  == '-') &&
            (charArray[  start +7 ]  == '-') &&
            (charArray[  start +10 ] == 'T') &&
            (charArray[  start +13 ] == ':') &&
            (charArray[  start +16 ] == ':');

    return valid;
}

어쨌든 ... 내 생각에 여기에 오는 사람들은 JSON 날짜 문자열을 찾고있을 것입니다 .ISO-8601 날짜이지만 매우 구체적인 구문 분석이 필요한 매우 구체적인 날짜입니다.

public static int parseIntFromTo ( char[] digitChars, int offset, int to ) {
    int num = digitChars[ offset ] - '0';
    if ( ++offset < to ) {
        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
        if ( ++offset < to ) {
            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
            if ( ++offset < to ) {
                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                if ( ++offset < to ) {
                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                    if ( ++offset < to ) {
                        num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                        if ( ++offset < to ) {
                            num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                            if ( ++offset < to ) {
                                num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                if ( ++offset < to ) {
                                    num = ( num * 10 ) + ( digitChars[ offset ] - '0' );
                                }
                            }
                        }
                    }
                }
            }
        }
    }
    return num;
}

https://github.com/RichardHightower/boon을 참조 하십시오. Boon에는 PLIST 파서 (ASCII)와 JSON 파서가 있습니다.

JSON 파서는 내가 아는 가장 빠른 Java JSON 파서입니다.

개틀링 퍼포먼스 친구들에 의해 독립적으로 검증되었습니다.

https://github.com/gatling/json-parsers-benchmark

Benchmark                               Mode Thr     Count  Sec         Mean   Mean error        Units
BoonCharArrayBenchmark.roundRobin      thrpt  16        10    1   724815,875    54339,825    ops/s
JacksonObjectBenchmark.roundRobin      thrpt  16        10    1   580014,875   145097,700    ops/s
JsonSmartBytesBenchmark.roundRobin     thrpt  16        10    1   575548,435    64202,618    ops/s
JsonSmartStringBenchmark.roundRobin    thrpt  16        10    1   541212,220    45144,815    ops/s
GSONStringBenchmark.roundRobin         thrpt  16        10    1   522947,175    65572,427    ops/s
BoonDirectBytesBenchmark.roundRobin    thrpt  16        10    1   521528,912    41366,197    ops/s
JacksonASTBenchmark.roundRobin         thrpt  16        10    1   512564,205   300704,545    ops/s
GSONReaderBenchmark.roundRobin         thrpt  16        10    1   446322,220    41327,496    ops/s
JsonSmartStreamBenchmark.roundRobin    thrpt  16        10    1   276399,298   130055,340    ops/s
JsonSmartReaderBenchmark.roundRobin    thrpt  16        10    1    86789,825    17690,031    ops/s

스트림, 리더, bytes [], char [], CharSequence (StringBuilder, CharacterBuffer) 및 String에 대해 가장 빠른 JSON 구문 분석기가 있습니다.

더 많은 벤치 마크보기 :

https://github.com/RichardHightower/json-parsers-benchmark


JSON에 대한이 답변은 질문에서 주제를 벗어났습니다. 또한 JSON 데이터 유형 중 "JSON 날짜"와 같은 것이 없기 때문에이 질문은 잘못되었습니다 . 그리고 오늘날,이 모든 코드는 내장 Java 기능에 대한 단일 라인 호출로 대체 될 수 있습니다.Instant.parse( "2013-12-14T01:55:33.412Z" )
Basil Bourque
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.