如何在 Javascript 中对史前日期使用 Date?

我在做一个 JavaScript Date 不够大的项目。

我想把多个事件放在同一个时间轴上,有些有月和日,有些没有,所以仅仅使用 year 不是一个选项。我希望能够实现登月和大爆炸在同一轴上。

如果我能够使用现有 Date 对象所具有的功能,那么将会有很大的帮助。它只能追溯到270,000年前,我需要一直追溯到大爆炸(13,800,000,000年前)。我不需要日期包含秒或毫秒。

如何扩展 Date 对象以包含此类日期的表示形式?

我曾试图为此找到库或本机函数,但没有找到。我还开始寻找 Date 对象的 JavaScript 实现,我可以对其进行修改,但是在这里也没有找到。

更新:

我开始使用 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();
};

5834 次浏览

If you only need to represent years, a simple Number might be enough : they can represent up to +/- 9007199254740991.

You could wrap it into a custom class to provide it with date functions.

The ECMAScript says:

A Date object contains a Number indicating a particular instant in time to within a millisecond. Such a Number is called a time value. A time value may also be NaN, indicating that the Date object does not represent a specific instant of time.

Time is measured in ECMAScript in milliseconds since 01 January, 1970 UTC. In time values leap seconds are ignored. It is assumed that there are exactly 86,400,000 milliseconds per day. ECMAScript Number values can represent all integers from –9,007,199,254,740,992 to 9,007,199,254,740,992; this range suffices to measure times to millisecond precision for any instant that is within approximately 285,616 years, either forward or backward, from 01 January, 1970 UTC.

The actual range of times supported by ECMAScript Date objects is slightly smaller: exactly –100,000,000 days to 100,000,000 days measured relative to midnight at the beginning of 01 January, 1970 UTC. This gives a range of 8,640,000,000,000,000 milliseconds to either side of 01 January, 1970 UTC.

The exact moment of midnight at the beginning of 01 January, 1970 UTC is represented by the value +0.

So you can create a custom method for Dates where you can use the integer value as the year. But on a practical note Ecmascript range for dates is good enough to hold all the practical dates. The one which you are trying to achieve does not make a real practical sense/meaning as even one is not sure if it follows the Babylonian astrology?

I don’t need the dates to contain seconds or milliseconds.

Note that Gregorian calendar moves in cycles of 400 years, hence in cycles of 240,000 years. Therefore you can take the 60000 milliseconds representation of Date, that you don't want to use, to go back in 240000 years cycles (up to 60000 such cycles). This can take you to about year 14.4 billion BC (just before Big Bang :) ), with minute resolution.

The following example is not taking into consideration all the functionality of Date object. However with further implementation, I believe it is possible to have similar functionality. For instance, one BigDate, x, is bigger than another BigDate, y, if both dates are AC and x.original > y.original or if x.isAC() but !y.isAC(), or if both dates are BC such that either x.getFullYear() < y.getFullYear() or x.getFullYear() === y.getFullYear() && x.original > y.original.

BigDate usage:

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..

And here comes the meat:

// 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;
}

Some demo (can as well be used to produce BigDate.prototype.toString(), etc.) :

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";

The resulted content would be: 4847996014 Jan 28 8: 21 BC

Here's a JSFiddle.

Clarification

Regarding (justified) design comments, I am aware that the BigDate object presented above manifests poor interface and design. The object is only presented as an example of consuming the unused information of seconds and milliseconds to satisfy the question. I hope this example helps to understand the technique.

Wrap the Date

Create a class of your own that extends the Date class by adding a long integer field "year offset".

Update all the methods that you want to use to apply this year offset - you can leave almost everything as-is, since you're not touching the complexities of handling time and days; maybe it will even be enough for you to change the constructors and string formatting routines to include "your" year in them.