将单独的日期、小时、分钟、秒和AM/PM转换为java.time.Instant



从前端,我收到一个单独的LocalDate(变量名为date(,以及用于小时、分钟、秒和";AM";或";PM";字符串,我需要将它们组合成一个java.time.Instant对象存储在数据库中。我尝试按如下方式构建LocalTime,如果这是PM时间,则添加12小时,然后构建Instant:

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:00 AM,这是存储在数据库中的时间。

我是在错误地构建时间还是瞬间?

毫无疑问,您的意外观测结果是由一个或多个时区问题引起的。

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

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

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

  • 从1900年1月29日上午07:01:01从某个时区的前端到1900-01-29T07:01:01ZInstant的转换是否正确?Instant以UTC显示其时间(由后面的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

Geeky部分:避免将时间格式化为字符串并解析回

我忍不住想,是否可以让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的构建与以前一样进行。

相关内容

  • 没有找到相关文章

最新更新