Как использовать Date в Javascript для доисторических дат?

Im работает над проектом, в котором дата JavaScript недостаточно велика.

Я хочу разместить несколько событий на одной оси времени, некоторые из них имеют месяц и день, а некоторые нет, поэтому просто использовать год не вариант. Я хочу иметь возможность посадки на Луну и большой взрыв на той же оси.

Это поможет много, если я смогу использовать функциональные возможности, существующие у существующего объекта Date. Он возвращается всего 270 000 лет, и мне нужно вернуться к Большому Взрыву (13 800 000 000 лет назад). Мне не нужны даты, чтобы содержать секунды или миллисекунды.

Как я могу расширить объект Date, чтобы включить представление для таких дат?

Я попытался найти библиотеки или собственные функции для этого, но без везения. Я также начал искать реализацию JavaScript объекта Date, который я мог бы изменить, но мне тоже не повезло.

Update:

Я начал работу с решения remdevtec, но в конечном итоге изменил его довольно много. Я хотел, чтобы даты приходили в числовом порядке, чтобы упростить сортировку и порядок дат.

Итак, я сделал то, что если год до -100 000, я обрабатываю миллисекунду значение как часы. Это то, что я получил до сих пор, и он работает в нашем проекте, но если я получу больше времени, я очищу его и поставлю на github.

JSFiddle

function BigDate(date){
    if(!date){
        this.original = new Date(); 
    }else if(date instanceof BigDate){
        this.original = date.original;
    }else{
        this.original = new Date(date);  
    }
    this.yearBreakpoint = -100000;
    this.breakPoint = Date.UTC(this.yearBreakpoint,0,0).valueOf();
    this.factor = 360000;//needed for our project to make extra space on our axis
}

BigDate.UTC = function (year, month, day, hour, minute, second, millisecond) {
    var temp = new BigDate();
    if(year < -temp.yearBreakpoint){
        temp.setUTCFullYear(year);
        return temp;
    }else{
        temp.original = Date.UTC(year,month,day,hour,minute,second,millisecond);
    }
    return temp.valueOf();
};

BigDate.now = function (){
    var temp = new BigDate();
    temp.original = Date.now();
    return temp.valueOf();
};

BigDate.parse = function (val){
    throw "not implemnted";
};

//custom functions

BigDate.prototype.getUTCDate = function () {
   if(this.valueOf() < this.breakPoint){
       return 0;
   }
   return this.original.getUTCDate();
};
BigDate.prototype.getUTCDay = function () {
   if(this.valueOf() < this.breakPoint){
        return 0;
    }
    return this.original.getUTCDay();
};
BigDate.prototype.getUTCFullYear = function () {
    if(this.valueOf() < this.breakPoint){
        return (this.valueOf() - this.breakPoint) / this.factor;
    }
    return this.original.getUTCFullYear();
};
BigDate.prototype.getUTCHours = function () {
    if(this.valueOf() < this.breakPoint){
        return 0;
    }
    return this.original.getUTCHours();
};
BigDate.prototype.getUTCMilliseconds = function () {
    if(this.valueOf() < this.breakPoint){
        return 0;
    }
    return this.original.getUTCMilliseconds();
};
BigDate.prototype.getUTCMinutes = function () {
    if(this.valueOf() < this.breakPoint){
        return 0;
    }
    return this.original.getUTCMinutes();
};
BigDate.prototype.getUTCMonth = function () {
    if(this.valueOf() < this.breakPoint){
        return 0;
    }
    return this.original.getUTCMonth();
};
BigDate.prototype.getUTCSeconds = function () {
    if(this.valueOf() < this.breakPoint){
        return 0;
    }
    return this.original.getUTCSeconds();
};

BigDate.prototype.setUTCDate = function (val) {
    if(val >= this.yearBreakpoint){
      return this.original.setUTCDate(val);
   }
};
BigDate.prototype.setUTCFullYear = function (val) {
    if(val < this.yearBreakpoint){
        this.original.setTime((parseInt(val) * this.factor) + this.breakPoint);
    }else{
        this.original.setUTCFullYear(val);
    }
    return this.valueOf();
};
BigDate.prototype.setUTCHours = function (val) {
    if(val >= this.yearBreakpoint){
      return this.original.setUTCHours(val);
    }
};
BigDate.prototype.setUTCMilliseconds = function (val) {
    if(val >= this.yearBreakpoint){
      return this.original.setUTCMilliseconds(val);
    }
};
BigDate.prototype.setUTCMinutes = function (val) {
    if(val >= this.yearBreakpoint){
        return this.original.setUTCMinutes(val);
    }
};
BigDate.prototype.setUTCMonth = function (val) {
    if(val >= this.yearBreakpoint){
      return   this.original.setUTCMonth(val);
    }
};
BigDate.prototype.setUTCSeconds = function (val) {
    if(val >= this.yearBreakpoint){
       return  this.original.setUTCSeconds(val);
    }
};

BigDate.prototype.setTime = function (val) {
    this.original.setTime(val);
    return this.valueOf();
};
BigDate.prototype.valueOf = function () {
    return this.original.valueOf();
};


BigDate.prototype.toDateString = function () {
    if(this.valueOf() < this.breakPoint){
        return "Jan 01 " + this.getUTCFullYear();
    }
    return this.original.toDateString();
};
BigDate.prototype.toISOString = function () {
    if(this.valueOf() < this.breakPoint){
        return this.getUTCFullYear() + "-01-01T00:00:00.000Z";
    }
    return this.original.toISOString();
};

BigDate.prototype.toJSON = function () {
    throw "not implemnted";
};
BigDate.prototype.toLocaleDateString = function () {
    throw "not implemnted";
};
BigDate.prototype.toLocaleTimeString = function () {
    throw "not implemnted";
};
BigDate.prototype.toLocaleString = function () {
    throw "not implemnted";
};
BigDate.prototype.toTimeString = function () {
    throw "not implemnted";
};
BigDate.prototype.toUTCString = function () {
    if(this.valueOf() < this.breakPoint){
        return "01 Jan "+ this.getFullYear() +" 00:00:00 GMT";
    }
    return this.original.toUTCString();
};




/**
 * Don't need no timezones
 */

BigDate.prototype.getDate = function () {
    return this.getUTCDate();
};
BigDate.prototype.getDay = function () {
    return this.getUTCDay();
};
BigDate.prototype.getFullYear = function () {
    return this.getUTCFullYear();
};
BigDate.prototype.getHours = function () {
    return this.getUTCHours();
};
BigDate.prototype.getMilliseconds = function() {
    return this.getUTCMilliseconds();
};
BigDate.prototype.getMinutes = function() { 
    return this.getUTCMinutes();
};
BigDate.prototype.getMonth = function () {
    return this.getUTCMonth();
};
BigDate.prototype.getSeconds = function () {
    return this.getUTCSeconds();
};
BigDate.prototype.getTimezoneOffset = function () {
    return 0;
};
BigDate.prototype.getTime = function () {
    return this.valueOf();
};

BigDate.prototype.setDate = function (val) {
    return this.setUTCDate(val);
};
BigDate.prototype.setFullYear = function (val) {
    return this.setUTCFullYear(val);
};
BigDate.prototype.setHours = function (val) {
    return this.setUTCHours(val);
};
BigDate.prototype.setMilliseconds = function (val) {
    return this.setUTCMilliseconds(val);
};
BigDate.prototype.setMinutes = function (val) {
    return this.setUTCMinutes(val);
};
BigDate.prototype.setMonth = function (val) {
    return this.setUTCMonth(val);
};
BigDate.prototype.setSeconds = function (val) {
    return this.setUTCSeconds(val);
};

BigDate.prototype.toString = function () {
    return this.toUTCString();
};

Ответ 1

Мне не нужны даты, чтобы содержать секунды или миллисекунды.

Обратите внимание, что григорианский календарь движется в циклах 400 лет, следовательно, в циклах 240 000 лет. Поэтому вы можете взять 60000 миллисекундное представление Date, которое вы не хотите использовать, чтобы вернуться в циклы 240000 лет (до 60000 таких циклов). Это может занять около года 14,4 млрд. До н. Э. (как раз перед Big Bang:)), с минимальным разрешением.

В следующем примере не учитываются все функциональные возможности объекта Date. Однако, с дальнейшей реализацией, я считаю, что возможно иметь аналогичную функциональность. Например, один BigDate, x, больше, чем другой BigDate, y, если обе даты AC и x.original > y.original или if x.isAC(), но !y.isAC(), или если обе даты BC такие что либо x.getFullYear() < y.getFullYear(), либо x.getFullYear() === y.getFullYear() && x.original > y.original.

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

var time = new Date (
  [year /*range: 0-239999*/], 
  [month /*range: 0-11*/], 
  [day of month /*range: 1-31*/], 
  [hours /*range: 0-23*/], 
  [minutes /*range: 0-59*/], 
  [a factor of 240,000,000 years to go back (from the first parameter year) /*range: 0-59*/],
  [a factor of 240,000 years to go back (from the first parameter year) /*range: 0-999*/]); 
var bigDate = new BigDate(time);

HTML

<span id="years"></span>
<span id="months"></span>
<span id="date"></span>
<span id="hours"></span>
<span id="minutes"></span>
<span id="acbc"></span>

JAVASCRIPT

function BigDate (date) { this.original = date; }    

// set unchanged methods,
BigDate.prototype.getMinutes = function () { return this.original.getMinutes(); }
BigDate.prototype.getHours = function () { return this.original.getHours(); }
BigDate.prototype.getDate = function () { return this.original.getDate(); }
BigDate.prototype.getMonth = function () { return this.original.getMonth(); }

// implement other BigDate methods..

И вот идет мясо:

// now return non-negative year
BigDate.prototype.getFullYear = function () {  
  var ms = this.original.getSeconds() * 1000 + this.original.getMilliseconds();
  if (ms === 0) return this.original.getFullYear();
  else return (ms * 240000) - this.original.getFullYear();
}

// now add AC/BC method
BigDate.prototype.isAC = function () {
  var result = this.original.getSeconds() === 0 &&
    this.original.getMilliseconds() === 0;
  return result;
}

Некоторая демонстрация (можно также использовать для создания BigDate.prototype.toString() и т.д.):

var years = document.getElementById("years");
var months = document.getElementById("months");
var date = document.getElementById("date");
var hours = document.getElementById("hours");
var minutes = document.getElementById("minutes");
var acbc = document.getElementById("acbc");

// SET A TIME AND PRESENT IT
var time = new Date (2016, 1, 28, 8, 21, 20, 200); 
var bigDate = new BigDate(time);
var monthsName = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
years.innerHTML = bigDate.getFullYear();
months.innerHTML = monthsName[bigDate.getMonth()];    
date.innerHTML = bigDate.getDate();
hours.innerHTML = bigDate.getHours() + ":";
minutes.innerHTML = bigDate.getMinutes();
acbc.innerHTML = (bigDate.isAC()) ? "AC":"BC";

Приведенное содержимое будет: 4847996014 Jan 28 8: 21 BC

Здесь JSFiddle.

Разъяснение

Что касается (обоснованных) комментариев к дизайну, я знаю, что представленный выше объект BigDate демонстрирует плохой интерфейс и дизайн. Объект представлен в качестве примера для использования неиспользуемой информации секунд и миллисекунд, чтобы удовлетворить вопрос. Надеюсь, этот пример поможет понять технику.

Ответ 2

Если вам нужно представлять только годы, простого номера может быть достаточно: они могут представлять до +/- 9007199254740991.

Вы можете перенести его в пользовательский класс, чтобы предоставить ему функции даты.

Ответ 3

Оберните дату

Создайте собственный класс, который расширяет класс Date, добавив длинное целое поле "смещение года".

Обновите все методы, которые вы хотите использовать для применения смещения в этом году - вы можете оставить почти все как есть, так как вы не трогаете сложности обработки времени и дней; может быть, вам даже будет достаточно, чтобы вы изменили конструкторы и строковые процедуры форматирования, включив в них "ваш" год.

Ответ 4

ECMAScript говорит:

Объект Date содержит номер, указывающий конкретный момент в время в пределах миллисекунды. Такой номер называется значением времени. значение времени также может быть NaN, указывая, что объект Date не представляют определенный момент времени.

Время измеряется в ECMAScript в миллисекундах с 01 января 1970 г. УНИВЕРСАЛЬНОЕ ГЛОБАЛЬНОЕ ВРЕМЯ. В значениях времени значения секунд прыжка игнорируются. Предполагается, что составляют ровно 86 400 000 миллисекунд в день. Значения числа ECMAScript могут представлять все целые числа от -9,007,199,254,740,992 до 9.007.199.254.740.992; этого диапазона достаточно для измерения времени до миллисекундной точности для любого момента, который находится в пределах приблизительно 285 616 лет, либо вперед, либо назад, с 01 января 1970 года по UTC.

Фактический диапазон времени, поддерживаемый объектами ECMAScript Date, равен немного меньше: ровно -100 000 000 дней до 100 000 000 дней измеренная относительно полуночи в начале января - 1970 г. УНИВЕРСАЛЬНОЕ ГЛОБАЛЬНОЕ ВРЕМЯ. Это дает диапазон 8 640 000 000 000 000 миллисекунд с 1 января 1970 года по UTC.

Точный момент полуночи в начале 01 января 1970 года UTC представляет значение +0.

Итак, вы можете создать собственный метод для дат, в котором вы можете использовать целочисленное значение как год. Но на практике примечание Диапазон интервала для дат достаточно хорош, чтобы провести все практические даты. Тот, который вы пытаетесь достичь, не дает реального практического смысла/смысла, поскольку даже один не уверен, следует ли ему вавилонская астрология