java.text.ParseException: 无法解析的日期: “09:07:31 AM PDT”

huangapple go评论82阅读模式
英文:

java.text.ParseException: Unparseable date: "09:07:31 AM PDT"

问题

我有一个在响应中的字段,它以时间形式呈现,我想在添加一些分钟之前对其进行解析。我已经编写了下面的代码,但结果出现错误。

SimpleDateFormat df = new SimpleDateFormat("hh:mm:ss a zzz");
Date date = df.parse(currentTime);
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.MINUTE, 10);

在这里,currentTime 的值是 "09:07:31 AM PDT"。

英文:

I have a field in the response that is coming as time which I want to parse before adding some minutes into it. I have written the below code which results in error.

SimpleDateFormat df = new SimpleDateFormat("HH:MM:ss a SSS");
        Date date = df.parse(currentTime);
        Calendar cal = Calendar.getInstance();
        cal.setTime(date);
        cal.add(Calendar.MINUTE, 10);

here, currentTime is coming in as "09:07:31 AM PDT"

答案1

得分: 3

以下是代码的翻译部分:

# tl;dr

    LocalTime                                        // 表示一天中的时间,没有日期和时区或UTC偏移。
    .parse(               
        "09:07:31 AM PDT".substring(0, 11),      // 从输入中去掉无意义的“PDT”。
        DateTimeFormatter.ofPattern("hh:mm:ss a")  // 定义一个格式化模式以匹配我们修改后的输入字符串。
    )                                                // 返回一个`LocalTime`对象。
    .toString()                                      // 生成标准的ISO 8601格式的文本,表示我们的`LocalTime`对象的值。

> 09:07:31


# 避免使用 `Date``Calendar`

您正在使用最早版本的Java捆绑的可怕日期时间类这些类早在多年前就被现代的*java.time*(JSR 310定义)所取代了

永远不要使用`Date`、`Calendar`、`SimpleDateFormat`等类

# `Date` 类不适用

`java.util.Date` 类表示一个时刻即UTC时间下的日期和时间您的输入缺少日期因此您的输入不能由此类表示

# 具有时区的时间没有意义

您的输入表示一个带有虚假时区的时间。`PDT` 可能代表太平洋夏令时间”,用于指示是否正在使用夏令时(DST)这不是一个真正的时区名称应该使用类似 `America/Los_Angeles` 这样的时区名称

无论如何时间和时区的组合没有意义没有日期的上下文时区没有意义

# `LocalTime`

我建议您提取时间并忽略 `PDT`。取前11个字符

    String input = "09:07:31 AM PDT";
    String s = input.substring(0, 11); // 使用令人讨厌的从零开始的索引计数。因此,要求前11个字符需要 (0, 11)。

定义一个格式化模式以匹配我们修改后的输入字符串

    DateTimeFormatter f = DateTimeFormatter.ofPattern("hh:mm:ss a");

解析为 `LocalTime`,表示没有日期和没有时区或UTC偏移的时间

    LocalTime lt = LocalTime.parse(s, f);

> lt.toString(): 09:07:31


# `ZonedDateTime`

为了好玩让我们为您的时间应用一个时区以及一个日期以获取一个 `ZonedDateTime`。

    LocalTime lt = LocalTime.parse("01:59:00 AM PDT".substring(0, 11), DateTimeFormatter.ofPattern("hh:mm:ss a"));
    LocalDate ld = LocalDate.of(2020, Month.MARCH, 7);
    ZoneId z = ZoneId.of("America/Los_Angeles");
    ZonedDateTime zdt = ZonedDateTime.of(ld, lt, z);
    ZonedDateTime zdtLater = zdt.plusMinutes(5);
    System.out.println("zdtLater = " + zdtLater);

我们得到 2:04 AM

> zdtLater = 2020-03-07T02:04-08:00[America/Los_Angeles]

将日期更改为 8 号

    LocalTime lt = LocalTime.parse("01:59:00 AM PDT".substring(0, 11), DateTimeFormatter.ofPattern("hh:mm:ss a"));
    LocalDate ld = LocalDate.of(2020, Month.MARCH, 8);
    ZoneId z = ZoneId.of("America/Los_Angeles");
    ZonedDateTime zdt = ZonedDateTime.of(ld, lt, z);
    ZonedDateTime zdtLater = zdt.plusMinutes(5);
    System.out.println("zdtLater = " + zdtLater);

我们得到 3:04 AM而不是 2:04 AM

> zdtLater = 2020-03-08T03:04-07:00[America/Los_Angeles]

日期赋予了时区中的时间意义

偏移随时间变化这就是时区的含义时区如 `America/Los_Angeles` 是过去现在和未来在北美西海岸许多地区使用的偏移变化的历史在2020年3月7日偏移为UTC的8小时在2020年3月8日偏移更改为UTC的7小时在凌晨2点的第一刻时钟跳跃了一个小时到凌晨3点在8号与7号不同凌晨2点的那个小时没有发生
 
# `OffsetTime`

*java.time* 框架确实提供了 [`OffsetTime`][2]这表示带有UTC偏移的时间

出于上述讨论的相同原因这个类没有意义带有偏移但没有日期的时间没有任何有用的目的我假设这只是为了匹配SQL标准类型 `TIME WITH TIME ZONE` 而添加到 *java.time* 中的`LocalTime` 匹配 `TIME WITHOUT TIME ZONE`。但是在SQL中这个 `TIME WITH TIME ZONE` 类型没有意义这个问题不仅是我的观点其他人也指出了这一点这不是SQL标准中唯一没有意义的东西

此外您的输入带有一个时区或至少是通过错误使用 `PDT` 意图带有时区),而不是偏移偏移是一定数量的小时-分钟-仅此而已时区是偏移变化的历史正如上面讨论的那样

[1]: https://en.wikipedia.org/wiki/Daylight_saving_time
[2]: https://docs.oracle.com/en/java/javase/11/docs/api/java.base/java/time/OffsetTime.html
英文:

tl;dr

LocalTime                                        // Represent a time-of-day without a date and without a time zone or offset-from-UTC.
.parse(               
"09:07:31 AM PDT".substring( 0 , 11 ) ,      // Remove the senseless `PDT` from the input.
DateTimeFormatter.ofPattern( "hh:mm:ss a" )  // Define a formatting pattern to match our modified input string.
)                                                // Returns a `LocalTime` object.
.toString()                                      // Generates text in standard ISO 8601 format to represent the value of our `LocalTime` object.

>09:07:31

Avoid Date & Calendar

You are using terrible date-time classes that were bundled with the earliest versions of Java. These were supplanted years ago by the modern java.time classes defined in JSR 310.

Never use Date, Calendar, SimpleDateFormat, and such.

Date class does not fit

The java.util.Date class represents a moment, a date with time-of-day, as seen in UTC. Your input lacks a date. So your input cannot be represented by this class.

Time-of-day with zone makes no sense

Your input represents a time-of-day with what is a false time zone. The PDT likely stands for "Pacific Daylight Saving Time", to indicate whether Daylight Saving Time (DST) is in effect or not. This is not a true time zone name. Instead a time zone name such as America/Los_Angeles should be used.

At any rate, the combination of a time-of-day with a time zone makes no sense. Without the context of a date, the time zone carries no meaning.

LocalTime

I suggest you extract the time-of-day and ignore the PDT. Take the first 11 characters.

String input = "09:07:31 AM PDT";
String s = input.substring( 0 , 11 ); // Uses annoying zero-based index counting. So asking for first through the eleventh characters requires ( 0 , 11 ).

Define a formatting pattern to match our modified input string.

DateTimeFormatter f = DateTimeFormatter.ofPattern( "hh:mm:ss a" );

Parse as a LocalTime, a time-of-day without a date and without a time zone or offset-from-UTC.

LocalTime lt = LocalTime.parse( s , f );

>lt.toString(): 09:07:31

ZonedDateTime

For fun, let's apply a time zone to your time-of-day, and a date to get a ZonedDateTime.

LocalTime lt = LocalTime.parse( "01:59:00 AM PDT".substring( 0 , 11 ) , DateTimeFormatter.ofPattern( "hh:mm:ss a" ) );
LocalDate ld = LocalDate.of( 2020 , Month.MARCH , 7 );
ZoneId z = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
ZonedDateTime zdtLater = zdt.plusMinutes( 5 );
System.out.println( "zdtLater = " + zdtLater );

We get 2:04 AM.

>zdtLater = 2020-03-07T02:04-08:00[America/Los_Angeles]

Change that date to the 8th.

LocalTime lt = LocalTime.parse( "01:59:00 AM PDT".substring( 0 , 11 ) , DateTimeFormatter.ofPattern( "hh:mm:ss a" ) );
LocalDate ld = LocalDate.of( 2020 , Month.MARCH , 8 );
ZoneId z = ZoneId.of( "America/Los_Angeles" );
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
ZonedDateTime zdtLater = zdt.plusMinutes( 5 );
System.out.println( "zdtLater = " + zdtLater );

We get 3:04 AM, not 2:04 AM.

>zdtLater = 2020-03-08T03:04-07:00[America/Los_Angeles]

The date is what gives meaning to that time-of-day in a time zone.

Offsets vary over time. That is the meaning of a time zone. A time zone such as America/Los_Angeles is a history of the past, present, and future changes to the offset used by the people in many regions on the west coast of North America. On March 7, 2020 the offset was eight hours behind UTC. On March 8, 2020, the offset was changed to seven hours behind UTC. At the first moment of 2 AM, the clock jumped an hour to 3 AM. The 2 AM hour never happened on the 8th as it did on the 7th.

OffsetTime

The java.time framework does offer the OffsetTime class. This represents a time-of-day with an offset-from-UTC.

This class makes no sense, for the same reasons discussed above. A time-of-day with an offset but no date serves no useful purpose. I presume this was added to java.time merely to match the SQL-standard type TIME WITH TIME ZONE, in parallel with LocalTime matching TIME WITHOUT TIME ZONE. But this TIME WITH TIME ZONE type makes no sense in SQL. This problem is noted by others, not merely my opinion. And this is not the only senseless thing in the SQL standard.

Furthermore, your input carries a time zone (or at least a time zone was intended by the mis-use of PDT), not an offset. An offset is a number of hour-minutes-seconds, nothing more. A time zone is a history of changes in offset, as discussed above.

答案2

得分: 1

你需要在格式中使用正确的字母组合,如下所示:

SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss aa zzz");

你可能还想查看 API 文档 1

注意: 如果使用上述格式,解析将会正常工作,但为了准确的计算,你需要包括日期部分。以下是一个示例,使用当前时区的当前日期作为日期部分:

String receivedTime = "09:07:31 AM PDT";
String currentDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss aa zzz");
Date date = df.parse(currentDate + " " + receivedTime);

1 https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html

英文:

You need to use the right combination of letters in format, here:

SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss aa zzz");

You might also want to look at API docs 1.

Note: Parsing would work if you use the above format, but you will need the date part as well for accurate calculations. Here is an example with the current date of the current timezone of your machine used as the date part.

        String recievedTime = "09:07:31 AM PDT";
        String currentDate = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss aa zzz");
        Date date = df.parse(currentDate +" " + recievedTime);

1 https://docs.oracle.com/javase/8/docs/api/java/text/SimpleDateFormat.html

huangapple
  • 本文由 发表于 2020年8月9日 00:29:50
  • 转载请务必保留本文链接:https://go.coder-hub.com/63317745.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定