Юлианский календарь — историческая календарная система, введённая Юлием Цезарем в 45 году до н. э. В отличие от современного григорианского календаря, юлианский использует более простое правило високосных лет: каждый четвёртый год считается високосным без исключений. Из-за накопления ошибки в продолжительности года юлианский календарь постепенно смещается относительно астрономического времени.
Библиотека Luxon напрямую не предоставляет полноценного API для работы с юлианским календарём как альтернативной календарной системой. Однако Luxon поддерживает:
Понимание различий между юлианским календарём, юлианским днём и григорианским календарём особенно важно при разработке:
В программировании часто путают два разных понятия:
| Термин | Описание |
|---|---|
| Юлианский календарь | Историческая календарная система |
| Julian Day (JD) | Непрерывный счёт дней, используемый в астрономии |
Luxon работает именно с Julian Day Number, а не с юлианским календарём как системой отображения дат.
Класс DateTime содержит методы для преобразования даты в
юлианский день.
import { DateTime } from "luxon";
const date = DateTime.local(2025, 5, 24);
console.log(date.toJulianDay());
Результат:
2460820.5
Значение представляет количество дней, прошедших с начала юлианской эпохи.
Юлианский день — это непрерывная шкала времени, используемая в астрономии.
Начальная точка:
Это позволяет выполнять вычисления дат без учёта:
Luxon поддерживает создание объекта DateTime из
юлианского дня.
import { DateTime } from "luxon";
const dt = DateTime.fromJulianDay(2460820.5);
console.log(dt.toISO());
Результат:
2025-05-24T00:00:00.000Z
Julian Day хранится как число с плавающей точкой.
Целая часть:
Дробная часть:
Пример:
import { DateTime } from "luxon";
const dt = DateTime.utc(2025, 5, 24, 18, 0);
console.log(dt.toJulianDay());
Результат:
2460821.25
Здесь:
.25 соответствует 6 часам после полудня UTC.Главная сложность при работе с историческими датами — календарная реформа.
В разных странах переход происходил в разное время:
| Страна | Год перехода |
|---|---|
| Италия | 1582 |
| Франция | 1582 |
| Англия | 1752 |
| Россия | 1918 |
Luxon использует проleptic Gregorian calendar — расширенный григорианский календарь на все даты.
Это означает:
import { DateTime } from "luxon";
const dt = DateTime.fromISO("1500-01-01");
console.log(dt.toISODate());
Дата интерпретируется как григорианская, хотя исторически в тот период использовался юлианский календарь.
Luxon не выполняет автоматическую реконструкцию исторических календарных систем.
Например:
DateTime.fromISO("1000-01-01")
не означает реальную дату по юлианскому календарю X века.
Для исторически точных вычислений обычно используются:
Разница между календарями постепенно увеличивается.
| Период | Разница |
|---|---|
| 1582 | 10 дней |
| 1700 | 11 дней |
| 1800 | 12 дней |
| 1900 | 13 дней |
| 2100 | 14 дней |
Иногда требуется вручную переводить дату из юлианского календаря.
Дата:
1 января 1900 года (юлианский)
Соответствует:
13 января 1900 года (григорианский)
В Luxon это можно реализовать вручную:
import { DateTime } from "luxon";
const julianDate = DateTime.fromISO("1900-01-01");
const gregorianEquivalent = julianDate.plus({ days: 13 });
console.log(gregorianEquivalent.toISODate());
import { DateTime } from "luxon";
function julianToGregorian(date, offsetDays) {
return date.plus({ days: offsetDays });
}
const julian = DateTime.fromISO("1900-01-01");
const gregorian = julianToGregorian(julian, 13);
console.log(gregorian.toISODate());
Можно реализовать функцию вычисления разницы между календарями.
function getJulianOffset(year) {
if (year >= 2100) return 14;
if (year >= 1900) return 13;
if (year >= 1800) return 12;
if (year >= 1700) return 11;
return 10;
}
Использование:
import { DateTime } from "luxon";
const year = 1850;
const offset = getJulianOffset(year);
const julian = DateTime.fromObject({
year,
month: 5,
day: 1
});
const gregorian = julian.plus({
days: offset
});
console.log(gregorian.toISODate());
Luxon поддерживает очень ранние даты.
import { DateTime } from "luxon";
const ancient = DateTime.fromObject({
year: -44,
month: 3,
day: 15
});
console.log(ancient.toISODate());
Результат:
-0044-03-15
Это дата убийства Юлия Цезаря.
Luxon использует астрономическую нумерацию лет:
| Исторический год | Luxon |
|---|---|
| 1 до н. э. | 0 |
| 2 до н. э. | -1 |
| 44 до н. э. | -43 |
Это важно учитывать при исторических вычислениях.
Юлианский день зависит от UTC.
Пример:
import { DateTime } from "luxon";
const local = DateTime.local();
const utc = local.toUTC();
console.log(local.toJulianDay());
console.log(utc.toJulianDay());
При преобразовании временной зоны меняется дробная часть числа.
Для корректных вычислений Julian Day рекомендуется использовать UTC.
import { DateTime } from "luxon";
const dt = DateTime.utc(2025, 5, 24, 0, 0);
console.log(dt.toJulianDay());
В научных системах часто используется MJD (Modified Julian Day).
Формула:
MJD = JD - 2400000.5
Пример:
import { DateTime } from "luxon";
const jd = DateTime.utc().toJulianDay();
const mjd = jd - 2400000.5;
console.log(mjd);
Julian Day удобен для точных расчётов промежутков.
import { DateTime } from "luxon";
const start = DateTime.utc(2025, 1, 1);
const end = DateTime.utc(2025, 12, 31);
const diff =
end.toJulianDay() - start.toJulianDay();
console.log(diff);
import { DateTime } from "luxon";
const d1 = DateTime.fromISO("1582-10-04");
const d2 = DateTime.fromISO("1582-10-15");
console.log(d2.diff(d1, "days").days);
Luxon считает даты непрерывно без пропуска календарной реформы.
Julian Day широко применяется:
Luxon удобен как вспомогательный инструмент обработки временных данных.
Luxon не поддерживает:
calendar: "julian"Нет автоматического учёта:
Luxon ориентирован на современные вычисления времени, а не на академическую хронологию.
Для сложной работы с юлианским календарём Luxon часто комбинируют с:
import { DateTime } from "luxon";
function convertJulianToGregorian(
year,
month,
day
) {
const offset = getJulianOffset(year);
return DateTime.fromObject({
year,
month,
day
}).plus({
days: offset
});
}
function getJulianOffset(year) {
if (year >= 2100) return 14;
if (year >= 1900) return 13;
if (year >= 1800) return 12;
if (year >= 1700) return 11;
return 10;
}
const result =
convertJulianToGregorian(1900, 1, 1);
console.log(result.toISODate());
Правило юлианского календаря:
year = 0
Реализация:
function isJulianLeapYear(year) {
return year % 4 === 0;
}
console.log(isJulianLeapYear(1900));
Результат:
true
В григорианском календаре 1900 год не является високосным.
year % 4 === 0
(year % 4 === 0 && year % 100 !== 0)
|| year % 400 === 0
Средняя длина юлианского года:
365.25
Реальная длина тропического года:
365.2422
Разница:
365.25 - 365.2422 = 0.0078
Из-за этого календарь смещается примерно на 1 день каждые 128 лет.
Типичные сценарии:
const archivedDate =
DateTime.fromISO("1789-07-14");
const battleDate =
DateTime.fromObject({
year: 1242,
month: 4,
day: 5
});
const jd =
DateTime.utc().toJulianDay();
При работе с историческими датами рекомендуется:
Операции с юлианским днём выполняются быстро, поскольку основаны на арифметике чисел.
import { DateTime } from "luxon";
const jd1 = DateTime.utc(2000, 1, 1)
.toJulianDay();
const jd2 = DateTime.utc(2025, 1, 1)
.toJulianDay();
console.log(jd2 - jd1);
Такой подход особенно эффективен в: