Come modellare le date parziali in Python? Come un anno sconosciuto, o un giorno sconosciuto del mese?

10

Voglio essere in grado di catturare fatti come Bob was born in 2000 e Bill's birthday is May 7th .

In entrambi gli esempi conosciamo solo una parte della data di nascita della persona. In un caso conosciamo solo l'anno; nell'altro caso conosciamo il mese e il giorno, ma non l'anno.

Come posso acquisire queste informazioni?

Alcuni esempi di come potrebbe funzionare:

Immagina una libreria come datetime che consenta a None nei campi di rappresentare incognite. Potrei avere il codice come il seguente:

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

Questo è solo un esempio di come potrebbe comportarsi. Non voglio necessariamente questo comportamento preciso.

    
posta Buttons840 18.05.2015 - 19:00
fonte

4 risposte

3

Prima di tutto, quando inizi a scomporre le date nei componenti costitutivi, non sono più date.

Allo stesso modo in cui non è possibile rimuovere funzionalità tramite sottoclassi senza interrompere OOP, non è possibile mescolare date e frazioni di date senza causare confusione (o peggio) rendendole compatibili come nell'esempio di codice senza rompere qualcos'altro .

Se vuoi catturare un anno, cosa c'è di sbagliato in un oggetto che contiene un intero semplice? Se si desidera catturare un mese e un giorno, perché non acquisire un'enumerazione del mese e un giorno intero? Forse anche memorizzarli internamente in un oggetto data in modo da ottenere il controllo corretto dei limiti (ad esempio, 31 febbraio non ha senso). Esporre comunque un'interfaccia diversa.

Perché vorresti confrontare una data con un anno per vedere se sono uguali, maggiori o minori? Non ha senso: non ci sono informazioni sufficienti per fare quel confronto. Tuttavia, ci sono altri confronti che potrebbero avere senso (questo è pseudocodice):

Year y = Year(2015)
Date d = Date(2015, 01, 01)
assert y.contains(d) == True
    
risposta data 18.05.2015 - 19:44
fonte
2

Il secondo commento di Robert Harvey contiene la risposta giusta, ma lascia che mi espandi un po '.

L'anno di nascita e le date di nascita delle persone sono entità completamente diverse, quindi non è necessario (e in realtà non dovresti) utilizzare lo stesso meccanismo per entrambi.

Per i data di nascita, puoi escogitare un tipo di dati BirthDate (o possibilmente un YearlyRecurringDate anche se al momento non riesco a trovare un nome decente) che conterrebbe solo un date con un anno costante, come 2000 di convenzione. L'anno 2000 è una buona scelta perché è stato un salto, quindi non mancheranno le persone il cui compleanno è il 28 febbraio.

Per anni di nascita, puoi escogitare un tipo di dati BirthYear (o possibilmente un tipo di dati ApproximateDate ) che conterrebbe un date e un indicatore della precisione: Year , Month ,% % co_de.

Il vantaggio di questi approcci è che al centro delle cose mantieni ancora un Full in modo che tu possa ancora eseguire l'aritmetica della data.

    
risposta data 18.05.2015 - 19:44
fonte
1

Credo che quello che stai descrivendo sarebbe una sostituzione drop-in per il modulo datetime che implementa gli attributi datetime.datetime (anno, mese, ecc.) come valori con una misurazione dell'incertezza (piuttosto che solo valori).

Esistono pacchetti Python per aiutare con numeri incerti (ad esempio: il incertezza pacchetto), e forse non sarebbe troppo difficile crea un fork di datetime che utilizza l'incertezza su ciascun attributo. Anch'io vorrei vederne uno e potrei persino usarlo. Un argomento potrebbe certamente essere fatto per l'inclusione di un udatetime nel pacchetto delle incertezze prima collegate.

I tuoi esempi sarebbero qualcosa di simile a:

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??:??:??

"I valori del segnale" hanno molti problemi, ma in aggiunta puoi rappresentare le cose con incertezza che i valori del segnale non possono:

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

Un'altra considerazione è che, per essere più precisi, le incertezze qui dovrebbero effettivamente essere di tipo timedelta . Lascio come esercizio per il lettore capire un costruttore conciso e completo per udatetime usando timedelta incertezze.

Quindi alla fine direi che ciò che descrivi è "facilmente" modellato con incertezze, ma l'implementazione di un udatetime è praticamente abbastanza difficile. La maggior parte prenderà il percorso "facile" e rompere il datetime in componenti e tracciare le incertezze su di essi in modo indipendente, ma se ti senti ambizioso il pacchetto uncertainties (o un altro) potrebbe essere interessato a una richiesta pull per udatetime .

    
risposta data 27.06.2018 - 00:10
fonte
0

Perché non creare una classe "period" che implementa una struttura da a.

"Bob è nato nel 2000" - >

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

È quindi possibile implementare vari metodi di ricerca come il bracketing delle date da a. L'attributo fuzz fornisce un'utile indicazione di quanto accurata sia la data in modo da poter specificare fuzz == 1 per le corrispondenze esatte, o fuzz == 31 per entro un mese circa.

    
risposta data 27.06.2018 - 10:46
fonte

Leggi altre domande sui tag