使用 Java 在 Android 中显示来自 BEGIN:VEVENT 原始数据的日期值

Display Date Value from BEGIN:VEVENT Raw Data in Android using Java

我是 android 开发的新手,我面临解析事件开始和结束日期以在 UI 或 activity 上显示到文本视图的问题。

这是二维码的原始数据。

BEGIN:VEVENT
SUMMARY:My Event
DESCRIPTION:This the foo event
LOCATION:Location
DTSTART:20200519T142616Z
DTEND:20200527T100000Z
END:VEVENT

我能够将原始事件日期解析为模型 class 下的各个属性。在向 UI 显示值时,我想以可读的格式显示日期。

现在我有如下格式的日期:

String startDate = "20200519T142616Z"; // - What is this Format?
String endDate = "20200527T100000Z";

问题#1什么类型的"20200519T142616Z"日期格式?

我想像这样显示日期:

Start Date: 05 May 2020 17:26:16
End Date: 27 May 2020 13:00:00

我使用了以下抛出异常的代码片段:那么我该如何解析它呢?

try {
     String property_value = "20200519T142616Z";
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:ss:mmZ");
     String startDate = sdf.parse(property_value);
}
catch (ParseException e) {
     e.printStackTrace();
}

问题#2 如何解析 "20200519T142616Z" 日期以显示格式如 2020 年 5 月 5 日 17:26:16?

请帮忙,我正在努力寻找解决方案?

问题#1“20200519T142616Z”日期格式有哪些类型?

回答:是祖鲁时代的伙伴。 “祖鲁”来自军事和航空传统,其中 25 个字母 A-Z(没有 "J"),每个字母都有一个可发音的名字,代表 their version of time zones. The "Zulu" zone is zero hours offset from UTC. For more check out link 1 and link 2.

此格式在 ISO 8601 标准中正式定义。

问题#2如何解析“20200519T142616Z”日期以显示格式如 2020 年 5 月 5 日17:26:16?

答案: T 只是一个文字,用来分隔日期和时间,Z 表示 "zero hour offset" 也称为 "Zulu time" (UTC ).如果你的字符串总是有一个 "Z" 你可以使用:

您需要将其转换为标准格式"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
    simpleDateFormat .setTimeZone(TimeZone.getTimeZone("UTC"));
    try {
        //20200519T142616Z // wrong format // this gives exception here
        /*
        * you format this string correctly 
        * after formatting your start date 
        * 2020-05-19T14:26:16.(three digit missing here)Z
        * 20200527T100000Z // wrong format 

        * 2020-05-19T14:17:46.316Z  // correct format
        * OUTPUT: E/test date: Tue May 19 05:30:00 GMT+05:30 2020
        * */
        Log.e("test date ", String.valueOf(format.parse("2020-05-19T14:26.126Z")));
    } catch (ParseException e) {
        e.printStackTrace();
    }

检查缓存异常here

你可以使用dateTime()

tl;博士

解析你的"basic"ISO 8601 string as a java.time.OffsetDateTime object. Generate localized text representing that object’s value via DateTimeFormatterclass.

OffsetDateTime
.parse( 
    "20200519T142616Z" ,
    DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssXXXXX" )
)
.format(
    DateTimeFormatter
    .ofLocalizedDateTime( FormatStyle.MEDIUM )
    .withLocale( Locale.UK )
)

看到这个 code run live at IdeOne.com

19 May 2020, 14:26:16

或者,从 UTC 调整到时区。

OffsetDateTime
.parse( 
    "20200519T142616Z" ,
    DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssXXXXX" )
)
.atZoneSameInstant(
    ZoneId.of( "Europe/Minsk" ) 
)
.format(
    DateTimeFormatter
    .ofLocalizedDateTime( FormatStyle.MEDIUM )
    .withLocale( new Locale( "ru" , "RU" ) )
)

看到这个 code run live at IdeOne.com

19 мая 2020 г., 17:26:16

请注意时间是如何从 14 点转移到 17 点的。在此示例中,时区 Europe/Minsk 比 UTC 早三个小时。所以,14 + 3 = 17。同一时刻,不同的挂钟时间。

ISO 8601“基本”变体

Question# 1 What types of "20200519T142616Z" date Format?

您的输入 "20200519T142616Z" 使用 ISO 8601 标准中定义的格式的“基本”变体进行格式化,最大限度地减少了分隔符的使用。

定义格式模式以匹配您的输入。

DateTimeFormatter f = DateTimeFormatter.ofPattern( "uuuuMMdd'T'HHmmssXXXXX" ) ;

解析为 OffsetDateTime 对象。

OffsetDateTime odt = OffsetDateTime.parse( input , f ) ;

要通过特定地区(时区)的人们使用的挂钟时间查看同一时刻,请应用 ZoneId 以获得 ZonedDateTime

ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;

生成表示该分区日期时间的本地化文本。同一时刻,时间轴上的同一点,不同的挂钟时间。

Locale locale = new Locale( "fr" , "TN" ) ;
DateTimeFormatter fOutput = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.LONG ).withLocale( locale ) ;
String output = zdt.format( fOutput ) ;
System.out.println( "output: " + output ) ;

看到这个code run live at IdeOne.com

odt.toString(): 2020-05-19T14:26:16Z

zdt.toString(): 2020-05-19T15:26:16+01:00[Africa/Tunis]

output: 19 mai 2020 à 3:26:16 PM CET

生成文本

Question# 2 How to parse "20200519T142616Z" date to display format like 05 May 2020 17:26:16?

不是"parse",而是"generate",一定是你的意思。

要生成表示日期时间对象值的文本,请使用另一个 DateTimeFormatter 对象。

不用硬编码值,让 java.time 自动本地化。

Locale locale = Locale.UK ;
DateTimeFormatter formatter = DateTimeFormatter.ofLocalizedDateTime( FormatStyle.MEDIUM ).wihLocale( locale ) ;
String output = odt.format( formatter ) ;

如果本地化文本不适合您,请按照答案前面的说明定义格式模式。这已在 Stack Overflow 上多次介绍,因此请搜索以了解更多信息。

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

您可以直接与数据库交换 java.time 对象。使用 JDBC driver compliant with JDBC 4.2 或更高版本。不需要字符串,不需要 java.sql.* classes。 Hibernate 5 和 JPA 2.2 支持 java.time

从哪里获得java.time classes?