Дни различаются по длине
Календарное расписание имеет смысл только в контексте часового пояса и года. Политики часто меняют смещение, используемое часовыми поясами своей юрисдикции. Это означает, что дни не всегда длятся 24 часа. Такие аномалии, как перехода на летнее время (DST), означают, что день может длиться 23 часа, 25 часов. долго или что-то еще, например, 23,5 часа.
Начните сначала, считайте с шагом в 30 минут.
Поэтому, если вы хотите разделить весь год на 30-минутные сегменты, вы должны начать с первого момента первого дня определенного года в определенном часовом поясе и добавлять по 30 минут за раз, пока не достигнете нового год.
ZoneId z = ZoneId.of( "America/Montreal" );
Year year = Year.of( 2021 );
LocalDate firstOfYear = year.atDay( 1 );
ZonedDateTime start = firstOfYear.atStartOfDay( z );
List < ZonedDateTime > zdts = new ArrayList <>();
Duration duration = Duration.ofMinutes( 30 );
ZonedDateTime zdt = start;
while ( zdt.getYear() == year.getValue() )
{
zdts.add( zdt );
// Setup the next loop.
zdt = zdt.plus( duration );
}
Вернуть неизменяемую копию этого списка.
List < ZonedDateTime > slots = List.copyOf( zdts );
Когда бег. Обратите внимание на что происходит в 1 или 2 часа ночи 14 марта 2021 г. и 7 ноября 2021 г.
slots = [2021-01-01T00:00-05:00[Америка/Монреаль], 2021-01-01T00:30-05:00[Америка/Монреаль], 2021-01-01T01:00-05:00[Америка /Монреаль], 2021-01-01T01:30-05:00[Америка/Монреаль], 2021-01-01T02:00-05:00[Америка/Монреаль],
…
2021-03-14T01:00-05:00[Америка/Монреаль], 2021-03-14T01:30-05:00[Америка/Монреаль], 2021-03-14T03:00-04:00[Америка/Монреаль] ,
…
2021-11-07T00:30-04:00[Америка/Монреаль], 2021-11-07T01:00-04:00[Америка/Монреаль], 2021-11-07T01:30-04:00[Америка/Монреаль] , 2021-11-07T01:00-05:00[Америка/Монреаль], 2021-11-07T01:30-05:00[Америка/Монреаль], 2021-11-07T02:00-05:00[Америка/Монреаль ],
…
2021-12-31T22:00-05:00[Америка/Монреаль], 2021-12-31T22:30-05:00[Америка/Монреаль], 2021-12-31T23:00-05:00[Америка/Монреаль] , 2021-12-31T23:30-05:00[Америка/Монреаль]]
Прогнозы на будущее ненадежны!
Но будьте осторожны: политики часто меняют смещение, используемое в зоне! Это происходит гораздо чаще, чем вы, вероятно, думаете. Политики даже ухудшились из-за этого, сократив свое предупреждение с нескольких лет до нескольких месяцев или даже нескольких недель, как это недавно наблюдалось в Турции и Марокко, и даже вообще без предупреждения, как это наблюдается в Северной Корее.
Таким образом, вы не можете надежно прогнозировать будущее, используя описанный выше подход.
Слот математика
Я полагаю, вы могли бы подойти к проблеме временных интервалов по-другому. Подсчитайте таким образом количество целых слотов в течение года.
ZoneId z = ZoneId.of( "America/Montreal" );
Year year = Year.of( 2021 );
LocalDate firstOfYear = year.atDay( 1 );
ZonedDateTime start = firstOfYear.atStartOfDay( z );
ZonedDateTime end = start.plusYears( 1 );
Duration slotLength = Duration.ofMinutes( 30 );
long wholeSlotsInYear = Duration.between( start , end ).dividedBy( slotLength );
Затем вы можете перейти к точке в году, умножив продолжительность и добавив результат к началу года.
int slotNumber = 22;
Duration jump = slotLength.multipliedBy( slotNumber - 1 ); // Subtract one to change an ordinal number into a zero-based index.
ZonedDateTime slot22 = start.plus( jump );
Отслеживание книги назначений
Если вы записываетесь на прием, например, в парикмахерскую или стоматологическую клинику, обычный подход заключается в отслеживании года-месяца-дня в определенное время суток. Но отслеживайте часовой пояс отдельно. Поэтому используйте LocalDateTime
с отдельным ZoneId
в вашей модели Java. В таблице базы данных используйте пару столбцов, один из которых имеет тип, аналогичный стандартному SQL-типу TIMESTAMP WITHOUT TIME ZONE
, а другой столбец текстового типа, содержащий имя часового пояса, например America/Montreal
или Africa/Tunis
.
При построении графика применяйте зону для определения момента. В Java это означает применение ZoneId
к LocalDateTime
для получения ZonedDateTime
.
Вам нужно четко усвоить основную идею о том, что LocalDateTime
объект не представляет момент. В нашем примере 15:00 23 числа следующего года может означать 15:00 в Токио, Япония, или 15:00 в Толедо, штат Огайо, США, два совершенно разных момента с разницей в несколько часов. LocalDateTime
по своей сути неоднозначен. Таким образом, необходимо также хранить часовой пояс, но отдельно.
LocalDateTime ldt = LocalDateTime.of( 2021 , 1 , 23 , 15 , 0 , 0 , 0 ) ;
ZoneId z = ZoneId.of( "America/Montreal" ) ;
ZonedDateTime zdt = ldt.atZone( z ) ; // Determine a moment.
Посмотрите тот же момент в формате UTC, извлекая файл Instant
.
Instant instant = zdt.toInstant() ;
person
Basil Bourque
schedule
16.06.2020