毫无疑问,您的意外观察是由于一个或多个时区问题造成的。
因此,您需要做的第一件事是确保您知道所涉及的时区。
- 您的前端使用哪个时区向您发送日期和时间?
- 您的数据库使用哪个时区来存储日期和时间并在您检查它们时向您显示它们?(建议使用 UTC 存储时间。)
一旦你知道这一点,你可以检查:
- 从 1/29/1900 07:01:01 AM 从某个时区的前端转换
Instant
为1900-01-29T07:01:01Z
正确的时间?以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
极客部分:避免将时间格式化为字符串并将其解析回来
我不禁思考是否可以让 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
收益如前。