Wie modelliere ich Teildaten in Python? Wie ein unbekanntes Jahr oder ein unbekannter Tag des Monats?

11

Ich möchte in der Lage sein, Fakten wie Bob was born in 2000und zu erfassen Bill's birthday is May 7th.

In beiden Beispielen kennen wir nur einen Teil des Geburtsdatums der Person. In einem Fall kennen wir nur das Jahr; im anderen Fall kennen wir den Monat und den Tag, aber nicht das Jahr.

Wie erfasse ich diese Informationen?

Einige Beispiele, wie dies funktionieren könnte:

Stellen Sie sich eine Bibliothek wie datetime vor, in der None in den Feldern Unbekannte darstellen konnte. Ich könnte Code wie den folgenden haben:

date_a = date(2000, 5, None)
date_b = date(2000, 6, None)
difference = date_b - date_a
assert difference.min.days == 1
assert difference.max.days == 60  # Or something close to 60.
assert equal(date_a, date_b) == False

date_c = date(2000, 5, None)
assert equal(date_a, date_c) == Maybe

Dies ist nur ein Beispiel dafür, wie es sich verhalten könnte. Ich möchte nicht unbedingt genau dieses Verhalten.

Buttons840
quelle
Im Allgemeinen verwenden Sie solche Dinge beispielsweise, indem Sie beispielsweise das Jahr 0001 in .NET für Daten ohne Jahr und den 1. Januar für Jahre ohne Monat und Tag verwenden.
Robert Harvey
Ich habe Ihre Frage bearbeitet, um Anfragen für eine Bibliothek zu entfernen. Solche Fragen sind auf dieser Website nicht zum Thema.
@ RobertHarvey Ich kann Ihren Vorschlag nicht verwenden. Wenn wir sehen, dass Bob am 1. Januar 2000 geboren wurde, wissen wir nicht genau, was dies bedeutet. Wir können nicht sagen, ob er am ersten Tag des Jahres 2000 geboren wurde oder ob er an einem Tag des Jahres 2000 geboren wurde. Wir müssen den Unterschied kennen.
Buttons840
@RobertHarvey Ich weiß, dass dies häufig vorkommt, aber ich habe viele schlechte Fehler gesehen, weil solche Signalwerte schlecht ausgewählt wurden. (Außerdem glaube ich nicht, dass es die Frage beantwortet, da das OP nur einige unbekannte Daten behandeln muss. Wenn Sie in solchen Fällen auf den 1. Januar setzen, können Sie echte Daten vom 1. Januar nicht von Unbekannten unterscheiden.
Gort the Robot
5
@ Buttons840: Dann müssen Sie eine Klasse schreiben, die das gewünschte Verhalten kapselt. Sie sollten die vorhandene Datumsklasse umbrechen und das gewünschte Verhalten hinzufügen.
Robert Harvey

Antworten:

3

Sobald Sie Datumsangaben in ihre Bestandteile zerlegen, sind sie zunächst keine Datumsangaben mehr.

Ebenso wie es nicht möglich ist, Funktionen über Unterklassen zu entfernen, ohne OOP zu beschädigen, ist es nicht möglich, Datums- und Datumsbrüche zu mischen, ohne Verwirrung (oder Schlimmeres) zu verursachen, sodass sie wie in Ihrem Codebeispiel kompatibel sind, ohne etwas anderes zu beschädigen.

Wenn Sie ein Jahr erfassen möchten, was ist mit einem Objekt mit einer einfachen Ganzzahl falsch? Wenn Sie einen Monat und einen Tag erfassen möchten, können Sie eine Monatsaufzählung und einen ganzzahligen Tag erfassen. Vielleicht speichern Sie sie sogar intern in einem Datumsobjekt, damit Sie die richtigen Grenzen überprüfen können (z. B. macht der 31. Februar keinen Sinn). Stellen Sie jedoch eine andere Schnittstelle zur Verfügung.

Warum sollten Sie ein Datum mit einem Jahr vergleichen, um festzustellen, ob sie gleich, größer oder kleiner sind? Es macht keinen Sinn: Es gibt nicht genügend Informationen, um diesen Vergleich durchzuführen. Es gibt jedoch andere Vergleiche, die sinnvoll sein könnten (dies ist ein Pseudocode):

Year y = Year(2015)
Date d = Date(2015, 01, 01)
assert y.contains(d) == True

quelle
2

Robert Harveys zweiter Kommentar enthält die richtige Antwort, aber lassen Sie mich etwas näher darauf eingehen.

Das Geburtsjahr und das Geburtsdatum der Menschen sind völlig unterschiedliche Einheiten, sodass Sie nicht für beide den gleichen Mechanismus verwenden müssen (und sollten).

Für Geburtsdaten können Sie einen BirthDateDatentyp festlegen (oder möglicherweise einen, YearlyRecurringDateobwohl ich momentan keinen anständigen Namen finden kann), der nur einen datemit einem konstanten Jahr enthält, wie z. B. 2000 gemäß Konvention. Das Jahr 2000 ist eine gute Wahl, weil es ein Sprung war, so dass es Menschen, deren Geburtstag am 28. Februar ist, nicht scheitern wird.

Für Geburtsjahre können Sie eine ersinnen BirthYearDatentyp (oder möglicherweise einen ApproximateDateDatentyp) , die ein enthalten würde date, und einen Indikator für die Genauigkeit: Year, Month, Full.

Der Vorteil dieser Ansätze besteht darin, dass Sie im Kern der Dinge immer noch eine beibehalten, datedamit Sie weiterhin Datumsarithmetik durchführen können.

Mike Nakis
quelle
1

Ich glaube, was Sie beschreiben, wäre ein Ersatz für das datetimeModul, das die datetime.datetimeAttribute (Jahr, Monat usw.) als Werte mit einer Unsicherheitsmessung (und nicht nur als Werte) implementiert .

Python-Pakete helfen bei unsicheren Zahlen (z. B. dem Unsicherheitspaket ), und vielleicht wäre es nicht allzu schwierig, eine Verzweigung daraus zu machen datetime, die Unsicherheit für jedes Attribut verwendet. Auch ich würde gerne einen sehen und könnte ihn sogar nutzen. Es könnte durchaus ein Argument für die Aufnahme von a udatetimein das oben genannte Unsicherheitspaket vorgebracht werden.

Ihre Beispiele wären so etwas wie:

bob_bday = udatetime(2000, (6,6))  # 2000-06 +/- 6mo
>>> 2000-??-?? T??:??:??
bil_bday = udatetime((1970, 50), 3, 7)  # assume bill is ~40 +/- 40 
>>> [1970+/-40]-03-07 T??:??:??

"Signalwerte" haben viele Probleme, aber zusätzlich können Sie Dinge mit Unsicherheit darstellen, die Signalwerte nicht können:

# ali was born in spring
ali_bday = udatetime((), (4.5, 1.5))
>>> [1970+/-40]-[4.5+/-1.5]-?? T??:??:??

Eine weitere Überlegung ist, dass die Unsicherheiten hier genauer gesagt tatsächlich vom Typ sein sollten timedelta. Ich überlasse es dem Leser als Übung, einen präzisen und vollständigen Konstruktor für die udatetimeVerwendung von timedeltaUnsicherheiten zu finden.

Letztendlich würde ich also sagen, dass das, was Sie beschreiben, "leicht" mit Unsicherheiten modelliert werden kann, aber die Implementierung von a udatetimeist praktisch ziemlich schwierig. Die meisten nehmen den "einfachen" Weg und teilen die Datums- und Uhrzeitangaben in Komponenten auf und verfolgen die Unsicherheit auf diesen unabhängig voneinander. Wenn Sie sich jedoch ehrgeizig fühlen, ist das uncertaintiesPaket (oder ein anderes) möglicherweise an einer Pull-Anfrage für interessiert udatetime.

7yl4r
quelle
0

Warum nicht eine "Punkt" -Klasse erstellen, die eine Von-Bis-Struktur implementiert?

"Bob wurde im Jahr 2000 geboren" ->

period {
   from  {
      yy = 2000;
      mm = 01;
      dd = 01; 
   }
   to {
     yy = 2000;
     mm = 12;
     dd = 31;
   }
   fuzz = 365;
}

Sie können dann verschiedene Suchmethoden implementieren, indem Sie die Datumsangaben von bis eingeben. Das Fuzz-Attribut gibt einen nützlichen Hinweis darauf, wie genau das Datum ist, sodass Sie Fuzz == 1 für genaue Übereinstimmungen oder Fuzz == 31 für einen Monat oder so angeben können.

James Anderson
quelle