0

从前端,我收到一个单独的(变量LocalDate名称是数据库。我尝试按如下方式构建 a,如果这是 PM 时间,则添加 12 小时,然后构建一个:datejava.time.InstantLocalTimeInstant

LocalTime time = LocalTime.of("pm".equals(amPm) ? hours + 12: hours, minutes, seconds);

Instant instant = date.atTime(time).toInstant(ZoneOffset.UTC);

但是当我存储和重新加载页面时,虽然日期总是完好无损,但时间总是在改变。如果我将日期设置为 1900 年 1 月 29 日并将时间设置为 07:01:01 AM,则Instant我正在创建和存储的值为:1900-01-29T07:01:01Z 当我调试时,这看起来是正确的,但是当页面重新加载时,时间显示为 02:01:01 AM,这就是存储在数据库中的时间。

我是否错误地构建了时间或瞬间?

4

1 回答 1

0

毫无疑问,您的意外观察是由于一个或多个时区问题造成的。

因此,您需要做的第一件事是确保您知道所涉及的时区。

  1. 您的前端使用哪个时区向您发送日期和时间?
  2. 您的数据库使用哪个时区来存储日期和时间并在您检查它们时向您显示它们?(建议使用 UTC 存储时间。)

一旦你知道这一点,你可以检查:

  • 从 1/29/1900 07:01:01 AM 从某个时区的前端转换Instant1900-01-29T07:01:01Z正确的时间?以InstantUTC 显示其时间(由尾随 表示Z)。
  • Instant数据库时区从 02:01:01 AM的转换是否正确?
  • 是否从数据库中正确获取时间?我假设您将其取回Java?
  • 您在 Java 中的时间是否在前端正确转换为 02:01:01 AM?我再次假设在页面重新加载时您正在显示从数据库中获取的时间,但我认为您没有告诉我们,所以我可能是错的。

要回答您的问题:

我是否错误地构建了时间或瞬间?

这取决于; 这当然是可能的。

  • 您对时间的构造假设pm始终为小写,并且 12 点钟(午夜或中午)被指定为 0。一方面我发现这两种假设或多或少不太可能,另一方面它们无法解释您观察到的 5 小时的差异。12 通常在 12 小时制上给出为 12(不是 0)。你的问题PM是大写的。
  • 您的构造Instant假设前端以 UTC 格式发送时间。对我来说,这听起来也不太可能,这可能是您观察到页面重新加载后显示的时间不正确的原因或原因之一。

代码示例

在下面的代码片段中,我做出了相反的假设:12 被给出为 12,AM/PM 无论如何都可能是,前端时区是 America/New_York。它可能很遥远,但可能有一个细节可供您选择并用于您的目的。

    DateTimeFormatter timeFormatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive() // Accept all of am, AM, aM and Am
            .appendPattern("h:m:sa")
            .toFormatter(Locale.US);
    ZoneId zone = ZoneId.of("America/New_York");
    
    LocalDate date = LocalDate.of(1900, Month.JANUARY, 29);
    int hours = 7;
    int minutes = 1;
    int seconds = 1;
    String amPm = "AM";
    
    String constructedTimeString
            = "" + hours + ':' + minutes + ':' + seconds + amPm;
    LocalTime time = LocalTime.parse(constructedTimeString, timeFormatter);

    Instant instant = date.atTime(time).atZone(zone).toInstant();
    
    System.out.println(instant);

输出是:

1900-01-29T12:01:01Z

极客部分:避免将时间格式化为字符串并将其解析回来

我不禁思考是否可以让 java.time 解析 AM/PM 字符串,而不必为一天中的时间构造一个字符串并对其进行解析。这是可能的,但是我们需要使用低级TemporalAccessor接口,否则通常是不必要的。

    DateTimeFormatter amPmFormatter = new DateTimeFormatterBuilder()
            .parseCaseInsensitive() // Accept all of am, AM, aM and Am
            .appendPattern("a")
            .toFormatter(Locale.US);

    int hours = 7;
    int minutes = 1;
    int seconds = 1;
    String amPm = "AM";
    
    TemporalAccessor parsedAmPm = amPmFormatter.parse(amPm);
    LocalTime time = LocalTime.of(0, minutes, seconds)
            .with(ChronoField.AMPM_OF_DAY, parsedAmPm.get(ChronoField.AMPM_OF_DAY))
            .with(ChronoField.CLOCK_HOUR_OF_AMPM, hours);

    System.out.println(time);

07:01:01

建设Instant收益如前。

于 2020-07-23T06:01:18.073 回答