Wie verwende ich Datum in Javascript für prähistorische Daten?

76

Ich arbeite an einem Projekt, bei dem das JavaScript-Datum nicht groß genug ist.

Ich möchte mehrere Ereignisse auf derselben Zeitachse platzieren. Einige haben Monat und Tag, andere nicht. Daher ist es nicht möglich, nur das Jahr zu verwenden. Ich möchte in der Lage sein, die Mondlandung und den Urknall auf derselben Achse zu haben.

Es wäre sehr hilfreich, wenn ich die Funktionalität des vorhandenen Date-Objekts nutzen könnte. Es geht nur 270.000 Jahre zurück und ich muss den ganzen Weg zurück zum Urknall (vor 13.800.000.000 Jahren) gehen. Ich brauche die Daten nicht, um Sekunden oder Millisekunden zu enthalten.

Wie kann ich das Date-Objekt um die Darstellung solcher Daten erweitern?

Ich habe versucht, Bibliotheken oder native Funktionen dafür zu finden, aber ohne Glück. Ich suchte auch nach einer JavaScript-Implementierung des Date-Objekts, die ich ändern konnte, aber ich hatte auch hier kein Glück.

Aktualisieren:

Ich habe mit der remdevtec-Lösung angefangen, sie aber ziemlich oft modifiziert. Ich wollte, dass die Daten in numerischer Reihenfolge angezeigt werden, um das Sortieren und Ordnen der Daten zu vereinfachen.

Ich habe also den Millisekundenwert als Stunden behandelt, wenn das Jahr vor -100.000 liegt. Dies ist, was ich bisher bekommen habe, und es funktioniert in unserem Projekt, aber wenn ich mehr Zeit habe, werde ich es aufräumen und auf Github legen.

JSFiddle

Ogge
quelle
14
Sie sollten angeben, welche Anforderungen Sie an diese Daten stellen. Müssen Sie beispielsweise eine Datumsarithmetik durchführen?
Aaron
23
Müssen Sie wirklich Tage und Monate wissen, wenn das Jahr 45.000.000 v. Chr. Ist? Wenn ja, welchen Kalender möchten Sie verwenden (insbesondere seit diesem Datum vor Kalendern und Menschen )? Ich nehme an, es wäre schön, Dippys Geburtstag aufzuzeichnen .
MT0
2
Verstehen Sie, dass es höchst unwahrscheinlich ist, dass das Kalendersystem für weitere 270000 Jahre gleich bleibt. Verdammt, sogar 1000 Jahre. Sehr langfristige Datumsberechnungen sind wahrscheinlich zwecklos. Dies gilt auch für die Zeit zurück: Das derzeitige gregorianische Kalendersystem wurde erst vor etwa hundert Jahren nach dem Ersten Weltkrieg endgültig global verankert.
Simba
13
Repräsentiert 270K Jahre = First World Problem vom Feinsten.
CodeAngry
1
Haben Sie überlegt, eine logarithmische Skala zu verwenden?
Sampathsris

Antworten:

81

Ich brauche die Daten nicht, um Sekunden oder Millisekunden zu enthalten.

Beachten Sie, dass sich der Gregorianische Kalender in Zyklen von 400 Jahren und damit in Zyklen von 240.000 Jahren bewegt. Daher können Sie die 60000-Millisekunden-Darstellung von Date, die Sie nicht verwenden möchten, verwenden, um in 240000-Jahres-Zyklen (bis zu 60000 solcher Zyklen) zurückzukehren. Dies kann Sie zu ungefähr 14,4 Milliarden v. Chr. (Kurz vor Urknall :)) mit winziger Auflösung führen.

Das folgende Beispiel berücksichtigt nicht alle Funktionen des Date-Objekts. Ich glaube jedoch, dass es bei weiterer Implementierung möglich ist, ähnliche Funktionen zu haben. Zum Beispiel ist ein BigDate xgrößer als ein anderes BigDate, ywenn beide Daten ACund x.original > y.originaloder oder x.isAC()aber !y.isAC()sind oder wenn beide Daten so sind BC, dass entweder x.getFullYear() < y.getFullYear()oder x.getFullYear() === y.getFullYear() && x.original > y.original.

BigDate-Nutzung:

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

Und hier kommt das Fleisch:

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

Einige Demos (können auch zum Produzieren BigDate.prototype.toString()usw. verwendet werden):

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

Der resultierende Inhalt wäre: 4847996014 Jan 28 8: 21 BC

Hier ist eine JSFiddle .

Klärung

In Bezug auf (berechtigte) Designkommentare ist mir bewusst, dass das BigDateoben dargestellte Objekt eine schlechte Schnittstelle und ein schlechtes Design aufweist. Das Objekt wird nur als Beispiel für den Verbrauch der nicht verwendeten Informationen von Sekunden und Millisekunden dargestellt, um die Frage zu beantworten. Ich hoffe, dieses Beispiel hilft, die Technik zu verstehen.

remdevtec
quelle
@Zach Ross-Clyne Vielen Dank für Ihren Bearbeitungsvorschlag. Ich habe einige weitere bearbeitet, einschließlich Ihres getSeconds()Verwendungsvorschlags.
Remdevtec
12
WTH speichert nicht nur den Offset / Faktor in der BigDateInstanz, sondern versteckt ihn im umschlossenen DateObjekt? Außerdem sollten Sie einen nützlichen Konstruktor verfügbar machen, anstatt die Leute mit "Faktoren" herumspielen zu lassen.
Bergi
2
Ich bin bei @Bergi. Das Entführen von Sekunden und Millisekunden ist unnötig und äußerst verwirrend. Es ist bemerkenswert schlechtes Design. -1.
jpmc26
2
Ich habe das Original vor den Änderungen nicht gesehen, aber ich glaube nicht, dass Sie die gegebene Kritik wirklich in Ihre Überarbeitungen einbezogen haben. Ich sehe immer noch, dass der Versatz Dateohne besonderen Grund in die Sekunden- und Millisekundenfelder des Objekts gestopft wird (ohnehin kein erklärter Grund). Warum nicht den Offset in separate Felder nebeneinander setzen this.original? Ganz zu schweigen von zukünftigen großen Daten, die nicht ohne Unterbrechung dargestellt werden können isAC(). Wie von anderen Kommentatoren festgestellt wurde, ist dies ein schlechtes Design und IMO sollte in seinem aktuellen Zustand nicht die am höchsten bewertete / akzeptierte Antwort sein.
SV
@sv Bei der Frage ging es nicht darum, zukünftige größere Daten darzustellen. Bezüglich Ihrer anderen Kommentare lesen Sie bitte die beigefügte Klarstellung im Beitrag.
Remdevtec
31

Wenn Sie nur Jahre darstellen müssen, kann eine einfache Zahl ausreichen: Sie kann bis zu +/- 9007199254740991 darstellen.

Sie können es in eine benutzerdefinierte Klasse einbinden, um Datumsfunktionen bereitzustellen.

Aaron
quelle
18

Wickeln Sie das Datum ein

Erstellen Sie eine eigene Klasse, die die Date-Klasse erweitert, indem Sie ein langes Ganzzahlfeld "Jahresversatz" hinzufügen.

Aktualisieren Sie alle Methoden, die Sie zum Anwenden des diesjährigen Versatzes verwenden möchten. Sie können fast alles unverändert lassen, da Sie die Komplexität der Handhabung von Zeit und Tagen nicht berühren. Vielleicht reicht es sogar aus, wenn Sie die Konstruktoren und Zeichenfolgenformatierungsroutinen so ändern, dass "Ihr" Jahr darin enthalten ist.

Peter ist
quelle
11

Das ECMAScript sagt:

Ein Datumsobjekt enthält eine Zahl, die einen bestimmten Zeitpunkt innerhalb einer Millisekunde angibt. Eine solche Zahl wird als Zeitwert bezeichnet. Ein Zeitwert kann auch NaN sein, was anzeigt, dass das Datumsobjekt keinen bestimmten Zeitpunkt darstellt.

Die Zeit wird in ECMAScript in Millisekunden seit dem 1. Januar 1970 UTC gemessen. In Zeitwerten werden Schaltsekunden ignoriert. Es wird angenommen, dass es genau 86.400.000 Millisekunden pro Tag gibt. ECMAScript-Zahlenwerte können alle Ganzzahlen von –9.007.199.254.740.992 bis 9.007.199.254.740.992 darstellen. Dieser Bereich reicht aus, um Zeiten bis zur Millisekundengenauigkeit für jeden Moment zu messen, der innerhalb von ungefähr 285.616 Jahren liegt, entweder vorwärts oder rückwärts, ab dem 1. Januar 1970 UTC.

Der tatsächliche Zeitraum, der von ECMAScript-Datumsobjekten unterstützt wird, ist geringfügig kleiner: genau –100.000.000 Tage bis 100.000.000 Tage, gemessen relativ zu Mitternacht zu Beginn des 1. Januar 1970 UTC. Dies ergibt einen Bereich von 8.640.000.000.000.000 Millisekunden zu beiden Seiten des 1. Januar 1970 UTC.

Der genaue Zeitpunkt der Mitternacht zu Beginn des 1. Januar 1970 UTC wird durch den Wert +0 dargestellt.

Sie können also eine benutzerdefinierte Methode für Datumsangaben erstellen, bei der Sie den ganzzahligen Wert als Jahr verwenden können. Praktisch gesehen ist der Ecmascript-Bereich für Daten jedoch gut genug, um alle praktischen Daten aufzunehmen. Derjenige, den Sie erreichen möchten, ergibt keinen wirklichen praktischen Sinn / Sinn, da selbst einer nicht sicher ist, ob er der babylonischen Astrologie folgt ?

Rahul Tripathi
quelle