如何使用 LocalDateTime 解析/格式化日期? (Java 8)

发布于 2025-01-21 03:16:03 字数 534 浏览 0 评论 0 原文

Java 8 添加了新的 java.time 用于处理日期和时间的 API (JSR 310)。

我将日期和时间作为字符串(例如,“2014-04-08 12:30”)。如何获取 LocalDateTime给定字符串的 实例?

在完成 LocalDateTime 对象的处理后:如何将 LocalDateTime 实例转换回与上面所示格式相同的字符串?

Java 8 added a new java.time API for working with dates and times (JSR 310).

I have date and time as string (e.g., "2014-04-08 12:30"). How can I obtain a LocalDateTime instance from the given string?

After I finished working with the LocalDateTime object: How can I then convert the LocalDateTime instance back to a string with the same format as shown above?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

夏末染殇 2025-01-28 03:16:03

解析日期和时间

从字符串中创建 localdatetime 对象您可以使用static localdatetime.parse.parse() 方法。它采用一个字符串和 datement formeformatter 作为参数。 DateTimeFormatter 用于指定日期/时间模式。

String str = "1986-04-08 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);

格式化日期和时间

要创建一个格式化的字符串 localDateTime 对象您可以使用 form> format()方法。

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"

请注意,在 dateTimeFormatter 中,有一些常用的日期/时间格式预定为常数。例如:使用 dateTimeFormatter.iso_date_time 格式化 localdateTime 实例从上方导致字符串“ 1986-04-04-08T12:30:00”

parse()格式()方法可用于所有日期/时间相关的对象(例如 localdate zoneddateTime

Parsing date and time

To create a LocalDateTime object from a string you can use the static LocalDateTime.parse() method. It takes a string and a DateTimeFormatter as parameter. The DateTimeFormatter is used to specify the date/time pattern.

String str = "1986-04-08 12:30";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.parse(str, formatter);

Formatting date and time

To create a formatted string out a LocalDateTime object you can use the format() method.

DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
LocalDateTime dateTime = LocalDateTime.of(1986, Month.APRIL, 8, 12, 30);
String formattedDateTime = dateTime.format(formatter); // "1986-04-08 12:30"

Note that there are some commonly used date/time formats predefined as constants in DateTimeFormatter. For example: Using DateTimeFormatter.ISO_DATE_TIME to format the LocalDateTime instance from above would result in the string "1986-04-08T12:30:00".

The parse() and format() methods are available for all date/time related objects (e.g. LocalDate or ZonedDateTime)

梦里泪两行 2025-01-28 03:16:03

您也可以在 localdate.parse() localdateTime.parse() string> String 上使用 localdate.parse() ,如果而无需提供模式> string

例如,

String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
System.out.println("Date: " + aLD);

String strDatewithTime = "2015-08-04T10:11:30";
LocalDateTime aLDT = LocalDateTime.parse(strDatewithTime);
System.out.println("Date with Time: " + aLDT);

output

Date: 2015-08-04
Date with Time: 2015-08-04T10:11:30

并仅当您必须处理其他日期模式时,使用 dateTimeFormatter

例如,在下面的示例中, dd mmm uuuu 代表本月的一天(两个数字),三个月份的字母(2月,2月,3月, ,...)和四位数的年:

DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
String anotherDate = "04 Aug 2015";
LocalDate lds = LocalDate.parse(anotherDate, dTF);
System.out.println(anotherDate + " parses to " + lds);

输出

04 Aug 2015 parses to 2015-08-04

还请记住, dateTimeFormatter 对象是双向的;它既可以解析输入和格式输出。

String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
System.out.println(aLD + " formats as " + dTF.format(aLD));

output

2015-08-04 formats as 04 Aug 2015

(请参阅完成格式化和解析dateformatter的模式列表)。

  Symbol  Meaning                     Presentation      Examples
  ------  -------                     ------------      -------
   G       era                         text              AD; Anno Domini; A
   u       year                        year              2004; 04
   y       year-of-era                 year              2004; 04
   D       day-of-year                 number            189
   M/L     month-of-year               number/text       7; 07; Jul; July; J
   d       day-of-month                number            10

   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
   Y       week-based-year             year              1996; 96
   w       week-of-week-based-year     number            27
   W       week-of-month               number            4
   E       day-of-week                 text              Tue; Tuesday; T
   e/c     localized day-of-week       number/text       2; 02; Tue; Tuesday; T
   F       week-of-month               number            3

   a       am-pm-of-day                text              PM
   h       clock-hour-of-am-pm (1-12)  number            12
   K       hour-of-am-pm (0-11)        number            0
   k       clock-hour-of-am-pm (1-24)  number            0

   H       hour-of-day (0-23)          number            0
   m       minute-of-hour              number            30
   s       second-of-minute            number            55
   S       fraction-of-second          fraction          978
   A       milli-of-day                number            1234
   n       nano-of-second              number            987654321
   N       nano-of-day                 number            1234000000

   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

   p       pad next                    pad modifier      1

   '       escape for text             delimiter
   ''      single quote                literal           '
   [       optional section start
   ]       optional section end
   #       reserved for future use
   {       reserved for future use
   }       reserved for future use

You can also use LocalDate.parse() or LocalDateTime.parse() on a String without providing it with a pattern, if the String is in ISO 8601 format.

For example,

String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
System.out.println("Date: " + aLD);

String strDatewithTime = "2015-08-04T10:11:30";
LocalDateTime aLDT = LocalDateTime.parse(strDatewithTime);
System.out.println("Date with Time: " + aLDT);

Output,

Date: 2015-08-04
Date with Time: 2015-08-04T10:11:30

And use DateTimeFormatter only if you have to deal with other date patterns.

For instance, in the following example, dd MMM uuuu represents the day of the month (two digits), three letters of the name of the month (Jan, Feb, Mar,...), and a four-digit year:

DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
String anotherDate = "04 Aug 2015";
LocalDate lds = LocalDate.parse(anotherDate, dTF);
System.out.println(anotherDate + " parses to " + lds);

Output

04 Aug 2015 parses to 2015-08-04

also remember that the DateTimeFormatter object is bidirectional; it can both parse input and format output.

String strDate = "2015-08-04";
LocalDate aLD = LocalDate.parse(strDate);
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("dd MMM uuuu");
System.out.println(aLD + " formats as " + dTF.format(aLD));

Output

2015-08-04 formats as 04 Aug 2015

(See complete list of Patterns for Formatting and Parsing DateFormatter.)

  Symbol  Meaning                     Presentation      Examples
  ------  -------                     ------------      -------
   G       era                         text              AD; Anno Domini; A
   u       year                        year              2004; 04
   y       year-of-era                 year              2004; 04
   D       day-of-year                 number            189
   M/L     month-of-year               number/text       7; 07; Jul; July; J
   d       day-of-month                number            10

   Q/q     quarter-of-year             number/text       3; 03; Q3; 3rd quarter
   Y       week-based-year             year              1996; 96
   w       week-of-week-based-year     number            27
   W       week-of-month               number            4
   E       day-of-week                 text              Tue; Tuesday; T
   e/c     localized day-of-week       number/text       2; 02; Tue; Tuesday; T
   F       week-of-month               number            3

   a       am-pm-of-day                text              PM
   h       clock-hour-of-am-pm (1-12)  number            12
   K       hour-of-am-pm (0-11)        number            0
   k       clock-hour-of-am-pm (1-24)  number            0

   H       hour-of-day (0-23)          number            0
   m       minute-of-hour              number            30
   s       second-of-minute            number            55
   S       fraction-of-second          fraction          978
   A       milli-of-day                number            1234
   n       nano-of-second              number            987654321
   N       nano-of-day                 number            1234000000

   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

   p       pad next                    pad modifier      1

   '       escape for text             delimiter
   ''      single quote                literal           '
   [       optional section start
   ]       optional section end
   #       reserved for future use
   {       reserved for future use
   }       reserved for future use
倦话 2025-01-28 03:16:03

Sufiyan Ghori 和 <一href="https://stackoverflow.com/questions/22463062/how-can-i-parse-format-dates-with-localdatetime-java-8/22463063#22463063">micha的答案很好地解释了关于字符串模式的问题。但是,如果您使用 ISO 8601,则无需申请DateTimeFormatter 因为 LocalDateTime 已经准备好了:

将 LocalDateTime 转换为时区 ISO 8601 字符串

LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC); // You might use a different zone
String iso8601 = zdt.toString();

转换从 ISO8601 字符串返回 LocalDateTime

String iso8601 = "2016-02-14T18:32:04.150Z";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601);
LocalDateTime ldt = zdt.toLocalDateTime();

Both Sufiyan Ghori's and micha's answer explain very well the question regarding string patterns. However, just in case you are working with ISO 8601, there isn't any need to apply DateTimeFormatter since LocalDateTime is already prepared for it:

Convert a LocalDateTime to a Time Zone ISO 8601 String

LocalDateTime ldt = LocalDateTime.now();
ZonedDateTime zdt = ldt.atZone(ZoneOffset.UTC); // You might use a different zone
String iso8601 = zdt.toString();

Convert from ISO8601 String back to a LocalDateTime

String iso8601 = "2016-02-14T18:32:04.150Z";
ZonedDateTime zdt = ZonedDateTime.parse(iso8601);
LocalDateTime ldt = zdt.toLocalDateTime();
温折酒 2025-01-28 03:16:03

用日期和时间在特定时间点中解析字符串(Java称其为“ 即时 ”)非常复杂。 Java在几次迭代中一直在解决这个问题。最新的一个, java.time java.time.chrono ,涵盖了几乎所有需求(时间扩张 :))。

但是,这种复杂性带来了很多混乱。

理解日期解析的关键是:

为什么Java有这么多方法来解析日期?

  1. 有几个系统可以测量一段时间。例如,日本历史日历源自各自皇帝或王朝统治时期的时间范围。然后,例如,例如, unix timestamp
    幸运的是,整个(商业)世界设法使用了相同的使用。
  2. 从历史上看,这些系统正在从/到各种原因。例如,从 julian calendar Gregorian日历 1582年;因此,在此之前的“西方”日期需要有所不同。
  3. 而且,当然,这种变化并没有立即发生。因为日历来自某些宗教和欧洲其他地区的总部,例如,德国直到1700年才切换

。...为什么 localdatetime ZonedDateTime 等。如此复杂的

  1. 时区
    时区基本上是地球表面的“条纹”* [3] ,其当局遵循相同的规则,即何时有时间偏移。这包括夏季规则。

    时区随着时间的流逝而变化,主要是基于谁征服了谁。和一个时区的规则随着时间的流逝而更改

  2. 有时间偏移。这与时区不同,因为时区可能是,例如“布拉格”,但是夏季时间偏移和冬季偏移。

    如果您获得了时区的时间戳,则偏移可能会有所不同,具体取决于一年中的哪一部分。在leap时,时间戳可能意味着两个不同的时间,因此没有其他信息,它可以' t可靠地转换。

    注意:由 timestamp 我的意思是“一个包含日期和/或时间的字符串,可选地使用时区和/或时间偏移。”

  3. 几个时区可以共享某些时期的同一时间偏移。例如,GMT/UTC时区与夏季时间偏移无效的“伦敦”时区相同。

使其更加复杂(但这对您的用例并不重要):

  1. 科学家观察到地球的动态,随着时间的流逝而变化;基于这一点,他们在个体年代结束时增加了几秒钟。 (So 2040-12-31 24:00:00 可能是有效的日期时间。)这需要对系统用来正确具有日期转换的元数据的定期更新。例如,在Linux上,您会定期更新Java软件包,包括这些新数据。

  2. 更新并不总是保留历史和未来时间戳的先前行为。因此,可能会发生在某个时区的更改周围的两个时间戳进行分析,以比较它们可能会给出不同的结果。这也适用于受影响时区和其他时区之间的比较。

    是否应该在您的软件中引起错误,请考虑使用某些没有复杂规则的时间戳,例如 Unix Timestamp

  3. 由于有7个,对于未来的日期,我们无法确切地转换日期。因此,例如, 8524-02-17的当前解析12:00:00 可能会从未来解析的几秒钟内退出。

JDK的API随着当代的需求而发展,

  • 早期的Java版本刚刚 java.util.date ,它具有有点幼稚的方法,假设只是一年,月,一天,时间和时间。这很快就不够了。
  • 同样,数据库的需求是不同的,因此引入了 的早期,具有其自身的局限性。
  • 由于没有很好地介绍不同的日历和时区,因此引入了日历 API。
  • 这仍然没有涵盖时区的复杂性。然而,上述API的混合实际上确实很痛苦。因此,随着Java开发人员开始从事全球Web应用程序的工作,针对大多数用例的库,例如Jodatime,很快就流行了。 Jodatime是大约十年来的事实上的标准。
  • 但是JDK并未与Jodatime集成,因此与之合作有点麻烦。因此,经过很长的讨论,讨论了如何处理问题, jsr-310 被创建主要基于jodatime

如何在Java的 Java.Time 中处理它,

解析时间戳的类型

确定要在消费时间戳字符串时 ,您需要知道它包含哪些信息。 这是关键点。如果您不正确,最终会得到一个隐秘的例外,例如“无法创建瞬间”,“ Zone Offset Misssist”,“ Unknown Zone ID”,等等

  • ​ a zoneddateTime获得
  • /stackoverflow.com/questions/23596530/unable-to-obtain-zoneddateTime-from-temporalaccessor-using-datetimeformatter-and-dateTimeFormatter-and?noredirect = 1&amp;lq = 1"> quartirect = 1"> quartirect = 1“>不可能从tuermalaccessor a hreff = a hreff = a href = “ https://stackoverflow.com/questions/39978897/39978897/dateTimeParseexecception-with-localdatement-localdetime-to-obtain-to-obtain-localdatetime-from-t?noredirect = 1&amp; lq = 1&amp; lq = 1“>可从tuermalAlaCcessor 获得localdateTime
  • a href =“ https://stackoverflow.com/questions/40279066/40279066/instant time-parsing-eror-unable-unable-unable-to-obtain-to-obtain-instant-from-temporalaccessor”

< >它包含日期和时间吗?

  1. 是否有时间偏移?
    时间偏移是+hh:mm 零件。有时,+00:00 可以用 z 作为'zulu time', utc 作为通用时间协调,或 gmt < /em>作为格林威治的平均时间。这些也设定了时区。
    对于这些时间戳,您可以使用 offsetDateTime


  2. 它有时区吗?
    对于这些时间戳,您可以使用 noreferrer“ >
    区域是由

    指定的

    • 名称(“布拉格”,“太平洋标准时间”,“ PST”)或
    • “区域ID”(“ America/Los_angeles”,“欧洲/伦敦”),由 java.time.zoneid

    时区列表由a “ noreferrer”>“ noreferrer”>“ tz database” ,由 icaan

    根据 ZoneID 的Javadoc,可以以某种方式将区域ID指定为 Z 和Offset。我不确定这是如何映射到真实区域的。

    如果只有TZ的时间戳属于一个时间偏移的时间偏移更改,那么它是模棱两可的,解释是 resolverstyle 的主题,请参见下文。

  3. 如果它没有,则假定或忽略了缺失的上下文。消费者必须决定。因此,它需要以 localDateTime 进行解析,并通过添加丢失的信息来转换为 offsetDateTime

    • 您可以假设是UTC时间。添加UTC偏移为0小时。
    • 您可以假设是转换发生的地方的时代。通过添加系统的时区进行转换。
    • 您可以忽略,然后按原样使用它。这是有用的,例如比较或减去两次(请参阅 <代码>持续时间 ),或者当您不知道并且并不重要时(例如,本地巴士时间表)。

部分时间信息

  • 基于时间戳所包含的内容,您可以采用 localdate localtime offsetTime 月日,<代码>年,或 YearMonth

如果您有完整的信息,则可以获得 java.time.instant 。这也用于内部用于在 OffSetDateTime ZonedDateTime 之间转换。

弄清楚如何解析它,

DateTimeFormatter 可以将时间戳字符串和格式解析为字符串。

代码> DateTimeFormatter s 应涵盖或多或少涵盖所有标准时间戳格式。例如, iso_instant 可以解析 2011-12-03T10:15:30.123457Z

如果您有一些特殊的格式,则可以创建自己的dateTimeFormatter (这也是解析器) 。

private static final DateTimeFormatter TIMESTAMP_PARSER = new DateTimeFormatterBuilder()
   .parseCaseInsensitive()
   .append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SX"))
   .toFormatter();

我建议查看 dateTimeFormatter 的源代码,并在如何使用 dateTimeFormatterBuilder 上构建一个源代码。当您在那里时,还要查看 Resolverstyle ,它控制解析器是宽大,智能还是严格的格式和模棱两可的信息。

现在, YeaterAlaccessor

,经常出现的错误是进入 terumalaccessor 的复杂性。这来自开发人员使用 simpledateformatter.parse(string)的方式。对, datementingformatter.parse(“ ...”)给您 temeralAccessor

// No need for this!
TemporalAccessor ta = TIMESTAMP_PARSER.parse("2011-... etc");

但是,通过上一节的知识,您可以方便地分解为所需的类型:

OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z", TIMESTAMP_PARSER);

您实际上也不需要 dateTimeFormatter 。您要解析的类型具有 Parse(String)方法。

OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z");

关于 terunalAccessor ,如果您对字符串中有哪些信息有模糊的了解,并且想在运行时做出决定,则可以使用它。

我希望我对您的灵魂有所了解:)

注意: java.time 的后退到Java 6和7: threeten-backport 。对于Android,它具有 threetenabp

[3] 不仅是它们不是条纹,而且还有一些奇怪的极端。例如,一些邻近的太平洋岛屿和-11:00时区。这意味着,在一个岛上,在5月3日下午1日,在另一个岛屿上,它仍然是4月30日下午30点(如果我正确计数的话:))

Parsing a string with date and time into a particular point in time (Java calls it an "Instant") is quite complicated. Java has been tackling this in several iterations. The latest one, java.time and java.time.chrono, covers almost all needs (except time dilation :) ).

However, that complexity brings a lot of confusion.

The key to understand date parsing is:

Why does Java have so many ways to parse a date?

  1. There are several systems to measure a time. For instance, the historical Japanese calendars were derived from the time ranges of the reign of the respective emperor or dynasty. Then there is, e.g., the Unix timestamp.
    Fortunately, the whole (business) world managed to use the same.
  2. Historically, the systems were being switched from/to, for various reasons. E.g., from the Julian calendar to the Gregorian calendar in 1582; so, the 'western' dates before that need to be treated differently.
  3. And, of course, the change did not happen at once. Because the calendar came from the headquarters of some religion and other parts of Europe believed in other deities, for instance Germany did not switch until the year 1700.

...and why is the LocalDateTime, ZonedDateTime et al. so complicated

  1. There are time zones.
    A time zone is basically a "stripe"*[3] of the Earth's surface whose authorities follow the same rules of when does it have which time offset. This includes summer time rules.

    The time zones change over time for various areas, mostly based on who conquers whom. And one time zone's rules change over time as well.

  2. There are time offsets. That is not the same as time zones, because a time zone may be, e.g., "Prague", but that has summer time offset and winter time offset.

    If you get a timestamp with a time zone, the offset may vary, depending on what part of the year it is in. During the leap hour, the timestamp may mean two different times, so without additional information, it can't be reliably converted.

    Note: By timestamp I mean "a string that contains a date and/or time, optionally with a time zone and/or time offset."

  3. Several time zones may share the same time offset for certain periods. For instance, the GMT/UTC time zone is the same as the "London" time zone when the summer time offset is not in effect.

To make it a bit more complicated (but that's not too important for your use case):

  1. The scientists observe Earth's dynamic, which changes over time; based on that, they add seconds at the end of individual years. (So 2040-12-31 24:00:00 may be a valid date-time.) This needs regular updates of the metadata that systems use to have the date conversions right. E.g., on Linux, you get regular updates to the Java packages including these new data.

  2. The updates do not always keep the previous behavior for both historical and future timestamps. So it may happen that parsing of the two timestamps around some time zone's change comparing them may give different results when running on different versions of the software. That also applies to comparing between the affected time zone and other time zone.

    Should this cause a bug in your software, consider using some timestamp that does not have such complicated rules, like Unix timestamp.

  3. Because of 7, for the future dates, we can't convert dates exactly with certainty. So, for instance, current parsing of 8524-02-17 12:00:00 may be off a couple of seconds from the future parsing.

JDK's APIs for this evolved with the contemporary needs

  • The early Java releases had just java.util.Date which had a bit naive approach, assuming that there's just the year, month, day, and time. This quickly did not suffice.
  • Also, the needs of the databases were different, so quite early, java.sql.Date was introduced, with its own limitations.
  • Because neither covered different calendars and time zones well, the Calendar API was introduced.
  • This still did not cover the complexity of the time zones. And yet, the mix of the above APIs was really a pain to work with. So as Java developers started working on global web applications, libraries that targeted most use cases, like JodaTime, got quickly popular. JodaTime was the de facto standard for about a decade.
  • But the JDK did not integrate with JodaTime, so working with it was a bit cumbersome. So, after a very long discussion on how to approach the matter, JSR-310 was created mainly based on JodaTime.

How to deal with it in Java's java.time

Determine what type to parse a timestamp to

When you are consuming a timestamp string, you need to know what information it contains. This is the crucial point. If you don't get this right, you end up with a cryptic exceptions like "Can't create Instant", "Zone offset missing", "unknown zone id", etc.

Does it contain the date and the time?

  1. Does it have a time offset?
    A time offset is the +hh:mm part. Sometimes, +00:00 may be substituted with Z as 'Zulu time', UTC as Universal Time Coordinated, or GMT as Greenwich Mean Time. These also set the time zone.
    For these timestamps, you use OffsetDateTime.

  2. Does it have a time zone?
    For these timestamps, you use ZonedDateTime.
    Zone is specified either by

    • name ("Prague", "Pacific Standard Time", "PST"), or
    • "zone ID" ("America/Los_Angeles", "Europe/London"), represented by java.time.ZoneId.

    The list of time zones is compiled by a "TZ database", backed by ICAAN.

    According to ZoneId's javadoc, the zone id's can also somehow be specified as Z and offset. I'm not sure how this maps to real zones.

    If the timestamp, which only has a TZ, falls into a leap hour of time offset change, then it is ambiguous, and the interpretation is subject of ResolverStyle, see below.

  3. If it has neither, then the missing context is assumed or neglected. And the consumer has to decide. So it needs to be parsed as LocalDateTime and converted to OffsetDateTime by adding the missing info:

    • You can assume that it is a UTC time. Add the UTC offset of 0 hours.
    • You can assume that it is a time of the place where the conversion is happening. Convert it by adding the system's time zone.
    • You can neglect and just use it as is. That is useful e.g. to compare or subtract two times (see Duration), or when you don't know and it doesn't really matter (e.g., local bus schedule).

Partial time information

  • Based on what the timestamp contains, you can take LocalDate, LocalTime, OffsetTime, MonthDay, Year, or YearMonth out of it.

If you have the full information, you can get a java.time.Instant. This is also internally used to convert between OffsetDateTime and ZonedDateTime.

Figure out how to parse it

There is an extensive documentation on DateTimeFormatter which can both parse a timestamp string and format to string.

The pre-created DateTimeFormatters should cover more or less all standard timestamp formats. For instance, ISO_INSTANT can parse 2011-12-03T10:15:30.123457Z.

If you have some special format, then you can create your own DateTimeFormatter (which is also a parser).

private static final DateTimeFormatter TIMESTAMP_PARSER = new DateTimeFormatterBuilder()
   .parseCaseInsensitive()
   .append(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SX"))
   .toFormatter();

I recommend to look at the source code of DateTimeFormatter and get inspired on how to build one using DateTimeFormatterBuilder. While you're there, also have a look at ResolverStyle which controls whether the parser is LENIENT, SMART or STRICT for the formats and ambiguous information.

TemporalAccessor

Now, the frequent mistake is to go into the complexity of TemporalAccessor. This comes from how the developers were used to work with SimpleDateFormatter.parse(String). Right, DateTimeFormatter.parse("...") gives you TemporalAccessor.

// No need for this!
TemporalAccessor ta = TIMESTAMP_PARSER.parse("2011-... etc");

But, equipped with the knowledge from the previous section, you can conveniently parse into the type you need:

OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z", TIMESTAMP_PARSER);

You do not actually need to the DateTimeFormatter either. The types you want to parse have the parse(String) methods.

OffsetDateTime myTimestamp = OffsetDateTime.parse("2011-12-03T10:15:30.123457Z");

Regarding TemporalAccessor, you can use it if you have a vague idea of what information there is in the string, and want to decide at runtime.

I hope I shed some light of understanding onto your soul :)

Note: There's a backport of java.time to Java 6 and 7: ThreeTen-Backport. For Android it has ThreeTenABP.

[3] Not just that they are not stripes, but there also some weird extremes. For instance, some neighboring Pacific Islands have +14:00 and -11:00 time zones. That means, that while on one island, there is 1st May 3 PM, on another island not so far, it is still 30 April 12 PM (if I counted correctly :) )

南笙 2025-01-28 03:16:03

使用 LocalDateTime.Parse 要注意的另一件事是,您不能将其与仅具有date formatter字符的自定义格式化器一起使用,例如 uuuuumdd 。在这种情况下,您应该改用 localdate.parse 。例如:

String s = "20210223";
        
// ok
LocalDate.parse(s, DateTimeFormatter.ofPattern("uuuuMMdd"));
        
// java.time.format.DateTimeParseException
LocalDateTime.parse(s, DateTimeFormatter.ofPattern("uuuuMMdd")); 

Another thing to note with LocalDateTime.parse is that you cannot use it with a custom formatter with only date formatter characters, such as uuuuMMdd. In this case, you should use LocalDate.parse instead. For example:

String s = "20210223";
        
// ok
LocalDate.parse(s, DateTimeFormatter.ofPattern("uuuuMMdd"));
        
// java.time.format.DateTimeParseException
LocalDateTime.parse(s, DateTimeFormatter.ofPattern("uuuuMMdd")); 
月棠 2025-01-28 03:16:03

以所需格式获取当前 UTC 时间

// Current the UTC time
OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);

// Get LocalDateTime
LocalDateTime localDateTime = utc.toLocalDateTime();
System.out.println("*************" + localDateTime);

// Formatted UTC time
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(" formats as " + dTF.format(localDateTime));

// Get the UTC time for the current date
Date now = new Date();
LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));

Get the current UTC time in the required format

// Current the UTC time
OffsetDateTime utc = OffsetDateTime.now(ZoneOffset.UTC);

// Get LocalDateTime
LocalDateTime localDateTime = utc.toLocalDateTime();
System.out.println("*************" + localDateTime);

// Formatted UTC time
DateTimeFormatter dTF = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(" formats as " + dTF.format(localDateTime));

// Get the UTC time for the current date
Date now = new Date();
LocalDateTime utcDateTimeForCurrentDateTime = Instant.ofEpochMilli(now.getTime()).atZone(ZoneId.of("UTC")).toLocalDateTime();
DateTimeFormatter dTF2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
System.out.println(" formats as " + dTF2.format(utcDateTimeForCurrentDateTime));
暖风昔人 2025-01-28 03:16:03

所有的答案都很好。 Java 8+ 版本具有以下用于解析和格式化时区的模式:VzOXxZ

这是根据文档中的规则进行解析的:

   Symbol  Meaning                     Presentation      Examples
   ------  -------                     ------------      -------
   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

但是格式化怎么样?

下面是一个日期示例(假设 ZonedDateTime),它显示了不同格式模式的这些模式行为:

// The helper function:
static void printInPattern(ZonedDateTime dt, String pattern) {
    System.out.println(pattern + ": " + dt.format(DateTimeFormatter.ofPattern(pattern)));
}

// The date:
String strDate = "2020-11-03 16:40:44 America/Los_Angeles";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzzz");
ZonedDateTime dt = ZonedDateTime.parse(strDate, format);
// 2020-11-03T16:40:44-08:00[America/Los_Angeles]

// Rules:
// printInPattern(dt, "V");     // exception!
printInPattern(dt, "VV");       // America/Los_Angeles
// printInPattern(dt, "VVV");   // exception!
// printInPattern(dt, "VVVV");  // exception!
printInPattern(dt, "z");        // PST
printInPattern(dt, "zz");       // PST
printInPattern(dt, "zzz");      // PST
printInPattern(dt, "zzzz");     // Pacific Standard Time
printInPattern(dt, "O");        // GMT-8
// printInPattern(dt, "OO");    // exception!
// printInPattern(dt, "OO0");   // exception!
printInPattern(dt, "OOOO");     // GMT-08:00
printInPattern(dt, "X");        // -08
printInPattern(dt, "XX");       // -0800
printInPattern(dt, "XXX");      // -08:00
printInPattern(dt, "XXXX");     // -0800
printInPattern(dt, "XXXXX");    // -08:00
printInPattern(dt, "x");        // -08
printInPattern(dt, "xx");       // -0800
printInPattern(dt, "xxx");      // -08:00
printInPattern(dt, "xxxx");     // -0800
printInPattern(dt, "xxxxx");    // -08:00
printInPattern(dt, "Z");        // -0800
printInPattern(dt, "ZZ");       // -0800
printInPattern(dt, "ZZZ");      // -0800
printInPattern(dt, "ZZZZ");     // GMT-08:00
printInPattern(dt, "ZZZZZ");    // -08:00

在正偏移量的情况下,+ 符号字符随处使用(其中现在有 -)并且从未省略。

这对于新的 java.time 类型非常有效。如果您打算将它们用于 java.util.Date 或 java.util.Calendar - 并非所有类型都可以工作,因为这些类型已损坏(因此标记为已弃用,请不要使用它们)。

All the answers are good. The Java 8+ versions have these patterns for parsing and formatting time zones: V, z, O, X, x, Z.

Here's they are, for parsing, according to rules from the documentation:

   Symbol  Meaning                     Presentation      Examples
   ------  -------                     ------------      -------
   V       time-zone ID                zone-id           America/Los_Angeles; Z; -08:30
   z       time-zone name              zone-name         Pacific Standard Time; PST
   O       localized zone-offset       offset-O          GMT+8; GMT+08:00; UTC-08:00;
   X       zone-offset 'Z' for zero    offset-X          Z; -08; -0830; -08:30; -083015; -08:30:15;
   x       zone-offset                 offset-x          +0000; -08; -0830; -08:30; -083015; -08:30:15;
   Z       zone-offset                 offset-Z          +0000; -0800; -08:00;

But how about formatting?

Here's a sample for a date (assuming ZonedDateTime) that show these patters behavior for different formatting patters:

// The helper function:
static void printInPattern(ZonedDateTime dt, String pattern) {
    System.out.println(pattern + ": " + dt.format(DateTimeFormatter.ofPattern(pattern)));
}

// The date:
String strDate = "2020-11-03 16:40:44 America/Los_Angeles";
DateTimeFormatter format = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss zzzz");
ZonedDateTime dt = ZonedDateTime.parse(strDate, format);
// 2020-11-03T16:40:44-08:00[America/Los_Angeles]

// Rules:
// printInPattern(dt, "V");     // exception!
printInPattern(dt, "VV");       // America/Los_Angeles
// printInPattern(dt, "VVV");   // exception!
// printInPattern(dt, "VVVV");  // exception!
printInPattern(dt, "z");        // PST
printInPattern(dt, "zz");       // PST
printInPattern(dt, "zzz");      // PST
printInPattern(dt, "zzzz");     // Pacific Standard Time
printInPattern(dt, "O");        // GMT-8
// printInPattern(dt, "OO");    // exception!
// printInPattern(dt, "OO0");   // exception!
printInPattern(dt, "OOOO");     // GMT-08:00
printInPattern(dt, "X");        // -08
printInPattern(dt, "XX");       // -0800
printInPattern(dt, "XXX");      // -08:00
printInPattern(dt, "XXXX");     // -0800
printInPattern(dt, "XXXXX");    // -08:00
printInPattern(dt, "x");        // -08
printInPattern(dt, "xx");       // -0800
printInPattern(dt, "xxx");      // -08:00
printInPattern(dt, "xxxx");     // -0800
printInPattern(dt, "xxxxx");    // -08:00
printInPattern(dt, "Z");        // -0800
printInPattern(dt, "ZZ");       // -0800
printInPattern(dt, "ZZZ");      // -0800
printInPattern(dt, "ZZZZ");     // GMT-08:00
printInPattern(dt, "ZZZZZ");    // -08:00

In the case of positive offset, the + sign character is used everywhere (where there is - now) and never omitted.

This well works for new java.time types. If you're about to use these for java.util.Date or java.util.Calendar - not all going to work as those types are broken (and so marked as deprecated, please don't use them).

夏尔 2025-01-28 03:16:03

通用方法如下所示。它适用于:

  • yyyy-MM-dd HH:mm:ss.SSS

  • yyyy-MM-dd HH:mm:ss.S

  • yyyy-MM-dd HH:mm:ss

  • yyyy-MM-dd HH:mm

  • yyyy-MM-dd HH

  • yyyy-MM-dd

    public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
    
    公共 LocalDateTime stringToLocalDateTime(String s){
        return LocalDateTime.parse(s, DateTimeFormatter.ofPattern(DATE_FORMAT_YYYY_MM_DD_HH_MM_SS_SSS.substring(0, s.length())));
    }
    

The universal method looks as below. It works for:

  • yyyy-MM-dd HH:mm:ss.SSS

  • yyyy-MM-dd HH:mm:ss.S

  • yyyy-MM-dd HH:mm:ss

  • yyyy-MM-dd HH:mm

  • yyyy-MM-dd HH

  • yyyy-MM-dd

    public static final String DATE_FORMAT_YYYY_MM_DD_HH_MM_SS_SSS = "yyyy-MM-dd HH:mm:ss.SSS";
    
    public LocalDateTime stringToLocalDateTime(String s){
        return LocalDateTime.parse(s, DateTimeFormatter.ofPattern(DATE_FORMAT_YYYY_MM_DD_HH_MM_SS_SSS.substring(0, s.length())));
    }
    
月下凄凉 2025-01-28 03:16:03

让我们提取两个问题,示例字符串“ 2014-04-08 12:30”

如何从给定的字符串获得localdatetime实例?

import java.time.format.DateTimeFormatter
import java.time.LocalDateTime

final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")

// Parsing or conversion
final LocalDateTime dt = LocalDateTime.parse("2014-04-08 12:30", formatter)

DT 应该允许您进行所有与日期相关的操作

然后,如何将LocalDateTime实例转换回具有相同格式的字符串?

final String date = dt.format(formatter) 

Let's take two questions, example string "2014-04-08 12:30"

How can I obtain a LocalDateTime instance from the given string?

import java.time.format.DateTimeFormatter
import java.time.LocalDateTime

final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm")

// Parsing or conversion
final LocalDateTime dt = LocalDateTime.parse("2014-04-08 12:30", formatter)

dt should allow you to all date-time related operations

How can I then convert the LocalDateTime instance back to a string with the same format?

final String date = dt.format(formatter) 
望喜 2025-01-28 03:16:03

这个问题已经有很多好的答案。此答案显示了如何使用预定义 dateTimeFormatter s构建 dateTimeFormatter ,该可以解析给定的日期时间字符串。

但是,使用此 dateTimeFormatter 将获得的 LocalDateTime 格式化将在 hh:mm:mm:ss 格式中返回字符串。要将时间字符串限制为 HH:MM 格式,我们仍然必须使用模式 uuuuu-mm-dd hh:mm ,就像其他答案所做的那样。

demo

class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                .append(DateTimeFormatter.ISO_LOCAL_DATE)
                .appendLiteral(' ')
                .append(DateTimeFormatter.ISO_LOCAL_TIME)
                .toFormatter(Locale.ENGLISH);

        String strDateTime = "2014-04-08 12:30";
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
        System.out.println(ldt);

        // However, formatting the obtained LocalDateTime using this DateTimeFormatter
        // will return a string with time in HH:mm:ss format. To restrict the time
        // string to HH:mm format, we still have to use the pattern, uuuu-MM-dd HH:mm as
        // other answers have done.
        String strDateTimeFormatted = ldt.format(dtf);
        System.out.println(strDateTimeFormatted);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm", Locale.ENGLISH);
        strDateTimeFormatted = ldt.format(formatter);
        System.out.println(strDateTimeFormatted);
    }
}

输出

2014-04-08T12:30
2014-04-08 12:30:00
2014-04-08 12:30

在线demo < < /a>

注意:在这里,您可以使用 y 而不是 u ,但我更喜欢 u 而不是 y

trail> trail> trail:日期时间< /a>

There are already many good answers to this question. This answer shows how to use predefined DateTimeFormatters to build a DateTimeFormatter which can parse the given date-time string.

However, formatting the obtained LocalDateTime using this DateTimeFormatter will return a string with time in HH:mm:ss format. To restrict the time string to HH:mm format, we still have to use the pattern uuuu-MM-dd HH:mm as other answers have done.

Demo:

class Main {
    public static void main(String[] args) {
        DateTimeFormatter dtf = new DateTimeFormatterBuilder()
                .append(DateTimeFormatter.ISO_LOCAL_DATE)
                .appendLiteral(' ')
                .append(DateTimeFormatter.ISO_LOCAL_TIME)
                .toFormatter(Locale.ENGLISH);

        String strDateTime = "2014-04-08 12:30";
        LocalDateTime ldt = LocalDateTime.parse(strDateTime, dtf);
        System.out.println(ldt);

        // However, formatting the obtained LocalDateTime using this DateTimeFormatter
        // will return a string with time in HH:mm:ss format. To restrict the time
        // string to HH:mm format, we still have to use the pattern, uuuu-MM-dd HH:mm as
        // other answers have done.
        String strDateTimeFormatted = ldt.format(dtf);
        System.out.println(strDateTimeFormatted);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm", Locale.ENGLISH);
        strDateTimeFormatted = ldt.format(formatter);
        System.out.println(strDateTimeFormatted);
    }
}

Output:

2014-04-08T12:30
2014-04-08 12:30:00
2014-04-08 12:30

ONLINE DEMO

Note: Here, you can use y instead of u but I prefer u to y.

Learn more about the modern Date-Time API from Trail: Date Time.

两人的回忆 2025-01-28 03:16:03

我发现涵盖这样的日期时间格式的多种变体非常好:

final DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"))
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);

I found it wonderful to cover multiple variants of date time formats like this:

final DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SS"))
    .appendOptional(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"))
    .parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
    .parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
    .parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0);
静谧幽蓝 2025-01-28 03:16:03

当我有一个类型 java.time.localdatetime 的变量时,以获得理想格式的日期,我不想使用中间

LocalDateTime nowDate = LocalDateTime.now();
String nowDateInString = nowDate.toString().substring(0,16).replace("T", " ");


类-27 11:17

您可以调整“子字符串”中的值以检索所需的内容。

我想指出的是,这在每种情况下都不是合适的方法。

When I have a variable of type java.time.LocalDateTime to get the date with a desirable format and I don't want to use intermediate classes, I just do:

LocalDateTime nowDate = LocalDateTime.now();
String nowDateInString = nowDate.toString().substring(0,16).replace("T", " ");


The value of nowDateInString : 2023-10-27 11:17

You can adjust the value in 'substring' to retrieve what you want.

I would like to point out that this is not a suitable method in every situation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文