毫无疑问,您的意外观察是由一个或多个时区问题引起的。
因此,您需要做的第一件事是确保您知道所涉及的时区。
- 您的前端使用哪个时区向您发送日期和时间?
- 您的数据库使用哪个时区来存储日期和时间并在您检查时显示给您? (建议使用 UTC 来存储时间。)
一旦你知道这一点,你可以检查:
- 从 1/29/1900 07:01:01 AM 从某个时区的前端到
1900-01-29T07:01:01Z 的 Instant 的转换是否正确? Instant 以 UTC 显示其时间(由结尾的 Z 表示)。
- 数据库时区从
Instant 到凌晨02:01:01 的转换是否正确?
- 是否从数据库中正确获取时间?我假设您正在将其取回 Java 中?
- Java 中的时间是否在前端正确转换为 02:01:01 AM?我再次假设在页面重新加载时您正在显示从数据库中获取的时间,但我认为您没有告诉我们,所以我可能是错的。
回答你的问题:
我是不是在错误地构造时间或瞬间?
视情况而定;这当然是可能的。
- 您对时间的构造是假设
pm 总是小写,并且 12 点钟(午夜或中午)被指定为 0。一方面我发现这两种假设或多或少不太可能,另一方面他们无法解释您观察到的 5 小时的差异。 12 通常在 12 小时制上给出为 12(不是 0)。您的问题以大写形式给出PM。
-
Instant 的构造假定前端以 UTC 格式发送时间。在我看来,这听起来也不太可能,这可能是您观察到页面重新加载后显示的时间不正确的原因或原因之一。
代码示例
在下面的 sn-p 中,我做了相反的假设: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 的构造像以前一样进行。