Работа с полуднем и полуночью

В API Js-joda отсутствуют специальные типы для представления понятий «полдень» и «полночь». Эти значения моделируются через стандартные классы времени: LocalTime, LocalDateTime, ZonedDateTime и связанные типы. Несмотря на внешнюю простоту, работа с такими моментами времени содержит множество нюансов, связанных с переходом суток, часовыми поясами, сравнением дат и сериализацией.


Представление полуночи

Полночь соответствует началу суток и представляется временем 00:00.

const { LocalTime } = require('@js-joda/core');

const midnight = LocalTime.MIDNIGHT;

console.log(midnight.toString());
// 00:00

Эквивалентное создание через фабричный метод:

const midnight = LocalTime.of(0, 0);

Также допустим разбор строки:

const midnight = LocalTime.parse('00:00');

Особенности полуночи

Полночь относится уже к новым суткам.

Например:

const { LocalDateTime, LocalDate, LocalTime } = require('@js-joda/core');

const date = LocalDate.of(2025, 5, 10);

const startOfDay = LocalDateTime.of(date, LocalTime.MIDNIGHT);

console.log(startOfDay.toString());
// 2025-05-10T00:00

Здесь 00:00 принадлежит именно 2025-05-10, а не предыдущему дню.


Представление полудня

Полдень соответствует времени 12:00.

const { LocalTime } = require('@js-joda/core');

const noon = LocalTime.NOON;

console.log(noon.toString());
// 12:00

Создание вручную:

const noon = LocalTime.of(12, 0);

Разбор строки:

const noon = LocalTime.parse('12:00');

Константы MIDNIGHT и NOON

Класс LocalTime содержит готовые константы:

Константа Значение
LocalTime.MIDNIGHT 00:00
LocalTime.NOON 12:00

Использование констант делает код более читаемым:

const meetingStart = LocalTime.NOON;
const resetTime = LocalTime.MIDNIGHT;

Начало суток через atStartOfDay()

Для получения полуночи конкретной даты используется метод atStartOfDay().

const { LocalDate } = require('@js-joda/core');

const date = LocalDate.of(2025, 8, 20);

const start = date.atStartOfDay();

console.log(start.toString());
// 2025-08-20T00:00

Метод возвращает объект LocalDateTime.


Получение конца дня

В Js-joda нет специальной константы «конец суток». Обычно используется время 23:59:59.999999999.

const { LocalTime } = require('@js-joda/core');

const endOfDay = LocalTime.of(23, 59, 59, 999999999);

console.log(endOfDay.toString());
// 23:59:59.999999999

Важно понимать разницу:

  • 00:00 — начало новых суток
  • 23:59:59.999999999 — последний наносекундный момент текущих суток

Проверка на полночь и полдень

Проверка полуночи

const { LocalTime } = require('@js-joda/core');

const time = LocalTime.parse('00:00');

const isMidnight = time.equals(LocalTime.MIDNIGHT);

console.log(isMidnight);
// true

Проверка полудня

const { LocalTime } = require('@js-joda/core');

const time = LocalTime.parse('12:00');

const isNoon = time.equals(LocalTime.NOON);

console.log(isNoon);
// true

Сравнение времени с полуднем

Полдень часто используется как разделитель первой и второй половины дня.

const { LocalTime } = require('@js-joda/core');

const time = LocalTime.parse('15:30');

console.log(time.isAfter(LocalTime.NOON));
// true

Пример проверки:

if (time.isBefore(LocalTime.NOON)) {
    console.log('До полудня');
} else {
    console.log('После полудня');
}

Работа с 12-часовым форматом

Полдень и полночь вызывают наибольшее количество ошибок именно при использовании AM/PM.

Полночь

Формат Значение
00:00 24-часовой
12:00 AM 12-часовой

Полдень

Формат Значение
12:00 24-часовой
12:00 PM 12-часовой

Форматирование полудня и полуночи

const {
    LocalTime,
    DateTimeFormatter
} = require('@js-joda/core');

const formatter = DateTimeFormatter.ofPattern('hh:mm a');

console.log(LocalTime.MIDNIGHT.format(formatter));
// 12:00 AM

console.log(LocalTime.NOON.format(formatter));
// 12:00 PM

Парсинг AM/PM времени

const {
    LocalTime,
    DateTimeFormatter
} = require('@js-joda/core');

const formatter = DateTimeFormatter.ofPattern('hh:mm a');

const midnight = LocalTime.parse('12:00 AM', formatter);
const noon = LocalTime.parse('12:00 PM', formatter);

console.log(midnight.toString());
// 00:00

console.log(noon.toString());
// 12:00

Добавление часов к полуночи

const { LocalTime } = require('@js-joda/core');

const midnight = LocalTime.MIDNIGHT;

console.log(midnight.plusHours(5).toString());
// 05:00

Добавление часов к полудню

const { LocalTime } = require('@js-joda/core');

const noon = LocalTime.NOON;

console.log(noon.plusHours(3).toString());
// 15:00

Переход через полночь

Одной из ключевых особенностей времени является циклический характер суток.

const { LocalTime } = require('@js-joda/core');

const time = LocalTime.of(23, 30);

const result = time.plusHours(2);

console.log(result.toString());
// 01:30

Дата при этом не изменяется, поскольку LocalTime не содержит информации о календарном дне.


Корректная работа с переходом суток

Если важна дата, необходимо использовать LocalDateTime.

const { LocalDateTime } = require('@js-joda/core');

const dateTime = LocalDateTime.parse('2025-05-10T23:30');

const result = dateTime.plusHours(2);

console.log(result.toString());
// 2025-05-11T01:30

Здесь уже происходит переход на следующий день.


Полночь в ZonedDateTime

При работе с часовыми поясами полночь может вести себя неожиданно из-за переходов летнего времени.

const {
    ZonedDateTime,
    ZoneId
} = require('@js-joda/core');

const zone = ZoneId.of('Europe/Berlin');

const dateTime = ZonedDateTime.parse(
    '2025-05-10T00:00+02:00[Europe/Berlin]'
);

console.log(dateTime.toString());

Проблемы полуночи при DST

В некоторых часовых поясах переход летнего времени может:

  • пропускать определённые моменты времени;
  • создавать повторяющиеся часы;
  • смещать локальную полночь.

Пример:

const {
    LocalDate,
    ZoneId
} = require('@js-joda/core');

const zone = ZoneId.of('America/Sao_Paulo');

const date = LocalDate.of(2018, 11, 4);

const start = date.atStartOfDay(zone);

console.log(start.toString());

Во время DST реальное начало суток может быть не 00:00.


Использование atStartOfDay(zone)

Метод учитывает правила временной зоны.

const {
    LocalDate,
    ZoneId
} = require('@js-joda/core');

const zone = ZoneId.of('Asia/Tokyo');

const result = LocalDate
    .of(2025, 1, 1)
    .atStartOfDay(zone);

console.log(result.toString());

Возвращается ZonedDateTime.


Разница между MIDNIGHT и MIN

В LocalTime существует также константа MIN.

console.log(LocalTime.MIN.toString());
// 00:00

Она эквивалентна полуночи:

console.log(LocalTime.MIN.equals(LocalTime.MIDNIGHT));
// true

Но семантически они отличаются:

Константа Смысл
MIDNIGHT Полночь
MIN Минимально возможное время

Разница между NOON и 12:00

Технически это одинаковые значения:

console.log(
    LocalTime.NOON.equals(LocalTime.of(12, 0))
);
// true

Однако использование NOON повышает читаемость кода:

const lunchTime = LocalTime.NOON;

Проверка диапазонов относительно полуночи

Частая ошибка — неправильная проверка ночного интервала.

Неверный вариант:

if (time.isAfter(start) && time.isBefore(end))

Если диапазон проходит через полночь, логика ломается.

Правильный вариант

const { LocalTime } = require('@js-joda/core');

const start = LocalTime.of(22, 0);
const end = LocalTime.of(6, 0);

const time = LocalTime.of(1, 30);

const isNight =
    time.isAfter(start) || time.isBefore(end);

console.log(isNight);
// true

Полночь как граница периода

Во многих системах сутки заканчиваются ровно в полночь.

const {
    LocalDate,
    LocalDateTime,
    LocalTime
} = require('@js-joda/core');

const nextDay = LocalDate.of(2025, 6, 1);

const boundary = LocalDateTime.of(
    nextDay,
    LocalTime.MIDNIGHT
);

console.log(boundary.toString());
// 2025-06-01T00:00

Работа с Duration

Время до полуночи

const {
    LocalTime,
    Duration
} = require('@js-joda/core');

const now = LocalTime.of(20, 15);

const untilMidnight = Duration.between(
    now,
    LocalTime.MIDNIGHT.plusHours(24)
);

console.log(untilMidnight.toHours());
// 3

Количество часов после полуночи

const {
    LocalTime,
    ChronoUnit
} = require('@js-joda/core');

const time = LocalTime.of(8, 45);

const hours = ChronoUnit.HOURS.between(
    LocalTime.MIDNIGHT,
    time
);

console.log(hours);
// 8

Использование полуночи в расписаниях

const { LocalTime } = require('@js-joda/core');

const backupTime = LocalTime.MIDNIGHT;

console.log(`Резервное копирование: ${backupTime}`);

Использование полудня в бизнес-логике

const { LocalTime } = require('@js-joda/core');

function isMorning(time) {
    return time.isBefore(LocalTime.NOON);
}

console.log(
    isMorning(LocalTime.of(9, 0))
);
// true

Сериализация времени

JSON

const { LocalTime } = require('@js-joda/core');

const time = LocalTime.NOON;

const json = JSON.stringify({
    time: time.toString()
});

console.log(json);
// {"time":"12:00"}

Восстановление

const parsed = JSON.parse(json);

const restored = LocalTime.parse(parsed.time);

console.log(restored.equals(LocalTime.NOON));
// true

Типичные ошибки

Ошибка с 12 AM и 12 PM

Неверная интерпретация:

Значение Реальное время
12:00 AM Полночь
12:00 PM Полдень

Использование LocalTime для перехода суток

const result = LocalTime.of(23, 0).plusHours(2);

console.log(result.toString());
// 01:00

Дата теряется.


Использование 24:00

Строка 24:00 не является допустимым временем в LocalTime.

Неверно:

LocalTime.parse('24:00');

Правильно:

LocalTime.MIDNIGHT

или:

LocalDate
    .of(2025, 5, 10)
    .plusDays(1)
    .atStartOfDay();

Практический пример: ночная смена

const { LocalTime } = require('@js-joda/core');

function isNightShift(time) {
    const start = LocalTime.of(22, 0);
    const end = LocalTime.of(6, 0);

    return time.equals(start)
        || time.isAfter(start)
        || time.isBefore(end);
}

console.log(
    isNightShift(LocalTime.of(1, 15))
);
// true

Практический пример: разделение дня

const { LocalTime } = require('@js-joda/core');

function getDayPeriod(time) {
    if (time.equals(LocalTime.MIDNIGHT)) {
        return 'Полночь';
    }

    if (time.equals(LocalTime.NOON)) {
        return 'Полдень';
    }

    if (time.isBefore(LocalTime.NOON)) {
        return 'Первая половина дня';
    }

    return 'Вторая половина дня';
}