从字符串创建 Joda 日期时间 UTC
Create Joda datetime UTC from String
我有以下 String
我想更改为 UTC:
Thu Aug 24 07:38:32 GMT+01:00 2017
我正在使用 Joda-Time 库。
我知道如何创建一个新的 Datetime
例如 new dateTime(DateTimeZone.UTC)
但是我如何从上面的 String
创建一个 DateTime
对象?
我尝试了以下但出现异常。当然必须有另一种方法来创建 DT 对象而不砍掉原来的 String
吗?如果外部 API 改变了它向我的应用程序发送原始 String
的方式,我的 String
操作代码将会失败。
DateTimeFormatter df = DateTimeFormat.forPattern("dd-MMM-YYYY HH:mm");
String strOrigTime = "Thu Aug 24 07:38:32 GMT+01:00 2017";
DateTime dt = DateTime.parse(strOrigTime, df);
Log.e(TAG, "dt after parse = " + dt.toString());
错误:
Caused by: java.lang.IllegalArgumentException: Invalid format: "Thu Aug 24 07:38:32 GMT+01:00 2017"
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:866)
at org.joda.time.DateTime.parse(DateTime.java:144)
使用的格式(dd-MMM-YYYY HH:mm
)表示:日(dd
)后跟-
,后跟月(MMM
),后跟-
,然后是年份 (YYYY
) 等等(check the javadoc 了解更多详情)。
此格式与输入字符串不匹配(星期几后跟月份,后跟日,然后是 hour/minute/second,等等)。所以第一件事是使用与输入匹配的格式,否则你总是会得到 "Invalid format" 错误。
另一个细节是星期几和月份名称是英文的,因此您还必须使用 java.util.Locale
来指定您用来解析输入的语言。如果您不使用区域设置,将使用系统默认设置,并且不能保证它始终是英语(并且它也可以更改,即使在运行时,所以最好指定一个)。
我还必须添加 "GMT" 作为文字并调用 withOffsetParsed()
以使其在解析的对象中包含偏移量 (+01:00
):
DateTimeFormatter df = DateTimeFormat
// use a pattern that matches input
.forPattern("EEE MMM dd HH:mm:ss 'GMT'Z yyyy")
// use English locale for day of week and month
.withLocale(Locale.ENGLISH)
// include the offset (+01:00) in the parsed object
.withOffsetParsed();
String strOrigTime = "Thu Aug 24 07:38:32 GMT+01:00 2017";
DateTime dt = DateTime.parse(strOrigTime, df);
System.out.println(dt.toString());
输出为:
2017-08-24T07:38:32.000+01:00
然后,您可以为这个对象设置UTC时区:
dt = dt.withZone(DateTimeZone.UTC);
System.out.println(dt.toString());
输出将是:
2017-08-24T06:38:32.000Z
请注意,withZone
方法保留了相同的时刻(两个日期代表相同的时间点),只是输出中使用的时区发生了变化。但是两个日期是等效的(它们代表相同的时刻,因为偏移量 +01:00 中的 07:38 与 UTC 中的 06:38 相同)。
如果您希望所有日期都转换为UTC,您也可以在格式化程序中设置:
// set UTC to the formatter
df = df.withZone(DateTimeZone.UTC);
那么你不需要在 DateTime
对象中调用 withZone
:所有解析的日期都将转换为 UTC。
你也说过"if the external API changes how it sends my app the orignal String
, my String
manipulation code would fail".
好吧,如果输入 String
发生变化,您也必须更改格式 - 没有其他办法,Joda-Time 不能只猜测格式是什么,您必须告诉它.
如果你想解析不止一种格式,有一种方法可以创建一个使用许多不同模式的格式化程序,并尝试解析每一个,直到其中一个有效(或者抛出异常,如果 none作品)。你可以这样做:
// format 1
DateTimeFormatter f1 = DateTimeFormat
// use a pattern that matches input
.forPattern("EEE MMM dd HH:mm:ss 'GMT'Z yyyy")
// use English locale for day of week and month
.withLocale(Locale.ENGLISH)
// include the offset (+01:00) in the parsed object
.withOffsetParsed();
// format 2
DateTimeFormatter f2 = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss Z");
// array of all possible formats
DateTimeParser[] parsers = { f1.getParser(), f2.getParser() };
// formatter that uses all the possible formats
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// append array of possible formats
.append(null, parsers)
// create formatter
.toFormatter().withLocale(Locale.ENGLISH).withOffsetParsed()
// set all parsed objects to UTC
.withZone(DateTimeZone.UTC);
// parse first format
System.out.println(DateTime.parse("Thu Aug 24 07:38:32 GMT+01:00 2017", formatter));
// parse second format
System.out.println(DateTime.parse("24/08/2017 07:38:32 +01:00", formatter));
两个日期都将被解析为:
2017-08-24T06:38:32.000Z
然后您可以根据需要向数组添加新格式。
Java新Date/TimeAPI
Joda-Time 处于维护模式,正在被新的 APIs 取代,所以我不建议用它开始一个新项目。即使在 joda's website 它说:"Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".
如果您不能(或不想)从 Joda-Time 迁移到新的 API,您可以忽略此部分。
如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it ).
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes 和方法 names 相同。
解析输入的代码非常相似,格式略有变化。
我正在使用 Instant
class,因为你想要 UTC 的输出,而 Instant
代表一个 UTC 时刻:
// format 1
DateTimeFormatter f1 = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O yyyy", Locale.ENGLISH);
// format 2
DateTimeFormatter f2 = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss XXX");
// formatter with both formats
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// add format 1
.appendOptional(f1)
// add format 2
.appendOptional(f2)
// create formatter
.toFormatter(Locale.ENGLISH);
// parse first format
System.out.println(Instant.from(formatter.parse("Thu Aug 24 07:38:32 GMT+01:00 2017")));
// parse second format
System.out.println(Instant.from(formatter.parse("24/08/2017 07:38:32 +01:00")));
这将输出:
2017-08-24T06:38:32Z
2017-08-24T06:38:32Z
我有以下 String
我想更改为 UTC:
Thu Aug 24 07:38:32 GMT+01:00 2017
我正在使用 Joda-Time 库。
我知道如何创建一个新的 Datetime
例如 new dateTime(DateTimeZone.UTC)
但是我如何从上面的 String
创建一个 DateTime
对象?
我尝试了以下但出现异常。当然必须有另一种方法来创建 DT 对象而不砍掉原来的 String
吗?如果外部 API 改变了它向我的应用程序发送原始 String
的方式,我的 String
操作代码将会失败。
DateTimeFormatter df = DateTimeFormat.forPattern("dd-MMM-YYYY HH:mm");
String strOrigTime = "Thu Aug 24 07:38:32 GMT+01:00 2017";
DateTime dt = DateTime.parse(strOrigTime, df);
Log.e(TAG, "dt after parse = " + dt.toString());
错误:
Caused by: java.lang.IllegalArgumentException: Invalid format: "Thu Aug 24 07:38:32 GMT+01:00 2017"
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:866)
at org.joda.time.DateTime.parse(DateTime.java:144)
使用的格式(dd-MMM-YYYY HH:mm
)表示:日(dd
)后跟-
,后跟月(MMM
),后跟-
,然后是年份 (YYYY
) 等等(check the javadoc 了解更多详情)。
此格式与输入字符串不匹配(星期几后跟月份,后跟日,然后是 hour/minute/second,等等)。所以第一件事是使用与输入匹配的格式,否则你总是会得到 "Invalid format" 错误。
另一个细节是星期几和月份名称是英文的,因此您还必须使用 java.util.Locale
来指定您用来解析输入的语言。如果您不使用区域设置,将使用系统默认设置,并且不能保证它始终是英语(并且它也可以更改,即使在运行时,所以最好指定一个)。
我还必须添加 "GMT" 作为文字并调用 withOffsetParsed()
以使其在解析的对象中包含偏移量 (+01:00
):
DateTimeFormatter df = DateTimeFormat
// use a pattern that matches input
.forPattern("EEE MMM dd HH:mm:ss 'GMT'Z yyyy")
// use English locale for day of week and month
.withLocale(Locale.ENGLISH)
// include the offset (+01:00) in the parsed object
.withOffsetParsed();
String strOrigTime = "Thu Aug 24 07:38:32 GMT+01:00 2017";
DateTime dt = DateTime.parse(strOrigTime, df);
System.out.println(dt.toString());
输出为:
2017-08-24T07:38:32.000+01:00
然后,您可以为这个对象设置UTC时区:
dt = dt.withZone(DateTimeZone.UTC);
System.out.println(dt.toString());
输出将是:
2017-08-24T06:38:32.000Z
请注意,withZone
方法保留了相同的时刻(两个日期代表相同的时间点),只是输出中使用的时区发生了变化。但是两个日期是等效的(它们代表相同的时刻,因为偏移量 +01:00 中的 07:38 与 UTC 中的 06:38 相同)。
如果您希望所有日期都转换为UTC,您也可以在格式化程序中设置:
// set UTC to the formatter
df = df.withZone(DateTimeZone.UTC);
那么你不需要在 DateTime
对象中调用 withZone
:所有解析的日期都将转换为 UTC。
你也说过"if the external API changes how it sends my app the orignal String
, my String
manipulation code would fail".
好吧,如果输入 String
发生变化,您也必须更改格式 - 没有其他办法,Joda-Time 不能只猜测格式是什么,您必须告诉它.
如果你想解析不止一种格式,有一种方法可以创建一个使用许多不同模式的格式化程序,并尝试解析每一个,直到其中一个有效(或者抛出异常,如果 none作品)。你可以这样做:
// format 1
DateTimeFormatter f1 = DateTimeFormat
// use a pattern that matches input
.forPattern("EEE MMM dd HH:mm:ss 'GMT'Z yyyy")
// use English locale for day of week and month
.withLocale(Locale.ENGLISH)
// include the offset (+01:00) in the parsed object
.withOffsetParsed();
// format 2
DateTimeFormatter f2 = DateTimeFormat.forPattern("dd/MM/yyyy HH:mm:ss Z");
// array of all possible formats
DateTimeParser[] parsers = { f1.getParser(), f2.getParser() };
// formatter that uses all the possible formats
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// append array of possible formats
.append(null, parsers)
// create formatter
.toFormatter().withLocale(Locale.ENGLISH).withOffsetParsed()
// set all parsed objects to UTC
.withZone(DateTimeZone.UTC);
// parse first format
System.out.println(DateTime.parse("Thu Aug 24 07:38:32 GMT+01:00 2017", formatter));
// parse second format
System.out.println(DateTime.parse("24/08/2017 07:38:32 +01:00", formatter));
两个日期都将被解析为:
2017-08-24T06:38:32.000Z
然后您可以根据需要向数组添加新格式。
Java新Date/TimeAPI
Joda-Time 处于维护模式,正在被新的 APIs 取代,所以我不建议用它开始一个新项目。即使在 joda's website 它说:"Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to java.time (JSR-310).".
如果您不能(或不想)从 Joda-Time 迁移到新的 API,您可以忽略此部分。
如果您正在使用 Java 8,请考虑使用 new java.time API. It's easier, less bugged and less error-prone than the old APIs.
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes 和方法 names 相同。
解析输入的代码非常相似,格式略有变化。
我正在使用 Instant
class,因为你想要 UTC 的输出,而 Instant
代表一个 UTC 时刻:
// format 1
DateTimeFormatter f1 = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O yyyy", Locale.ENGLISH);
// format 2
DateTimeFormatter f2 = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss XXX");
// formatter with both formats
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
// add format 1
.appendOptional(f1)
// add format 2
.appendOptional(f2)
// create formatter
.toFormatter(Locale.ENGLISH);
// parse first format
System.out.println(Instant.from(formatter.parse("Thu Aug 24 07:38:32 GMT+01:00 2017")));
// parse second format
System.out.println(Instant.from(formatter.parse("24/08/2017 07:38:32 +01:00")));
这将输出:
2017-08-24T06:38:32Z
2017-08-24T06:38:32Z