Як я моделюю часткові дати в Python? Як невідомий рік, чи невідомий день місяця?


11

Я хочу вміти фіксувати такі факти, як Bob was born in 2000і Bill's birthday is May 7th.

В обох прикладах ми знаємо лише частину дати народження людини. В одному випадку ми знаємо лише рік; в іншому випадку ми знаємо місяць і день, але не рік.

Як зафіксувати цю інформацію?

Кілька прикладів, як це може працювати:

Уявіть бібліотеку, як дата, яка дозволила "None" у полях представляти невідомі. У мене може бути такий код, як наступний:

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

Це лише приклад того, як воно може вести себе. Мені не обов’язково хочеться такої точної поведінки.


Взагалі спосіб, яким ви займаєтесь подібними справами, полягає у використанні, наприклад, року 0001 в .NET для дат, у яких немає року, і 1 січня протягом років без місяця та дня.
Роберт Харві

Я відредагував ваше запитання, щоб видалити запити на бібліотеку. Такі питання поза темою на цьому веб-сайті.

@RobertHarvey Я не можу використовувати вашу пропозицію. Якщо ми бачимо, що Боб народився 1 січня 2000 року, ми не знаємо, що це означає саме. Ми не можемо сказати, народився він у перший день 2000 року, чи він народився у будь-який день 2000 року. Нам потрібно знати різницю.
Кнопки840

@RobertHarvey Я знаю, що це звичайне явище, але я бачив багато поганих збоїв через поганий вибір таких значень сигналу. (Плюс до цього, я не думаю, що це відповідає на питання, оскільки ОП потребує вирішення лише деяких дат, невідомих. Встановлення 1 січня в таких випадках не дозволяє відрізняти реальні дати 1 січня від невідомих.
Gort the Robot

5
@ Buttons840: Тоді вам доведеться написати клас, який інкапсулює поведінку, яку ви хочете. Ви повинні обернути наявний клас дати та додати бажане поведінку.
Роберт Харві

Відповіді:


3

Перш за все, щойно ви починаєте розкладати дати на їх складові, вони вже не є датами.

Так само, як неможливо видалити функціональність за допомогою підкласів, не порушуючи OOP, неможливо змішати дати та дроби, не викликаючи плутанини (або ще гірше), роблячи їх сумісними, як у прикладі вашого коду, не порушуючи щось інше.

Якщо ви хочете захопити рік, що не так з об'єктом, що містить просте ціле число? Якщо ви хочете зафіксувати місяць і день, чому б не взяти перерахунок за місяць і цілий день? Можливо, навіть зберігайте їх всередині об’єкта дати, щоб ви отримали належну перевірку меж (наприклад, 31 лютого немає сенсу). Однак відкрийте інший інтерфейс.

Чому ви хочете порівняти дату з роком, щоб побачити, чи вони однакові, більші чи менші? Немає сенсу: для порівняння немає достатньої інформації. Однак є й інші порівняння, які можуть мати сенс (це псевдокод):

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

2

Другий коментар Роберта Харві містить правильну відповідь, але дозвольте мені трохи розширити його.

Рік народження людей та дані про народження людей - це абсолютно різні сутності, тому вам не потрібно (а насправді не слід) використовувати один і той же механізм для обох.

Що стосується даних про народження, ви можете розробити BirthDateтип даних (або, можливо, YearlyRecurringDateя не можу придумати гідне ім'я зараз), який би містив dateлише постійний рік, як 2000 за умовами. 2000 рік є хорошим вибором, тому що він був високосним, тому він не підведе людей, у яких день народження 28 лютого.

За рік народження, ви можете розробити BirthYearтип даних (або , можливо, ApproximateDateтип даних) , який буде містити date, і показник точності: Year, Month, Full.

Перевага цих підходів полягає в тому, що в основі речей ви все ще зберігаєте, dateщоб ви все ще могли виконувати арифметику дати.


1

Я вважаю, що те, що ви описуєте, було б заміною datetimeмодуля, який реалізує datetime.datetimeатрибути (рік, місяць тощо) як значення з вимірюванням невизначеності (а не просто значення).

Пакети Python існують, щоб допомогти з невизначеними числами (наприклад, пакунок невизначеності ), і, можливо, було б не надто важко зробити вилку, datetimeяка використовує невизначеність для кожного атрибута. Я теж хотів би побачити його і, можливо, навіть використати його. Безумовно, можна навести аргумент щодо включення програми udatetimeдо вищезазначеного пакету невизначеностей.

Ваші приклади були б на кшталт:

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

"Значення сигналу" мають багато питань, але крім того, ви можете представляти речі з невизначеністю, що значення сигналу не можуть:

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

Ще одне врахування полягає в тому, що якщо бути точнішим, то тут невизначеності повинні насправді носити тип timedelta. Я залишаю це як вправу для читача розібратися у стислій та завершеній конструкції udatetimeвикористання timedeltaневизначеностей.

Тому в кінцевому підсумку я б сказав, що те, що ви описуєте, "легко" моделюється з невизначеностями, але реалізація програми udatetimeпрактично досить складна. Більшість вирушить по "простому" маршруту і розбить дату на компоненти та відстежують невизначеність щодо них самостійно, але якщо ви відчуваєте себе амбітним, uncertaintiesпакет (чи інший) може зацікавити запит на тягу udatetime.


0

Чому б не створити клас "period", який реалізує a від структури.

"Боб народився в 2000 році" ->

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

Потім ви можете реалізувати різні способи пошуку, такі як дужка з датами. Атрибут fuzz дає корисну інформацію про те, наскільки точна дата, тому ви можете вказати fuzz == 1 для точного відповідності, або fuzz == 31 протягом місяця або близько того.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.