Недавно я обновил свой MySQL-коннектор с 5.1.47 до 8.0.33. После этого я встретил ошибку:
Caused by: java.sql.SQLException: HOUR_OF_DAY: 0 -> 1
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:130) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:98) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:90) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:64) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:74) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:85) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.mysql.cj.jdbc.result.ResultSetImpl.getTimestamp(ResultSetImpl.java:947) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.mysql.cj.jdbc.result.ResultSetImpl.getTimestamp(ResultSetImpl.java:985) ~[mysql-connector-j-8.0.33.jar:8.0.33]
at com.zaxxer.hikari.pool.HikariProxyResultSet.getTimestamp(HikariProxyResultSet.java) ~[HikariCP-4.0.3.jar:na]
at org.hibernate.type.descriptor.sql.TimestampTypeDescriptor$2.doExtract(TimestampTypeDescriptor.java:84) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.type.descriptor.sql.BasicExtractor.extract(BasicExtractor.java:47) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:257) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:253) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.type.AbstractStandardBasicType.nullSafeGet(AbstractStandardBasicType.java:243) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.type.AbstractStandardBasicType.hydrate(AbstractStandardBasicType.java:329) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:3214) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.persister.entity.Loadable.hydrate(Loadable.java:94) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
at org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl.loadFromResultSet(EntityReferenceInitializerImpl.java:342) ~[hibernate-core-5.6.15.Final.jar:5.6.15.Final]
... 113 common frames omitted
Исследуя эту ошибку, я понял, что новый драйвер MySQL выполнит некоторое преобразование, и мой набор данных содержит дату «1916-05-01 00:00 00». Согласно Википедии, первое общенациональное внедрение летнего времени было осуществлено Германской и Австро-Венгерской империями, начиная с 30 апреля 1916 года. Поэтому можно подумать, что оно не может перевести '1916-05-01 00:00 00» к метке времени, поскольку «1916-05-01 00:00 00» «не существует», только «1916-05-01 01:00 00». Я решил узнать все эти «несуществующие» даты в часовом поясе «Европа/Амстердам». Вот как я это сделал:
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Calendar start = Calendar.getInstance();
Calendar end = Calendar.getInstance();
start.setTime(sdf.parse("1900-01-01"));
end.setTime(sdf.parse("2025-01-01"));
List<String> errorItems = new ArrayList<>();
while (!start.after(end)) {
try {
Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("Europe/Amsterdam"), Locale.US);
calendar.setLenient(false);
calendar.set(start.get(Calendar.YEAR), start.get(Calendar.MONTH), start.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
Timestamp ts = new Timestamp(calendar.getTimeInMillis());
System.out.println(ts);
} catch (IllegalArgumentException e) {
errorItems.add(sdf.format(start.getTime()));
}
start.add(Calendar.DAY_OF_YEAR, 1);
}
System.out.println("error date: " + errorItems);
}
Результат: [1914-11-08, 1916-05-01]
«1916-05-01» я уже понял, но почему «1914-11-08»? В 1914 году летнего времени даже не существовало. Есть у кого-нибудь идеи?
Я хотел бы знать, почему я не могу получить временную метку даты «1914-11-08 00:00:00» в часовом поясе «Европа/Амстердам».
Я знаю, что переход на классы java.time может решить эту проблему, но это было бы очень сложно сделать, поскольку это старое приложение, и с этим связана другая логика. Я просто не понимаю, почему это «1914-11-08 00:00:00» нельзя обработать. В 1914 году не было летнего времени, поэтому «1914-11-08 00:00:00» должно быть действительным временем.
«TIMESTAMP» имеет диапазон от «1970-01-01 00:00:01» UTC до «2038-01-19 03:14:07» UTC». - dev.mysql.com/doc/refman/8.0/en/datetime.html вы имели в виду дату и время?
Я имею в виду java.sql.Timestamp. даже если время до '1970-01-01 00:00:01' UTC можно преобразовать в значение java.sql.Timestamp, верно? @P.Salmon
Я воспроизвел. Мой результат error date: [1914-11-08, 1916-05-01].
Моя Java 19 считает, что этот день начался в 1914-11-08T01:00+01:00[Europe/Amsterdam]. timeanddate.com не согласен.
существует не только «летнее время» - из Базы данных часовых поясов данные: «#В начале ноября 1914 года немцы ввели часовой пояс, используемый в центральной # Европе, и заставили жителей установить свои часы и общественные часы# на шестьдесят минут вперед». (соответствующие данные)
Если вы можете решить эту проблему, используя Instant или OffsetDateTime из java.time, я полагаю, что оно того стоит. Это не обязательно означает изменение всего кода даты и времени в исходных файлах Java. Для взаимодействия со старым кодом существуют простые методы преобразования.




Около двух лет назад создатели базы данных часовых поясов IANA решили, что, поскольку в Брюсселе и Амстердаме действуют одинаковые правила часовых поясов, начиная с 1970 года, они «свяжут» Европу/Амстердам с Европой/Брюсселем. Это фактически стерло историю правил часовых поясов до 1970 года для Европы / Амстердама и заменило правила Европы / Брюсселя до 1970 года.
Для Европы/Брюсселя местная дата 1914-11-08 00:00:00 не существует, поскольку в то время местное время было переведено на один час вперед до 1914-11-08 01:00:00. Это изменение не коснулось Амстердама.
Ваше обновление с 5.1.47 до 8.0.33, очевидно, уловило это изменение в базе данных IANA tz.
PS: Если вам не нравится это изменение в базе данных IANA tz, не срывайте это на мне. Я всего лишь посланник.
Можете ли вы вместо этого переключиться на использование новых классов java.time? Те, которые вы используете, полны ошибок и устарели.