Работа с астрономическим временем — одна из сложных задач при разработке календарей, систем навигации, приложений для астрономии, погодных сервисов и геолокационных платформ. Библиотека Luxon не содержит встроенных средств вычисления солнечного и лунного времени, однако предоставляет мощный API для работы с часовыми поясами, интервалами времени, локалями и высокоточной обработкой дат. Благодаря этому Luxon удобно использовать совместно со специализированными астрономическими библиотеками.
Солнечное время определяется положением Солнца относительно конкретной точки на поверхности Земли. В прикладной разработке чаще всего используются:
В отличие от стандартного гражданского времени, солнечное зависит от:
Luxon особенно полезен именно на этапе обработки этих данных.
npm install luxon
Подключение:
import { DateTime } from "luxon";
Главный объект библиотеки — DateTime.
Создание даты:
const dt = DateTime.now();
console.log(dt.toISO());
Дата с часовым поясом:
const dt = DateTime.now().setZone("Asia/Almaty");
console.log(dt.toString());
Luxon использует стандарт IANA Time Zone Database, поэтому корректно обрабатывает:
Для вычисления солнечного времени Luxon обычно объединяют с библиотекой SunCalc.
Установка:
npm install suncalc
Подключение:
import { DateTime } from "luxon";
import SunCalc from "suncalc";
Пример вычисления:
const latitude = 49.8028;
const longitude = 73.0877;
const date = new Date();
const times = SunCalc.getTimes(date, latitude, longitude);
console.log(times.sunrise);
console.log(times.sunset);
SunCalc возвращает обычные объекты Date. Для дальнейшей
обработки удобно преобразовать их в DateTime.
const sunrise = DateTime.fromJSDate(times.sunrise)
.setZone("Asia/Almaty");
const sunset = DateTime.fromJSDate(times.sunset)
.setZone("Asia/Almaty");
console.log(sunrise.toFormat("HH:mm"));
console.log(sunset.toFormat("HH:mm"));
Астрономические вычисления всегда чувствительны к часовому поясу.
Пример:
const sunriseUtc = DateTime.fromJSDate(times.sunrise, {
zone: "utc"
});
const localSunrise = sunriseUtc.setZone("Asia/Almaty");
console.log(localSunrise.toString());
Luxon автоматически:
Luxon предоставляет гибкое форматирование.
console.log(sunrise.toFormat("HH:mm"));
console.log(
sunrise.toFormat("dd LLL yyyy HH:mm:ss")
);
console.log(
sunrise.setLocale("ru").toLocaleString(DateTime.DATETIME_FULL)
);
SunCalc возвращает время максимального положения Солнца.
const solarNoon = DateTime
.fromJSDate(times.solarNoon)
.setZone("Asia/Almaty");
console.log(solarNoon.toFormat("HH:mm:ss"));
Гражданские сумерки используются:
const dawn = DateTime
.fromJSDate(times.dawn)
.setZone("Asia/Almaty");
const dusk = DateTime
.fromJSDate(times.dusk)
.setZone("Asia/Almaty");
console.log(dawn.toFormat("HH:mm"));
console.log(dusk.toFormat("HH:mm"));
const nauticalDawn = DateTime
.fromJSDate(times.nauticalDawn)
.setZone("Asia/Almaty");
const astronomicalDawn = DateTime
.fromJSDate(times.nightEnd)
.setZone("Asia/Almaty");
console.log(nauticalDawn.toISO());
console.log(astronomicalDawn.toISO());
Luxon умеет вычислять интервалы времени.
const daylight = sunset.diff(sunrise, [
"hours",
"minutes"
]);
console.log(daylight.toObject());
Результат:
{
hours: 14,
minutes: 37
}
Для работы с периодами используется Interval.
import { Interval } from "luxon";
const daylightInterval = Interval.fromDateTimes(
sunrise,
sunset
);
console.log(daylightInterval.length("hours"));
const current = DateTime.now().setZone("Asia/Almaty");
const isDaylight = daylightInterval.contains(current);
console.log(isDaylight);
SunCalc поддерживает:
const moonTimes = SunCalc.getMoonTimes(
new Date(),
latitude,
longitude
);
console.log(moonTimes.rise);
console.log(moonTimes.set);
const moonrise = DateTime
.fromJSDate(moonTimes.rise)
.setZone("Asia/Almaty");
const moonset = DateTime
.fromJSDate(moonTimes.set)
.setZone("Asia/Almaty");
console.log(moonrise.toFormat("HH:mm"));
console.log(moonset.toFormat("HH:mm"));
Иногда Луна может не появляться над горизонтом.
if (!moonTimes.rise) {
console.log("Восход Луны отсутствует");
}
Такие ситуации часто встречаются:
const illumination = SunCalc.getMoonIllumination(
new Date()
);
console.log(illumination.phase);
Фаза возвращается в диапазоне:
0 → новолуние
0.25 → первая четверть
0.5 → полнолуние
0.75 → последняя четверть
function getMoonPhase(phase) {
if (phase < 0.03 || phase > 0.97) {
return "Новолуние";
}
if (phase < 0.22) {
return "Растущий серп";
}
if (phase < 0.28) {
return "Первая четверть";
}
if (phase < 0.47) {
return "Растущая Луна";
}
if (phase < 0.53) {
return "Полнолуние";
}
if (phase < 0.72) {
return "Убывающая Луна";
}
if (phase < 0.78) {
return "Последняя четверть";
}
return "Убывающий серп";
}
console.log(illumination.fraction);
Значение:
0 → Луна невидима
1 → полная освещённость
const moonPosition = SunCalc.getMoonPosition(
new Date(),
latitude,
longitude
);
console.log(moonPosition.altitude);
console.log(moonPosition.azimuth);
Параметры:
| Свойство | Описание |
|---|---|
| altitude | высота над горизонтом |
| azimuth | азимут |
| distance | расстояние до Луны |
| parallacticAngle | параллактический угол |
В астрономии рекомендуется хранить время в UTC.
const utcNow = DateTime.utc();
console.log(utcNow.toISO());
Локальное отображение выполняется отдельно:
const local = utcNow.setZone("Asia/Almaty");
Стандарт ISO 8601 используется практически во всех астрономических API.
console.log(DateTime.utc().toISO());
Пример:
2026-05-24T18:42:11.000Z
Астрономические движки часто используют Unix-время.
const timestamp = DateTime.now().toSeconds();
console.log(timestamp);
Обратное преобразование:
const dt = DateTime.fromSeconds(timestamp);
Luxon не поддерживает юлианскую дату напрямую, однако преобразование можно реализовать самостоятельно.
function toJulianDate(dt) {
return dt.toMillis() / 86400000 + 2440587.5;
}
Использование:
const jd = toJulianDate(DateTime.utc());
console.log(jd);
Для астрономии важно избегать:
Наиболее безопасный подход:
const utc = DateTime.utc();
Только при отображении:
utc.setZone("Asia/Almaty");
Солнечный полдень редко совпадает с 12:00 гражданского времени.
Причины:
Luxon помогает корректно отображать эти различия.
В северных регионах восход или закат могут отсутствовать.
if (times.sunrise && times.sunset) {
console.log("Обычный день");
} else {
console.log("Полярный режим");
}
const schedule = [
{
event: "Восход",
time: sunrise.toFormat("HH:mm")
},
{
event: "Полдень",
time: solarNoon.toFormat("HH:mm")
},
{
event: "Закат",
time: sunset.toFormat("HH:mm")
}
];
console.table(schedule);
schedule.sort((a, b) => {
return a.time.localeCompare(b.time);
});
const json = JSON.stringify({
sunrise: sunrise.toISO(),
sunset: sunset.toISO(),
moonrise: moonrise.toISO()
});
const parsed = JSON.parse(json);
const restored = DateTime.fromISO(parsed.sunrise);
const now = DateTime.now();
let nextSunset = sunset;
if (now > sunset) {
const tomorrow = now.plus({ days: 1 });
const tomorrowTimes = SunCalc.getTimes(
tomorrow.toJSDate(),
latitude,
longitude
);
nextSunset = DateTime
.fromJSDate(tomorrowTimes.sunset)
.setZone("Asia/Almaty");
}
const duration = sunrise.diff(DateTime.now(), [
"hours",
"minutes",
"seconds"
]);
console.log(duration.toObject());
const localized = sunrise
.setLocale("ru")
.toLocaleString(DateTime.TIME_24_WITH_SECONDS);
console.log(localized);
import { Duration } from "luxon";
const duration = Duration.fromObject({
hours: 1,
minutes: 30
});
console.log(duration.as("minutes"));
if (!sunrise.isValid) {
console.log(sunrise.invalidReason);
}
Астрономические вычисления могут быть ресурсоёмкими.
Практические рекомендации:
DateTime вместо строк;setZone() внутри
циклов.Распространённая схема:
SunCalc → вычисления
Luxon → работа со временем
Frontend → отображение
Backend → хранение UTC
Большинство погодных сервисов возвращают:
Luxon позволяет быстро нормализовать данные.
const sunrise = DateTime
.fromSeconds(api.sunrise, {
zone: "utc"
})
.setZone(api.timezone);
const cities = [
{
name: "Karaganda",
lat: 49.8028,
lon: 73.0877
},
{
name: "Tokyo",
lat: 35.6762,
lon: 139.6503
}
];
Вычисление:
cities.forEach(city => {
const times = SunCalc.getTimes(
new Date(),
city.lat,
city.lon
);
const sunrise = DateTime
.fromJSDate(times.sunrise);
console.log(
city.name,
sunrise.toISO()
);
});
SunCalc обеспечивает хорошую точность для:
Однако для профессиональной астрономии используются:
Luxon при этом остаётся удобным уровнем обработки и представления времени.