Текущото състояние на нещата във времето

От времето, когато JDBC е изобретен и неговите интерфейси са стандартизирани, са изминали 20 години и през това време много неща са се променor.

Първо, светът стана глобален и сега един сървър може да обслужва потребители от цял ​​свят. Скоростта на интернет се повиши. Следователно към SQL беше добавен друг тип данни за работа с времето. Сега типовете изглеждат така:

  • ДАТА - съхранява датата: година, месец, ден.
  • ВРЕМЕ - съхранява време: часове, minutesи, секунди.
  • TIMESTAMP - съхранява конкретна точка от времето: дата, час и мorсекунди.
  • TIMESTAMP WITH TIME ZONE - TIMESTAMP и часова зона (име на зона or отместване).

Второ, Java представи DateTime API за глобално управление на времето. Има следните класове:

  • Дата и час :
    • Местна дата
    • Местно време
  • Точен момент :
    • java.time.Instant
    • java.time.LocalDateTime
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime
  • Време с часова зона :
    • java.time.OffsetDateTime
    • java.time.ZonedDateTime

Третият интересен момент е, че много SQL клиенти биха искали да получават време от сървъра, който вече е в тяхната локална зона . Разбира се, можете да конвертирате времето в движение, но не е удобно и има грешки.

Например, искам да взема всички задачи за днес от базата данни. SQL Server има функция CURDATE() за това. Само тук сървърът е в САЩ, а аз съм в Япония. И бих искал той да върне всички записи за „моето днес“, а не „неговото днес“.

Като цяло, SQL сървърът също трябва да може да работи интелигентно с клиенти в различни часови зони.

Съвременните проблеми изискват модерни решения

По принцип новите типове от Java DateTime API и типовете от SQL могат да бъдат удобно картографирани. За да представите типа DATE в Java, трябва да използвате класа java.time.LocalDate от JDK 8 DateTime API.

Типът TIME от базата данни може да бъде представен от два типа от Java: java.time.LocalTime и java.time.OffsetTime . Нищо сложно също.

Конкретен момент от време, представен от типа TIMESTAMP в базата данни, може да бъде представен в Java чрез 4 типа:

  • java.time.Instant
  • java.time.LocalDateTime
  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

И накрая, TIMESTAMP WITH TIME ZONE може да бъде представен от два типа:

  • java.time.OffsetDateTime
  • java.time.ZonedDateTime

Тъй като вече сте запознати с API на DateTime, запомнянето на този въпрос няма да е трудно за вас :)

Ще го напиша под формата на table, така че ще бъде по-лесно:

SQL ТИП Тип Java
ДАТА java.time.LocalDate
ВРЕМЕ java.time.LocalTime
java.time.OffsetTime
КЛАПОТО ЗА ЧАС java.time.Instant
java.time.LocalDateTime
java.time.OffsetDateTime
java.time.ZonedDateTime
ЧАСОВ ПЕЧАТ С ЧАСОВА ЗОНА java.time.OffsetDateTime
_

Получаване на датата

Имам добра новина за вас. Първо от много време. Можем да заобиколим ограничението на метода getDate() , който връща java.sql тип Дата.

Въпросът е, че обектътнабор от резултатиима още един интересен метод - getObject() . Този метод приема два параметъра: колона и тип и връща стойността на колоната, преобразувана в дадения тип. Общата форма на метода е следната:

ClassName Name = getObject(column, ClassName);

И ако искате да конвертирате типа DATE в типа java.time.LocalDate , тогава трябва да напишете нещо като:

LocalDate localDate = results.getObject(4, LocalDate.class);

И всеки TIMESTAMP като цяло може да бъде преобразуван в куп типове:

java.time.Instant instant = results.getObject(9, java.time.Instant.class);
java.time.LocalDateTime local = results.getObject(9, java.time. LocalDateTime.class);
java.time.OffsetDateTime offset = results.getObject(9, java.time. OffsetDateTime.class);
java.time.ZonedDateTime zoned = results.getObject(9, java.time. ZonedDateTime.class);

важно! Този code няма да работи, ако имате остарял MySQL JDBC драйвер . Обърнете внимание на versionта на "mysql-connector-java", написана във вашия pom.xml or добавена към библиотеките в настройките на проекта.

Между другото, по същия начин можете да заобиколите невъзможността да съхранявате null за примитивни типове. Ако колона на table е от тип INT, тогава има няколко начина да получите нула от нея. Вижте примера по-долу:

Integer id1 = results.getObject(8, Integer.class);    	 // this will work
Integer id2 = results.getObject(8, int.class);                 //this will also work
int id3 = results.getObject(8,  Integer.class);            	//method will return null, JVM will throw NPE
int id4 = results.getObject(8,  int.class);                    	//method will return null, JVM will throw NPE

Настройка на часовата зона в MySQL

С MySQL също се случиха много интересни неща. Както знаете, когато създавате MySQL връзка, можете да добавите различни параметри към нея :
mysql://localhost:3306/db_scheme?Name=meaning&Name=meaning

И така, добавени са три параметъра за работа с часови зони в MySQL. Можете да подадете тези параметри, когато установите връзка със сървъра.

По-долу ще дам table с тях:

Параметър Стойности Стойност по подразбиране
връзка TimeZone МЕСТЕН ​​| СЪРВЪР | потребителска зона СЪРВЪР
forceConnectionTimeZoneToSession вярно | невярно вярно
SaveInstants вярно | невярно невярно

С помощта на параметъра connectionTimeZone избираме часовата зона (часова зона), в която ще се изпълняват всички заявки. От гледна точка на клиента, сървърът работи в определената часова зона.

Параметърът forceConnectionTimeZoneToSession кара променливата time_zone на сесията да бъде игнорирана и заменена с connectionTimeZone.

И накрая, параметърът SaveInstants контролира преобразуването на точното време между timeZone на JVM и connectionTimeZone.

Най-често срещаните конфигурации са:

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=false - съответства на стария MySQL JDBC драйвер version 5.1 с useLegacyDatetimeCode=true.

  • connectionTimeZone=LOCAL & forceConnectionTimeZoneToSession=true е нов режим, който осигурява най-естествения начин за обработка на стойностите за дата и час.

  • connectionTimeZone=SERVER & SaveInstants=true - Съответства на стария MySQL JDBC драйвер version 5.1 с useLegacyDatetimeCode=false.

  • connectionTimeZone=user_defined & SaveInstants=true - Помага за преодоляване на ситуацията, при която часовата зона на сървъра не може да бъде разпозната от конектора, тъй като е зададена като общо съкращение като CET/CEST.

Да, датите са интересна тема и има много проблеми с тях. Както се казва: страшно е, разбира се, но и аз не се сърдя! :)