Ваше системное время не GMT, это Европа / Лондон (или что-то подобное). В марте лондонское время совпадает с GMT. Не в апреле. Вот почему.
getWorkingHour()
возвращает экземпляр Date
(еще один плохо разработанный и давно устаревший класс, но пусть пока это будет другая история). Когда вы добавляете его к пустой строке, неявно вызывается Date.toString
и строит строку, используя системный часовой пояс. В стандартное время печатается GMT
как сокращение часового пояса. Летнее время (DST) начинается в Лондоне в последнее воскресенье марта, в данном случае 31 марта. Поэтому в апреле Date.toString
на вашей JVM использует British Summer Time и его сокращение, BST
для печати времени.
Хорошее решение включает в себя два изменения:
- Не полагайтесь на часовой пояс JVM по умолчанию. Его можно изменить в любой момент из другой части вашей программы или из другой программы, запущенной в той же JVM, поэтому он слишком хрупок. Вместо этого дайте явный часовой пояс для ваших операций с датой и временем.
- Пропустите старые классы даты и времени
Calendar
и Date
и вместо этого используйте java.time, современный Java-интерфейс даты и времени. С ним гораздо приятнее работать, и он дает гораздо более четкий код, не в последнюю очередь, когда речь идет о преобразованиях между часовыми поясами.
Вместо Calendar
используйте ZonedDateTime
. В зависимости от возможностей вашего драйвера JDBC, преобразуйте его в Instant
или OffsetDateTime
в UTC для сохранения в базе данных.
Чтобы создать ZonedDateTime
, можно использовать один из его методов of
(их несколько):
ZonedDateTime initial = ZonedDateTime.of(2019, 3, 10, 9, 0, 0, 0, ZoneId.of("America/Sao_Paulo"));
Это создает дату и время 10 марта 2019 года в 09:00 в Сан-Паулу. Чтобы добавить к нему 2 часа:
int appointmentDuration = 2;
ZonedDateTime current = initial.plusHours(appointmentDuration);
System.out.println(current);
Выход:
2019-03-10T11: 00-03: 00 [Америка / Sao_Paulo]
Чтобы преобразовать в Instant
для вашей базы данных:
Instant inst = current.toInstant();
System.out.println(inst);
Выход:
2019-03-10T14: 00: 00Z
Инстансы нейтральны по отношению к часовому поясу, только момент времени, но печатаются в UTC. Некоторые драйверы JDBC принимают их для времени UTC. Если у вас этого нет, вам нужно вместо этого дать OffsetDateTime
. Конвертировать так:
OffsetDateTime odt = current.toOffsetDateTime().withOffsetSameInstant(ZoneOffset.UTC);
System.out.println(odt);
Выход:
2019-03-10T14: 00Z
Обратите внимание, что я указываю UTC явно, а не полагаюсь на JVM по умолчанию. Так что это явно в UTC. Вы замечаете, что дата и время совпадают с тем, что было напечатано с Instant
.