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

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" ) ;

나에게 이것은 좋다.



답변

불행히도 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 을 사용할 수도 있지만 왜 그렇게 신경 써야할지 모르겠습니다.


답변

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에서이를 수행 하는 완전히 새로운 방법 이 있습니다


답변

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

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을 사용하여 개인 정적 필드에 인스턴스를 캐시 할 수 있습니다.


답변

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 );


답변

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

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


답변

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, 그리고 .



답변

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);