Duration для временных интервалов

Класс Duration из библиотеки js-joda предназначен для работы с временными интервалами, измеряемыми в секундах и наносекундах. В отличие от календарных сущностей (Period, LocalDate, YearMonth), Duration оперирует точным количеством времени.

Duration используется в сценариях:

  • измерение времени выполнения операций;
  • интервалы между событиями;
  • таймауты;
  • задержки;
  • арифметика времени;
  • вычисление разницы между моментами времени;
  • работа с часовыми поясами и UTC-временем.

Duration является неизменяемым объектом (immutable). Любая операция создаёт новый экземпляр.


Подключение

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

Для ES-модулей:

import { Duration } from '@js-joda/core';

Создание Duration

Интервал в секундах

const duration = Duration.ofSeconds(120);

console.log(duration.toString());

Результат:

PT2M

Формат PT2M соответствует стандарту ISO-8601:

  • P — период;
  • T — начало временной части;
  • 2M — две минуты.

Интервал в минутах

const duration = Duration.ofMinutes(15);

Интервал в часах

const duration = Duration.ofHours(5);

Интервал в днях

const duration = Duration.ofDays(2);

Важно понимать: один день в Duration всегда равен ровно 24 часам.

Duration.ofDays(1)

эквивалентно:

Duration.ofHours(24)

Интервал в миллисекундах

const duration = Duration.ofMillis(1500);

Интервал в наносекундах

const duration = Duration.ofNanos(500000000);

Создание через parse

Duration поддерживает ISO-8601 строковый формат.

const duration = Duration.parse('PT2H30M');

Значение:

  • 2H — два часа;
  • 30M — тридцать минут.

Примеры ISO-8601

Строка Значение
PT20S 20 секунд
PT15M 15 минут
PT10H 10 часов
P2DT3H 2 дня и 3 часа
PT0.5S полсекунды

Получение компонентов

Секунды

const duration = Duration.ofMinutes(2);

console.log(duration.seconds());

Результат:

120

Наносекунды

const duration = Duration.ofSeconds(1, 500000000);

console.log(duration.nano());

Результат:

500000000

Создание через between

Метод between вычисляет разницу между двумя временными объектами.

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

const start = LocalTime.parse('10:00');
const end = LocalTime.parse('12:45');

const duration = Duration.between(start, end);

console.log(duration.toString());

Результат:

PT2H45M

Разница между Period и Duration

Duration

Работает с:

  • секундами;
  • миллисекундами;
  • наносекундами;
  • часами;
  • минутами.

Основан на точном времени.


Period

Работает с:

  • годами;
  • месяцами;
  • днями.

Основан на календарной модели.


Пример различия

Duration.ofDays(1)

всегда:

24 часа

Но:

Period.ofDays(1)

может означать календарный день с переходом:

  • на летнее время;
  • зимнее время;
  • через смену часового пояса.

Арифметические операции

Добавление

const duration =
    Duration.ofHours(2)
        .plusMinutes(30);

console.log(duration.toString());

Результат:

PT2H30M

Вычитание

const duration =
    Duration.ofHours(5)
        .minusHours(2);

console.log(duration.toString());

Результат:

PT3H

Умножение

const duration =
    Duration.ofMinutes(10)
        .multipliedBy(3);

console.log(duration.toString());

Результат:

PT30M

Деление

const duration =
    Duration.ofHours(4)
        .dividedBy(2);

console.log(duration.toString());

Результат:

PT2H

Отрицательные интервалы

const duration =
    Duration.ofMinutes(10)
        .minusMinutes(20);

console.log(duration.toString());

Результат:

PT-10M

Проверка знака

Положительный интервал

duration.isNegative()

Нулевой интервал

duration.isZero()

Пример

const duration = Duration.ofSeconds(0);

console.log(duration.isZero());

Результат:

true

Абсолютное значение

const duration = Duration.ofMinutes(-30);

console.log(duration.abs().toString());

Результат:

PT30M

Работа с LocalDateTime

Добавление интервала

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

const dateTime =
    LocalDateTime.parse('2025-01-10T12:00');

const result =
    dateTime.plus(Duration.ofHours(5));

console.log(result.toString());

Результат:

2025-01-10T17:00

Вычитание интервала

const result =
    dateTime.minus(Duration.ofMinutes(90));

Работа с Instant

Instant особенно часто используется вместе с Duration.

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

const start = Instant.now();

// операция

const end = Instant.now();

const executionTime =
    Duration.between(start, end);

console.log(executionTime.toMillis());

Конвертация значений

В миллисекунды

duration.toMillis()

В наносекунды

duration.toNanos()

Пример

const duration = Duration.ofSeconds(2);

console.log(duration.toMillis());

Результат:

2000

Сравнение интервалов

compareTo

const d1 = Duration.ofMinutes(10);
const d2 = Duration.ofMinutes(20);

console.log(d1.compareTo(d2));

Результат:

-1

Проверка равенства

d1.equals(d2)

Нормализация значений

При создании Duration библиотека автоматически нормализует данные.

const duration =
    Duration.ofSeconds(90);

console.log(duration.toString());

Результат:

PT1M30S

Наносекундная точность

Duration хранит:

  • секунды;
  • наносекундную часть.

Это позволяет получать очень высокую точность вычислений.

const duration =
    Duration.ofSeconds(1, 1);

console.log(duration.nano());

Результат:

1

Использование в таймерах

Таймаут

const timeout =
    Duration.ofSeconds(30);

Интервал опроса

const polling =
    Duration.ofMillis(500);

Измерение времени выполнения

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

const start = Instant.now();

for (let i = 0; i < 1000000; i++) {
    Math.sqrt(i);
}

const end = Instant.now();

const elapsed =
    Duration.between(start, end);

console.log(elapsed.toMillis());

Работа с дробными секундами

const duration =
    Duration.parse('PT1.5S');

console.log(duration.toMillis());

Результат:

1500

Использование с часовыми поясами

Duration не содержит информации о часовом поясе.

Он представляет только физический промежуток времени.

const duration = Duration.ofHours(1);

Этот интервал всегда равен:

3600 секунд

независимо от:

  • UTC;
  • GMT;
  • DST;
  • локального времени.

Переполнение значений

Очень большие интервалы могут вызывать переполнение.

Duration.ofSeconds(Number.MAX_SAFE_INTEGER)

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


Часто используемые методы

Метод Назначение
ofSeconds() создание из секунд
ofMinutes() создание из минут
ofHours() создание из часов
ofDays() создание из дней
parse() создание из ISO-8601
between() разница между моментами
plus() добавление
minus() вычитание
multipliedBy() умножение
dividedBy() деление
toMillis() миллисекунды
toNanos() наносекунды
isZero() проверка на ноль
isNegative() проверка знака
abs() модуль

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

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

const issuedAt = Instant.now();

const ttl = Duration.ofMinutes(15);

const expiresAt = issuedAt.plus(ttl);

console.log(expiresAt.toString());

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

const now = Instant.now();

const expired =
    now.isAfter(expiresAt);

console.log(expired);

Практический пример: ограничение скорости запросов

const interval =
    Duration.ofSeconds(1);

const lastRequest =
    Instant.now();

const nextAllowed =
    lastRequest.plus(interval);

Практический пример: задержка повторной попытки

const retryDelay =
    Duration.ofSeconds(5);

const retryTime =
    Instant.now().plus(retryDelay);

Особенности ISO-8601 представления

Duration.ofMinutes(90).toString()

Результат:

PT1H30M

Интервал с днями

Duration.ofDays(3).toString()

Результат:

PT72H

Важно: Duration хранит дни как часы, а не как календарные сутки.


Отличия от стандартного Date

Date

  • изменяемый объект;
  • слабая поддержка интервалов;
  • привязка к часовому поясу;
  • сложность вычислений.

Duration

  • неизменяемость;
  • точная временная модель;
  • наносекундная точность;
  • безопасная арифметика;
  • ISO-8601 совместимость.

Совместное использование с ZonedDateTime

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

const zoned =
    ZonedDateTime.now(
        ZoneId.of('Europe/Moscow')
    );

const future =
    zoned.plus(Duration.ofHours(3));

console.log(future.toString());

Проверка длительности операции

const start = Instant.now();

// операция

const duration =
    Duration.between(
        start,
        Instant.now()
    );

if (duration.toMillis() > 1000) {
    console.log('Слишком долго');
}

Внутреннее устройство

Duration хранит:

  • поле секунд;
  • поле наносекунд.

Структура аналогична Java API java.time.Duration, на основе которого построен js-joda.


Когда использовать Duration

Duration подходит для:

  • таймеров;
  • интервалов ожидания;
  • сетевых таймаутов;
  • измерения производительности;
  • интервалов между событиями;
  • работы с UTC;
  • серверного времени;
  • TTL и expiration logic;
  • scheduler-систем;
  • cron-логики;
  • rate limiting.

Когда Duration использовать не следует

Duration плохо подходит для:

  • календарных месяцев;
  • годов;
  • бизнес-календарей;
  • банковских периодов;
  • вычислений «через месяц»;
  • операций с рабочими днями.

Для таких задач используется Period.