从前端,我收到一个单独的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,这是存储在数据库中的时间。
我是在错误地构建时间还是瞬间?
毫无疑问,您的意外观测结果是由一个或多个时区问题引起的。
因此,你需要做的第一件事是确保你知道涉及哪些时区。
- 您的前端使用哪个时区向您发送日期和时间
- 您的数据库使用哪个时区来存储日期和时间,并在检查时显示给您?(建议UTC存储时间。(
一旦你知道了这一点,你可以检查:
- 从1900年1月29日上午07:01:01从某个时区的前端到
1900-01-29T07:01:01Z
的Instant
的转换是否正确?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
的构建与以前一样进行。