lk-geimfari / mimesis

Mimesis is a robust data generator for Python that can produce a wide range of fake data in multiple languages.
https://mimesis.name
MIT License
4.39k stars 330 forks source link

Person date of birth #1470

Closed SpoonOfDoom closed 7 months ago

SpoonOfDoom commented 7 months ago

Feature request

I would love it if the Person provider had a function to quickly create a date of birth for a given age range, which imho is a common requirement when creating fake person data. I see that you can work around that with creating random dates and setting fitting start/end dates, but as a quality of life addition, I think a Person.date_of_birth() function would be very useful. See for comparison the way Faker does birthdays: https://faker.readthedocs.io/en/master/locales/de_DE.html?highlight=date_of_birth#faker.providers.date_time.de_DE.Provider.date_of_birth

Thesis

What I propose is that in addition to just age(), you should be able to generate a plausible date of birth for a given person. It should have some sensible defaults, so that for example it doesn't generate 200 year old people or babies, which are unlikely to be users of your application. I think the API that Faker provides is pretty intuitive, so I'm going to use it in these examples.

>>> Person.date_of_birth()
# generates a date anywhere between now and 100 years ago. Alternatively, use 18 as a default minimum age so generated persons are adults unless specified otherwise.
datetime.date(2023, 7, 21)

>>> Person.date_of_birth(minimum_age=18)
# generates a date anywhere between 18 and 100 years ago
datetime.date(1998, 6, 22)

>>> Person.date_of_birth(maximum_age=200)
# generates a date anywhere between now and 200 years ago
datetime.date(1898, 6, 22)

>>> Person.date_of_birth(minimum_age=18, maximum_age=20)
# generates a date anywhere between 18 and 20 years ago
datetime.date(2004, 5, 23)

Reasoning

In a typical application, you usually do not store the user's (or any person's) age as a number. It's far more common to store a date of birth and derive the age from that when you need it. I could use completely random datetimes, but sometimes it's necessary to check certain cases like "is the user 13/18/21 or above", where you need a certain age for the test, but still have it result in a datetime. You can work around this by doing something like

date_of_birth = date(
  start=datetime.now() - relativedelta(years=minimum_age), 
  end=datetime.now() - relativedelta(years=maximum_age)
)

# or 

date_of_birth = datetime.now() - relativedelta(years=Person.age())

but that is not as clean or intuitive as it could be. In my mind, frameworks like this are all about quality of life and plausible data, because otherwise we may as well use raw random numbers and strings everywhere, so in that sense, it would be a useful addition.

If you agree that this is useful, I can work on a pull request for it. If somehow I missed an obvious way to do this already, please point me in the right direction.

lk-geimfari commented 7 months ago

We have a separate provider for the date/time related data: Datetime.

SpoonOfDoom commented 7 months ago

I realize that, but unless I'm overlooking something, nothing that quite does the same thing. I mentioned that there are ways around this using the Datetime or other random numbers. But I argue if Person.age() has a place even though you can generate random numbers in other ways, Person.date_of_birth() has as much use as that, if not more.

MarcelWilson commented 7 months ago

This is a function I came up with.

def date_of_birth(minimum_age: int = 21, maximum_age: int = 115):
    current_year = datetime.now().year
    return gen.datetime.date(
        start=current_year - maximum_age, end=current_year - minimum_age
    )

Which could easily be converted to a method of Datetime.

def date_of_birth(self, minimum_age: int = 21, maximum_age: int = 115):
    return self.date(start=self._CURRENT_YEAR - maximum_age, end=self._CURRENT_YEAR - minimum_age)

When I get a little time I plan to submit a PR.

lk-geimfari commented 7 months ago

I realize that, but unless I'm overlooking something, nothing that quite does the same thing. I mentioned that there are ways around this using the Datetime or other random numbers.

But I argue if Person.age() has a place even though you can generate random numbers in other ways, Person.date_of_birth() has as much use as that, if not more.

I agree. I'll add this method.

lk-geimfari commented 7 months ago

Version 13.1.0 has been published and is available for download. Thanks everyone.

See https://github.com/lk-geimfari/mimesis/releases/tag/v13.1.0 for more details.

I'm closing this issue.