简体   繁体   English

SimpleDateFormat.parse(date_string) 生成上一个日期

[英]SimpleDateFormat.parse(date_string) generate a previous date

I got a weird issue.我有一个奇怪的问题。

SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);

I call it with:我称之为:

Date date = sdf.parse("06/05/2020");

and it show the "date" is Thu Jun 04 18:00:00 MDT 2020, that is, one day less.它显示“日期”是 Thu Jun 04 18:00:00 MDT 2020,即少了一天。

Where is wrong for SimpleDateFormat? SimpleDateFormat 哪里错了?

I am using Android Studio 3.5.1 and Androidx.我正在使用 Android Studio 3.5.1 和 Androidx。

Thanks in advance.提前致谢。 Shawn肖恩

java.time and ThreeTenABP java.time 和 ThreeTenABP

The bullet-proof way is switching to java.time, the modern Java date and time API.防弹的方法是切换到java.time,现代的Java日期和时间API。

    DateTimeFormatter dateFormatter
            = DateTimeFormatter.ofPattern("MM/dd/yyyy", Locale.ENGLISH);

    LocalDate date = LocalDate.parse("06/05/2020", dateFormatter);

    System.out.println(date);

Output is: Output 是:

2020-06-05 2020-06-05

What went wrong in your code?你的代码出了什么问题?

It's certainly a time zone problem.这当然是时区问题。 However, it isn't reproduced by naïvely running your code.但是,它不会通过天真地运行您的代码来复制。 There is something more going on, and we can only guess at exactly what.还有更多的事情发生,我们只能猜测到底是什么。 I'll present a couple of ways that this might have happened.我将介绍几种可能发生这种情况的方法。

The first possibility, the default time zone of your JVM might have changed underway.第一种可能性,JVM 的默认时区可能正在更改。 To demonstrate:展示:

    TimeZone.setDefault(TimeZone.getTimeZone("Etc/UTC"));
    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
    Date date = sdf.parse("06/05/2020");

    TimeZone.setDefault(TimeZone.getTimeZone("America/Edmonton"));
    System.out.println(date);

Thu Jun 04 18:00:00 MDT 2020 2020 年 6 月 4 日星期四 18:00:00 MDT

In all fairness it's not a full day wrong, it's 6 hours.平心而论,这不是一整天的错误,而是 6 个小时。 It's bad enough, and certainly the day of week and day of month are wrong.这已经够糟糕的了,当然星期几和月份的日期是错误的。 Please note that the JVM's time zone setting may have been changed from a completely different part of your program or from a different program running in the same JVM.请注意,JVM 的时区设置可能已从您程序的完全不同部分或在同一 JVM 中运行的不同程序更改。 What happened was: The SimpleDateFormat got the default time zone of the JVM, that is, UTC.发生的事情是: SimpleDateFormat获得了 JVM 的默认时区,即 UTC。 So parsed the date into the first moment of June 5 in UTC.因此,将日期解析为 UTC 时间 6 月 5 日的第一刻。 At this point in time, it's still June 4 in North America.此时,北美仍是 6 月 4 日。 Next, when we print the Date , Date.toString() grabs the (changed) time zone of the JVM and uses it for rendering the string.接下来,当我们打印Date时, Date.toString()的(更改的)时区并将其用于呈现字符串。 Therefore we got the MDT time (North American Mountain Daylight Time), not the UTC time that had been used for parsing.因此我们得到了 MDT 时间(北美山区夏令时),而不是用于解析的 UTC 时间。

We don't need something as drastic as setting the time zone for the entire JVM to demonstrate, though.不过,我们不需要像为整个 JVM 设置时区那样激烈的东西来演示。 It's enough to set the time zone of the formatter.设置格式化程序的时区就足够了。

    SimpleDateFormat sdf = new SimpleDateFormat("MM/dd/yyyy", Locale.ENGLISH);
    sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
    Date date = sdf.parse("06/05/2020");
    System.out.println(date);

When running in America/Edmonton time zone:在美国/埃德蒙顿时区运行时:

Thu Jun 04 18:00:00 MDT 2020 2020 年 6 月 4 日星期四 18:00:00 MDT

What happens is basically the same as above.发生的事情与上面基本相同。

Question: Doesn't java.time require Android API level 26?问:java.time不需要Android API 26级吗?

java.time works nicely on both older and newer Android devices. java.time 适用于较旧和较新的 Android 设备。 It just requires at least Java 6 .它只需要至少Java 6

  • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.在 Java 8 及更高版本以及更新的 Android 设备(来自 API 级别 26)中,现代 ZDB9734A 内置23871083ACE16。
  • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).在非 Android Java 6 和 7 中,获得 ThreeTen Backport,现代类的后向端口(JSR 310 的 ThreeTen;参见底部的链接)。
  • On (older) Android use the Android edition of ThreeTen Backport.在(旧版)Android 上,使用 ThreeTen Backport 的 Android 版本。 It's called ThreeTenABP.它被称为 ThreeTenABP。 And make sure you import the date and time classes from org.threeten.bp with subpackages.并确保从带有子包的org.threeten.bp导入日期和时间类。

Links链接

This is a common problem with TimeZone , you need to set the correct timezone to your sdf , something like:这是TimeZone的常见问题,您需要为sdf设置正确的时区,例如:

sdf.setTimeZone(TimeZone.getTimeZone("GMT"))

If you set the right timezone, you'll see the right day:)如果您设置了正确的时区,您将看到正确的日期:)

Hope it helps希望能帮助到你

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM