Ice*_*e09 627 java date iso8601
我试图将ISO 8601格式的字符串转换为java.util.Date
.
yyyy-MM-dd'T'HH:mm:ssZ
如果与Locale(比较样本)一起使用,我发现该模式符合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));
Run Code Online (Sandbox Code Playgroud)
这显然不是那么好.我错过了什么或者有更好的解决方案吗?
回答
感谢JuanZe的评论,我发现了Joda-Time魔术,这里也有描述.
所以,解决方案是
DateTimeFormatter parser2 = ISODateTimeFormat.dateTimeNoMillis();
String jtdate = "2010-01-01T12:00:00+01:00";
System.out.println(parser2.parseDateTime(jtdate));
Run Code Online (Sandbox Code Playgroud)
或者更简单地说,通过构造函数使用默认解析器:
DateTime dt = new DateTime( "2010-01-01T12:00:00+01:00" ) ;
Run Code Online (Sandbox Code Playgroud)
对我来说,这很好.
jar*_*bjo 451
不幸的是,SimpleDateFormat(Java 6及更早版本)可用的时区格式不符合ISO 8601.SimpleDateFormat理解时区字符串,如"GMT + 01:00"或"+0100",后者根据RFC#822.
即使Java 7根据ISO 8601添加了对时区描述符的支持,SimpleDateFormat仍然无法正确解析完整的日期字符串,因为它不支持可选部分.
使用regexp重新格式化输入字符串当然是一种可能,但替换规则并不像您的问题那么简单:
更简单的解决方案是在JAXB中使用数据类型转换器,因为JAXB必须能够根据XML Schema规范解析ISO8601日期字符串.如果你需要一个对象,它javax.xml.bind.DatatypeConverter.parseDateTime("2010-01-01T12:00:00Z")
会给你一个Calendar
对象,你可以简单地在它上面使用getTime()Date
.
你也许可以使用Joda-Time,但我不知道为什么你应该为此烦恼.
Ant*_*nio 220
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);
Run Code Online (Sandbox Code Playgroud)
你可以找到部分更多的例子例子在SimpleDateFormat的Javadoc中.
wry*_*iel 200
好的,这个问题已经回答了,但无论如何我都会放弃我的答案.它可能对某人有帮助.
我一直在寻找Android(API 7)的解决方案.
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;
}
}
Run Code Online (Sandbox Code Playgroud)
性能说明:我每次都会实例化新的SimpleDateFormat,以避免Android 2.1中的错误.如果你像我一样惊讶,看到这个谜语.对于其他Java引擎,您可以将实例缓存在私有静态字段中(使用ThreadLocal,以保证线程安全).
Ada*_*dam 100
该java.time API(Java中内嵌的8和更高版本),使这是一个更容易一些.
如果您知道输入是UTC格式的,例如Z
末尾的(对于Zulu),则Instant
类可以解析.
java.util.Date date = Date.from( Instant.parse( "2014-12-12T10:39:40Z" ));
Run Code Online (Sandbox Code Playgroud)
如果您的输入可能是另一个与UTC相关的偏移值而不是最后由(Zulu)指示的UTCZ
,请使用OffsetDateTime
该类进行解析.
OffsetDateTime odt = OffsetDateTime.parse( "2010-01-01T12:00:00+01:00" );
Run Code Online (Sandbox Code Playgroud)
然后提取一个Instant
,并java.util.Date
通过调用转换为a from
.
Instant instant = odt.toInstant(); // Instant is always in UTC.
java.util.Date date = java.util.Date.from( instant );
Run Code Online (Sandbox Code Playgroud)
dav*_*d_p 67
在杰克逊-数据绑定库也有ISO8601DateFormat类是确实在(实际执行ISO8601Utils.
ISO8601DateFormat df = new ISO8601DateFormat();
Date d = df.parse("2010-07-28T22:25:51Z");
Run Code Online (Sandbox Code Playgroud)
Bas*_*que 47
OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" )
Run Code Online (Sandbox Code Playgroud)
Java 8及更高版本中的新java.time包受Joda-Time的启发.
该OffsetDateTime
级代表以时间轴上的时刻偏移从-UTC而不是一个时区.
OffsetDateTime odt = OffsetDateTime.parse ( "2010-01-01T12:00:00+01:00" );
Run Code Online (Sandbox Code Playgroud)
调用toString
生成标准ISO 8601格式的字符串:
2010-01-01T12:00 + 01:00
看穿UTC的透镜相同的值,提取Instant
或调整从偏移+01:00
到00:00
.
Instant instant = odt.toInstant();
Run Code Online (Sandbox Code Playgroud)
…要么…
OffsetDateTime odtUtc = odt.withOffsetSameInstant( ZoneOffset.UTC );
Run Code Online (Sandbox Code Playgroud)
如果需要,调整到时区.一个时区是历史的偏移,从-UTC值的区域,拥有一套用于处理异常,如夏令时(DST)规则.因此,应尽可能应用时区而不是仅仅偏移.
ZonedDateTime zonedDateTimeMontréal = odt.atZoneSameInstant( ZoneId.of( "America/Montreal" ) );
Run Code Online (Sandbox Code Playgroud)
该java.time框架是建立在Java 8和更高版本.这些类取代麻烦的老传统日期时间类,如java.util.Date
,Calendar
,和SimpleDateFormat
.
现在处于维护模式的Joda-Time项目建议迁移到java.time类.
要了解更多信息,请参阅Oracle教程.并搜索Stack Overflow以获取许多示例和解释.规范是JSR 310.
您可以直接与数据库交换java.time对象.使用符合JDBC 4.2或更高版本的JDBC驱动程序.不需要字符串,不需要课程.java.sql.*
从哪里获取java.time类?
该ThreeTen-额外项目与其他类扩展java.time.该项目是未来可能添加到java.time的试验场.您可以在此比如找到一些有用的类Interval
,YearWeek
,YearQuarter
,和更多.
Ant*_*nio 47
从 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);
Run Code Online (Sandbox Code Playgroud)
d.d*_*lov 27
对于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);
Run Code Online (Sandbox Code Playgroud)
Jam*_*ven 20
DatatypeConverter解决方案不适用于所有VM.以下适用于我:
javax.xml.datatype.DatatypeFactory.newInstance().newXMLGregorianCalendar("2011-01-01Z").toGregorianCalendar().getTime()
Run Code Online (Sandbox Code Playgroud)
我发现joda不能开箱即用(特别是我上面给出的带有时区的例子,这应该是有效的)
小智 16
我认为我们应该使用
DateFormat format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
Run Code Online (Sandbox Code Playgroud)
对于日期 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());
}
}
Run Code Online (Sandbox Code Playgroud)
Java 8+
我在答案中没有找到的简单的衬里:
Date date = Date.from(ZonedDateTime.parse("2010-01-01T12:00:00+01:00").toInstant());
Run Code Online (Sandbox Code Playgroud)
日期不包含时区,它将存储在 UTC 中,但即使在简单输出期间也会正确转换为您的 JVM 时区System.out.println(date)
。
在我搜索了很多将 ISO8601 转换为最新版本后,我突然发现了一个 Java 类,它是ISO8601Util.java,它是com.google.gson.internal.bind.util 的一部分。所以你可以用它来转换日期。
ISO8601Utils.parse("2010-01-01T12:00:00Z" , ParsePosition(0))
Run Code Online (Sandbox Code Playgroud)
你可以简单地使用这个 kotlin 扩展功能
fun String.getDateFromString() : Date? = ISO8601Utils.parse(this ,
ParsePosition(0))
Run Code Online (Sandbox Code Playgroud)
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);
}
}
Run Code Online (Sandbox Code Playgroud)
上面的方法在Java 6中发生错误时替换[ Z
with +0000
]或[ +01:00
with +0100
](您可以检测Java版本并用if语句替换try/catch).
小智 5
您也可以使用以下课程 -
org.springframework.extensions.surf.util.ISO8601DateFormat
Date date = ISO8601DateFormat.parse("date in iso8601");
Run Code Online (Sandbox Code Playgroud)
链接到 Java 文档 -包的层次结构 org.springframework.extensions.surf.maven.plugin.util
我遇到了同样的问题并通过以下代码解决了它。
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;
}
Run Code Online (Sandbox Code Playgroud)
早些时候我正在使用
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());
它对我来说很好。
Java 有十几种不同的方法来解析日期时间,正如这里的优秀答案所展示的那样。但有点令人惊讶的是,Java 的时间类都没有完全实现 ISO 8601!
使用 Java 8,我建议:
ZonedDateTime zp = ZonedDateTime.parse(string);
Date date = Date.from(zp.toInstant());
Run Code Online (Sandbox Code Playgroud)
这将处理 UTC 和偏移量的示例,例如“2017-09-13T10:36:40Z”或“2017-09-13T10:36:40+01:00”。它适用于大多数用例。
但它不会处理像“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/我不知道任何可以处理所有这些的 Java 类。
从 Java 12 开始,Instant#parse
可以解析包含时区偏移的日期时间字符串。
Date dt = Date.from(Instant.parse(your-date-time-string));
Run Code Online (Sandbox Code Playgroud)
使用解析ISO 8601格式的日期时间字符串Instant#parse
,并将结果转换为java.util.Date
使用Date#from
. 请参阅在 Ideone.com 上运行的此代码。
演示:
import java.time.Instant;
import java.util.Date;
import java.util.stream.Stream;
public class Main {
public static void main(String[] args) {
Stream.of(
"2010-01-01T12:00:00+01:00",
"2010-01-01T12:00:00-01:00",
"2010-01-01T12:00:00Z"
)
.map(Instant::parse)
.map(Date::from)
.forEach(System.out::println);
}
}
Run Code Online (Sandbox Code Playgroud)
从Trail: Date Time中了解有关现代日期时间 API 的更多信息。
归档时间: |
|
查看次数: |
547488 次 |
最近记录: |