ISO 8601 호환 문자열을 java.util.Date로 변환
나는 변환하려고 ISO 8601 A를 포맷 문자열 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은 RFC # 822 에 따라 "GMT + 01 : 00"또는 "+0100"과 같은 시간대 문자열을 이해합니다 .
Java 7이 ISO 8601에 따라 시간대 설명자에 대한 지원을 추가 한 경우에도 SimpleDateFormat은 선택적 부분을 지원하지 않기 때문에 전체 날짜 문자열을 제대로 구문 분석 할 수 없습니다.
regexp를 사용하여 입력 문자열을 다시 형식화하는 것은 확실히 한 가지 가능성이지만 대체 규칙은 질문 에서처럼 간단하지 않습니다.
- 일부 시간대는 UTC를 제외한 전체 시간이 아니므로 문자열이 반드시 ": 00"으로 끝나는 것은 아닙니다.
- ISO8601은 시간대에 포함 할 시간 만 허용하므로 "+01"은 "+01 : 00"과 같습니다.
- ISO8601에서는 "+00 : 00"대신 UTC를 나타 내기 위해 "Z"를 사용할 수 있습니다.
더 쉬운 해결책은 JAXB에서 데이터 유형 변환기를 사용하는 것입니다. JAXB는 XML 스키마 사양에 따라 ISO8601 날짜 문자열을 구문 분석 할 수 있어야하기 때문입니다. 객체 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는 .
좋습니다.이 질문은 이미 답변되었지만 어쨌든 내 답변을 삭제하겠습니다. 누군가를 도울 수 있습니다.
Android (API 7) 용 솔루션을 찾고있었습니다 .
- Joda는 의문의 여지가 없었습니다. 크기가 크고 초기화 속도가 느립니다. 그것은 또한 그 특정 목적을위한 중대한 과잉 인 것처럼 보였습니다.
- 관련 답변은
javax.xml
Android 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 형식 이라는 것을 알고 있으면 클래스가 구문 분석 할 수 있습니다.Z
Instant
java.util.Date date = Date.from( Instant.parse( "2014-12-12T10:39:40Z" ));
입력이 끝에 (Zulu)로 표시된 UTC 가 아닌 다른 UTC 오프셋 값일 수있는 경우 클래스를 사용하여 구문 분석하십시오.Z
OffsetDateTime
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을 참조하십시오 . 그리고 많은 예제와 설명을 위해 Stack Overflow를 검색하십시오. 사양은 JSR 310 입니다.
java.time 객체를 데이터베이스와 직접 교환 할 수 있습니다 . JDBC 4.2 이상을 준수 하는 JDBC 드라이버를 사용하십시오 . 문자열이나 클래스 가 필요하지 않습니다 .java.sql.*
java.time 클래스는 어디서 구할 수 있습니까?
- 자바 SE 8 , 자바 SE 9 , 자바 SE (10) , 그리고 나중에
- 내장.
- 번들로 구현 된 표준 Java API의 일부입니다.
- Java 9에는 몇 가지 사소한 기능과 수정 사항이 추가되었습니다.
- Java SE 6 및 Java SE 7
- java.time 기능의 대부분은 ThreeTen-Backport의 Java 6 및 7로 백 포트됩니다 .
- 기계적 인조 인간
- java.time 클래스의 최신 버전의 Android 번들 구현.
- 이전 Android (<26)의 경우 ThreeTenABP 프로젝트는 ThreeTen-Backport (위에서 언급)를 채택합니다 . ThreeTenABP 사용 방법…을 참조하십시오 .
ThreeTen - 추가 프로젝트 추가 클래스와 java.time를 확장합니다. 이 프로젝트는 java.time에 향후 추가 될 수있는 가능성을 입증하는 곳입니다. 당신은 여기에 몇 가지 유용한 클래스와 같은 찾을 수 있습니다 Interval
, YearWeek
, YearQuarter
, 그리고 더 .
Java 버전 7의 경우
Oracle 문서를 따를 수 있습니다 : http://docs.oracle.com/javase/7/docs/api/java/text/SimpleDateFormat.html
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);
DatatypeConverter 솔루션은 모든 VM에서 작동하지 않습니다. 다음은 나를 위해 작동합니다.
javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime()
나는 joda가 기본적으로 작동하지 않는다는 것을 발견했습니다 (특히 내가 날짜의 시간대로 위에서 준 예제의 경우 유효해야 함)
나는 우리가 사용해야한다고 생각한다
DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
날짜 2010-01-01T12:00:00Z
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());
}
}
java.time
Java 8에서는 java.time.ZonedDateTime 클래스와 해당 정적 parse(CharSequence text)
메서드를 사용할 수 있습니다 .
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
이해하지 못하여 ISO8601 날짜를 Java 6에서 읽을 수있는 형식으로 표준화해야합니다 .X
IllegalArgumentException: Unknown pattern character 'X'
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에서 오류가 발생했을 때 [ Z
를 +0000
] 또는 [ +01:00
로 +0100
] 를 대체하는 위의 방법입니다 (Java 버전을 감지하고 try / catch를 if 문으로 대체 할 수 있음).
나는 같은 문제에 직면하고 다음 코드로 해결했습니다.
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());
그것은 나를 위해 잘 작동했습니다.
또한 다음 클래스를 사용할 수 있습니다.
org.springframework.extensions.surf.util.ISO8601DateFormat
Date date = ISO8601DateFormat.parse("date in iso8601");
Java 문서 링크 -org.springframework.extensions.surf.maven.plugin.util 패키지의 계층 구조
Apache Jackrabbit 은 날짜 유지를 위해 ISO 8601 형식을 사용하며이를 구문 분석하는 도우미 클래스가 있습니다.
org.apache.jackrabbit.util.ISO8601
jackrabbit-jcr-commons 와 함께 제공 됩니다.
다른 사람들이 언급했듯이 Android는 SDK에 포함 된 클래스를 사용하여 ISO 8601 날짜 구문 분석 / 형식 지정을 지원하는 좋은 방법이 없습니다. 이 코드를 여러 번 작성 했으므로 마침내 ISO 8601 및 RFC 1123 날짜의 형식 지정 및 구문 분석을 지원하는 DateUtils 클래스를 포함하는 Gist를 만들었습니다. Gist는 또한 그것이 지원하는 것을 보여주는 테스트 케이스를 포함합니다.
https://gist.github.com/mraccola/702330625fad8eebe7d3
JAVA 1.7 용 SimpleDateFormat에는 ISO 8601 형식에 대한 멋진 패턴이 있습니다.
내가 한 일은 다음과 같습니다.
Date d = new SimpleDateFormat( "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
Locale.ENGLISH).format(System.currentTimeMillis());
Java에는 여기에 훌륭한 답변이 보여 주듯이 날짜-시간을 구문 분석하는 12 가지 다른 방법이 있습니다. 하지만 놀랍게도 Java의 시간 클래스는 ISO 8601을 완전히 구현하지 않습니다!
Java 8에서는 다음을 권장합니다.
ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());
그러면 '2017-09-13T10 : 36 : 40Z'또는 '2017-09-13T10 : 36 : 40 + 01 : 00'과 같은 오프셋과 함께 UTC 형식의 예가 처리됩니다. 대부분의 사용 사례에 적합합니다.
그러나 같은 예를 처리하지 않습니다 "2017-09-13T10을 : 36 : 40 + 01",하는 것입니다 유효한 ISO 8601 날짜 - 시간.
또한 날짜 만 처리하지 않습니다 (예 : "2017-09-13").
이를 처리해야한다면 먼저 정규식을 사용하여 구문을 스니핑하는 것이 좋습니다.
여기에 많은 코너 케이스와 함께 ISO 8601 예제 목록이 있습니다. https://www.myintervals.com/blog/2009/05/20/iso-8601-date-validation-that-doesnt-suck/ I 'm 이들 모두를 처리 할 수있는 Java 클래스를 알지 못합니다.
다음과 같이하십시오.
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);
}
다음은 출력입니다.
2016 년 10 월 19 일 수요일 15:15:36 CST
다음과 같은 문자열 사용 LocalDate.parse(((String) data.get("d_iso8601")),DateTimeFormatter.ISO_DATE)
비슷한 요구 사항이있었습니다. 사전에 정확한 형식을 모르고 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");
도움이되기를 바랍니다.
이와 같은 날짜 형식을 지정하기 위해 Java 6 기반 응용 프로그램에서 다음이 저에게 효과적이었습니다. 누락 된 콜론을 삽입하는 thymeleaf 프로젝트 에는 DateFormat
클래스 가 있습니다 JacksonThymeleafISO8601DateFormat
.
ECMAScript 날짜 형식 호환성을 위해 사용했습니다.
https://en.wikipedia.org/wiki/ISO_8601에 따라 하나의 Java 라이브러리도 모든 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
};
}
ISO8601에서 날짜를 구문 분석하는 방법과 LocalDateTime이 DST를 처리하지 않는 방법을 보여주는 간단한 테스트입니다.
@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());
}
기본 기능 제공 : @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;
}
}
이것은 나에게 가장 잘 작동하는 것 같습니다.
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);
}
많은 사람들이 원하는 것은 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을
나는 ISO-8601을 사용하지만 동일한 비트는 사용하지 않는 JSON 파서와 PLIST 파서를 작성했습니다.
/*
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 비 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
참고 URL : https://stackoverflow.com/questions/2201925/converting-iso-8601-compliant-string-to-java-util-date
'your programing' 카테고리의 다른 글
여러 단어 경계 구분 기호를 사용하여 문자열을 단어로 분할 (0) | 2020.10.02 |
---|---|
호스트를 통해 외부에서 VirtualBox 게스트에 SSH를 사용하는 방법은 무엇입니까? (0) | 2020.10.02 |
Genymotion VM에 Google Play 서비스를 설치하는 방법 (드래그 앤 드롭 지원 없음)? (0) | 2020.10.02 |
SO_REUSEADDR과 SO_REUSEPORT는 어떻게 다릅니 까? (0) | 2020.10.02 |
Chrome 자동 완성 사용 중지 (0) | 2020.10.02 |