Расчет Jday(юлианский день) в JavaScript
У меня есть требование для расчета jday
в JavaScript, для выполнения проверки на стороне клиента, может ли кто-нибудь помочь мне, как рассчитать JDAY
в JavaScript или сценарии, чтобы изменить данный JDAY на фактическую дату или наоборот.
Чтобы узнать, что такое JDay, я нашел следующий сайт,
http://www.pauahtun.org/Software/jday.1.html
Я также ссылаюсь на приведенный ниже сайт для расчета, который упоминается в JAVA
http://www.rgagnon.com/javadetails/java-0506.html
заранее спасибо
6 ответов
Юлианский день
Юлианский день - это количество прошедших дней с начала цикла в 7980 лет.
Цель системы, изобретенной в 1583 году Джозефом Скалигером, состоит в том, чтобы упростить вычисление разности целых (целых чисел) между одной календарной датой и другой календарной датой.
Цикл 7980 года был получен путем объединения нескольких традиционных временных циклов (солнечного, лунного и определенного римского налогового цикла), для которых 7980 было обычным кратным числом.
Начальная точка для первого юлианского цикла началась 1 января 4713 г. до н.э. в полдень по Гринвичу и закончится 22 января 3268 г. в полдень по Гринвичу, ровно 7980 полных дней спустя.
Например, юлианский номер дня на 1 января 2016 года составлял 2457 389, то есть число дней с 1 января 4713 г. до н.э. в этот день.
Как рассчитать
Поскольку мы знаем, что время Unix - это количество секунд с 00:00:00 UTC, 1 января 1970 года, не считая високосных секунд, а также называемое Epoch, мы можем использовать некоторую математику для вычисления юлианского дня, когда у нас уже есть Unix время.
GMT и UTC на практике имеют одинаковое текущее время, поэтому для этого не должно быть никакой разницы.
Для начала нам нужно знать количество дней, с которых начался юлианский цикл, до начала отметок времени Unix.
Другими словами, количество дней с 1 января 4713 г. до н.э. в 12:00:00 мск, до 1 января 1970 г. в 00:00:00 мск.
Имея это количество дней, которое никогда не меняется, мы можем просто добавить количество дней с 1 января 1970 года до сегодняшнего дня, которое в любом случае возвращает Javascript, чтобы получить юлианский день.
Не суммируя все эти годы, а просто просматривая в Интернете, он говорит нам, что разница в днях между 4713 г. до н.э. и 1970 г. н.э. составляет 2440588 дней, и поскольку юлианский цикл начался в полдень, а не в полночь, мы должны вычтите ровно полдня, сделав это 2440587,5 дней.
Итак, что мы имеем сейчас 2440587.5 days + UNIX TIME in days === Julian Day
С помощью некоторой простой математики мы можем выяснить, что продолжительность дня составляет 86 400 секунд, а метка времени Unix в миллисекундах при использовании Javascript, поэтому UNIX TIME / 86400000
получит нам количество дней с четверга, 1 января 1970 года, до сегодняшнего дня.
Теперь только на один день, мы хотели получить целое число дней, а не дробных, и можем просто округлить их до целых дней, делая что-то вроде
Math.floor((UNIX TIME / 86400000) + 2440587.5);
Юлиан Дэйт
Иногда в программировании под "юлианской датой" понимается число дней с начала года, например, 1 июня 2016 года будет 152 дня в этом году и т. Д.
Правильное использование "Юлианской даты" - это юлианский день с временной меткой, добавленной в виде дробной части дня.
Взяв пример в верхней части этого ответа, где 1 января 2016 года был юлианский день 2457 389, мы можем добавить к этому время.
Юлианский день начинается в полдень, без добавления дробного времени, и поэтому в полночь это будет 2457389.5
и в 18:00 или через шесть часов после полудня 2457389.25
, добавив "полдня", "четверть дня" и т. д.
Снова подсчитав
Это означает, что 0,1 юлианская дата совпадает с 24 часами, деленными на 10, или 24 / 10 === 2.4 hours
или, другими словами, метки времени юлианского дня дробны с десятичными (одна десятая дня и т. д.).
Давайте посмотрим на некоторые функции Javascript, во-первых, Date
конструктор.
Javascript имеет доступ только к местному времени на компьютере, на котором он работает, поэтому, когда мы делаем new Date()
это не обязательно создает дату UTC, даже если время UNIX в UTC, new Date
дает вам количество секунд с начала эпохи до любого местного времени вашего компьютера и не учитывает ваш часовой пояс.
Javascript, однако, имеет Date.UTC
, которая возвращает дату в формате UTC, давайте проверим разницу, и она, конечно, будет отличаться в зависимости от часового пояса, установленного для локальной системы.
var regular_date = new Date(2016, 1, 1, 0, 0, 0);
var UTC_date = Date.UTC(2016, 1, 1, 0, 0, 0);
var difference = UTC_date - regular_date;
document.body.innerHTML = 'The difference between your local time and UTC is ' +(difference/1000)+ ' seconds';
Помните часть в начале этой главы, где 0,1 юлианская дата совпадает с 24 часами, деленными на 10, или 24 / 10 === 2.4 hours
Что ж, 2,4 часа - это 144 минуты, а теперь давайте посмотрим быстро на Javascripts getTimezoneOffset()
метод, говорят доктора
Метод getTimezoneOffset() возвращает смещение часового пояса от UTC в минутах для текущей локали.
Таким образом, он возвращает смещение системного часового пояса в минутах, что интересно, так как большинство методов javascript, работающих с датами, возвращают миллисекунды.
Мы знаем, что 1/10 дня - это 144 минуты, поэтому 10/10 или целый день - 1440 минут, поэтому мы могли бы использовать некоторые математические средства для противодействия часовому поясу локальных систем, указанному в минутах, и разделить его на количество минут в дне, чтобы получить правильное дробное значение
Итак, теперь у нас есть
2440587.5 days + UNIX TIME in days === Julian Day
и мы знаем, что Javascripts Date конструктор на самом деле не использует UTC для текущей даты, но системное время, поэтому мы должны иметь
TIMEZONEOFFSET / 1440
соединяя их вместе, мы получим
(JAVASCRIPT TIME / 86400000) - (TIMEZONEOFFSET / 1440) + 2440587.5
// ^^ days since epoch ^^ ^^ subtract offset ^^ ^^days from 4713 B.C. to 1970 A.D.
Переводить это на JavaScript было бы
var date = new Date(); // a new date
var time = date.getTime(); // the timestamp, not neccessarely using UTC as current time
var julian_day = (time / 86400000) - (date.getTimezoneOffset()/1440) + 2440587.5);
Теперь это то, что мы должны использовать, чтобы получить юлианский день, принимая меры для устранения смещения часового пояса и, конечно, без доли времени Юлиана.
Мы сделаем это, просто округлив его до ближайшего целого числа
var julian_date = Math.floor((time / 86400000) - (date.getTimezoneOffset()/1440) + 2440587.5));
И пришло время для моего первоначального ответа на этот вопрос, прежде чем я сделал это очень долгое редактирование, чтобы объяснить, почему это правильный подход, после жалоб в поле для комментариев.
Date.prototype.getJulian = function() {
return Math.floor((this / 86400000) - (this.getTimezoneOffset() / 1440) + 2440587.5);
}
var today = new Date(); //set any date
var julian = today.getJulian(); //get Julian counterpart
console.log(julian)
.as-console-wrapper {top:0}
И то же самое с фракционной частью
Date.prototype.getJulian = function() {
return (this / 86400000) - (this.getTimezoneOffset() / 1440) + 2440587.5;
}
var today = new Date(); //set any date
var julian = today.getJulian(); //get Julian counterpart
console.log(julian)
.as-console-wrapper { top: 0 }
И, наконец, пример, показывающий, почему
new Date().getTime()/86400000 + 2440587.5
не работает, по крайней мере, если ваше системное время настроено на часовой пояс со смещением, т. е. все, кроме GMT
// the correct approach
Date.prototype.getJulian = function() {
return (this / 86400000) - (this.getTimezoneOffset() / 1440) + 2440587.5;
}
// the simple approach, that does not take the timezone into consideration
Date.prototype.notReallyJulian = function() {
return this.getTime()/86400000 + 2440587.5;
}
// --------------
// remember how 18:00 should return a fractional 0.25 etc
var date = new Date(2016, 0, 1, 18, 0, 0, 0);
// ^ ^ ^ ^ ^ ^ ^
// year month date hour min sec milli
var julian = date.getJulian(); //get Julian date
var maybe = date.notReallyJulian(); // not so much
console.log(julian); // always returns 2457389.25
console.log(maybe); // returns different fractions, depending on timezone offset
.as-console-wrapper { top: 0 }
new Date().getTime()/86400000 + 2440587.5
получит метку времени Unix, преобразует ее в дни и добавит JD 1970-01-01, который является эпохой метки времени Unix.
Это то, что астрономы называют юлианской датой. Это хорошо определено. Поскольку ни метка времени Unix, ни JD не учитывают дополнительных секунд, что не снижает точность. Обратите внимание, что JD не обязательно должен быть в часовом поясе UTC (но обычно это так). Этот ответ дает вам JD в часовом поясе UTC.
Согласно википедии:
a = (14 - month) / 12
y = year + 4800 - a
m = month + 12a - 3
JDN = day + (153m + 2) / 5 + 365y + y/4 - y/100 + y/400 - 32045
Если у вас возникла более конкретная проблема с реализацией, укажите эти детали в вопросе, чтобы мы могли помочь вам в дальнейшем.
ПРИМЕЧАНИЕ: это не правильно, потому что "напольные скобки" в вики были здесь забыты.
Правильные формулы:
a = Int((14 - Month) / 12)
y = Year + 4800 - a
m = Month + 12 * a - 3
JDN = Day + Int((153 * m + 2) / 5) + 365 * y + Int(y / 4) - Int(y / 100) + Int(y / 400) - 32045
JD =>
const millisecondsSince1970Now = new Date+0
const julianDayNow = 2440587.5+new Date/864e5
const dateNow = new Date((julianDayNow-2440587.5)*864e5)
Кажется, существует путаница в том, что такое юлианский день и как его рассчитать.
Время Javascript измеряется в миллисекундах GMT/UTC UInt64 от
Jan 1, 1970 at midnight
.
Месяц, день, год аспекты JavaScript
Date
все функции реализованы с использованием правил григорианского календаря. Но Джулиана "Дней" это не коснулось; однако сопоставление "дневного счета" с юлианским месяцем, днем и годом будет.
Таким образом, расчет конверсий в юлианский день является относительным отсчетом дней с этого момента времени (1 января 1970 г. по Гринвичу / UTC).
Юлианский день для
Jan 1, 1970
является
2440587.5
(0,5, потому что JulianDays начинаются в ПОЛДЕНЬ).
В
864e5
константа - это обозначение JavaScript для
86,400,000
(миллисекунды / день).
Единственная сложность заключается в вычислении юлианских дат (дней) до принятия григорианского календаря 1582 года, изменения которого по поручению Папы Григория должны были исправить неточности смещения високосного года, влияющие на Пасху. Потребовалось примерно до 1752 года, чтобы быть полностью принятым в большинстве стран мира, которые использовали систему юлианского календаря или производную систему (Россия и Китай использовали систему до 20-го века).
И еще более вопиющие ошибки в первые 60 лет введения юлианской даты из "реформаторского" мандата Юлия Цезаря 46 г. до н.э., когда священники совершали ошибки, а люди неправильно понимали, складывая календарь на 14-15 месяцев. (отсюда ошибки во многих религиозных датах и времени того периода).
Ничего из этого не применяется при вычислении значений юлианского дня в JavaScript.
См. Также: (из заметок ядра сценариев AfEE EdgeS/EdgeShell)
- Ответы по астрономии - число юлианского дня (многокалендарные преобразования)
- Юлианский календарь
- Атомные часы
- Приоритет оператора JavaScript
- Microsoft FILETIME относительно единиц эпохи 1/1/1601: 10^-7 (100 нс)
- Форматы меток времени UUID/GUID - полезны также для преобразования времени в дату
- Детали "дополнительной секунды"
Есть отдельная тонкость "дополнительная секунда", которая применяется к астрономическим расчетам и использованию атомных часов, которые связаны с орбитальной траекторией Земли и дрейфом вращения.
т.е.
86,400.000
секунд в день требует "корректировки", чтобы синхронизировать календари (часовые пояса, спутники GPS), как и в настоящее время.86,400.002
.
Кажется, что окончательный код, указанный в принятом ответе, неверен. Проверьте "официальный" онлайн калькулятор на веб-сайте Военно-морской обсерватории США:
http://aa.usno.navy.mil/data/docs/JulianDate.php
Если кто-то знает правильный ответ на время ответа и календарь, это USNO.
Я сделал это для равноденствия и уединения. Вы можете использовать эту функцию для любой даты по юлианскому календарю. Он возвращает дату по юлианскому календарю в формате даты: день / месяц. Включите год, и вы можете отформатировать его как хотите. Там все, год, месяц, день. Поскольку Equinox и Solistice - это временные метки, а не даты, мои даты в коде возвращаются в виде десятичных знаков, следовательно, "day = k.toFixed(0);". Для любой другой юлианской даты это должно быть day = k;
// For the HTML-page
<script src="../js/meuusjs.1.0.3.min.js"></script>
<script src="../js/Astro.Solistice.js"></script>
// Javascript, Julian Date to Calender Date
function jdat (jdag) {
var jd, year, month, day, l, n, i, j, k;
jd = jdag;
l = jd + 68569;
n = Math.floor(Math.floor(4 * l) / 146097);
l = l - Math.floor((146097 * n + 3) / 4);
i = Math.floor(4000 * (l + 1) / 1461001);
l = l - Math.floor(1461 * i / 4) + 31;
j = Math.floor(80 * l / 2447);
k = l - Math.floor(2447 * j / 80);
l = Math.floor(j / 11);
j = j + 2 - 12 * l;
i = 100 * (n - 49) + i + l;
year = i;
month = j;
day = k.toFixed(0); // Integer
dat = day.toString() + "/" + month.toString(); // Format anyway you want.
return dat;
}
// Below is only for Equinox and Solistice. Just skip if not relevant.
// Vernal Equinox
var jv = A.Solistice.march(year); // (year) predefined, today.getFullYear()
var vdag = jdat(jv);
// Summer Solistice
var js = A.Solistice.june(year);
var ssol = jdat(js);
//Autumnal Equinox
var jh = A.Solistice.september(year);
var hdag = jdat(jh);
// Winter Solistice
var jw = A.Solistice.december(year);
var vsol = jdat(jw);
Что бы вы ни делали, НЕ ИСПОЛЬЗУЙТЕ getTimezoneOffset() в даты, предшествующие изменению политики в текущей локали, в прошлом она полностью нарушалась (к правилам базы данных iana не применяются). Например, если я введу (дата UTC 1 октября 1995 года в 00:00:00):var d=new Date(Date.UTC(1995, 9, 1, 0, 0, 0)); console.log(d.toLocaleString()); console.log(d.getTimezoneOffset());
в консоли javascript в Chrome он печатает (я во Франции):
01.10.1995 в 01:00:00 <= это зимнее время, +1:00 от UTC
-120 <= НО это смещение летнего времени (должно быть -60 для зимы)
Между 1973 и 1995 годами (включительно), летнее время (-120) прекратилось в последнее воскресенье сентября, следовательно, 1 октября 1995 года, getTimezoneOffset()
должен вернуть -60, а не -120. Обратите внимание, что форматированная дата правильная (01:00:00 - ожидаемое значение -60). Тот же результат в Firefox, но в IE и Edge, что еще хуже, даже отформатированная дата неверна (01/10/ 1995 02: 00: 00, что соответствует плохому результату -120 getTimezoneOffset()
). Каким бы ни был браузер (из этих 4), getTimezoneOffset()
использует текущие правила, а не правила рассматриваемой даты. Вариация на ту же проблему, когда DST не применялся во Франции (1946-1975), консоль Chrome:d=new Date(Date.UTC(1970, 6, 1, 0, 0, 0)); console.log(d.toLocaleString()); console.log(d.getTimezoneOffset());
отображается:
01/07/1970 01: 00: 00 <= нормально, летнее время не было в июне 1970, +1:00
-120 <= та же проблема, здесь тоже должно быть -60
А также, то же самое в Firefox, хуже в IE / Edge (01/07/1970 02: 00: 00).
Кроме того, для этого есть пакет npm:
юлианский
Преобразование между объектом Date и юлианскими датами, используемыми в астрономии и истории
var julian = require('julian');
var now = new Date(); // Let's say it's Thu, 21 Nov 2013 10:47:02 GMT
var jd = '';
console.log(jd = julian(now)); // -> '2456617.949335'
console.log(julian.toDate(jd)); // -> Timestamp above in local TZ