bookwyrm icon indicating copy to clipboard operation
bookwyrm copied to clipboard

Allow dates to be only year

Open gary-host-laptop opened this issue 3 years ago • 14 comments

Is your feature request related to a problem? Please describe. Currently dates need to be a full date with day, month and year.

Describe the solution you'd like To be able to to set only year, since a lot of older or not so known books don't have that specific data available.

Describe alternatives you've considered N/A

Additional context N/A

gary-host-laptop avatar Mar 15 '21 18:03 gary-host-laptop

#863 doesn't do this, but it's adjacent

mouse-reeve avatar Apr 04 '21 02:04 mouse-reeve

i got a dev environment set up and looked around the codebase a bit; i'd love to work on this! how would you want it implemented in terms of ui/database though? a date input can't be used for just a year (and likewise the DateTimeField uses datetime which doesn't support just a year). i was thinking maybe using a toggle switch to change the form to use a number input (sorry for the quick terrible mockup) image

and then have the form's clean method check the toggle box, and if set, set the date to datetime(year, 1, 1) along with an additional year_only flag set to true

does that sound alright? if there are other ideas please lmk :)

ghost avatar Apr 05 '21 16:04 ghost

alternatively, could drop the toggle switch and just display both inputs. might be a little confusing in the ui, but would be less code on the frontend and backend

ghost avatar Apr 05 '21 19:04 ghost

I think the toggle is a good idea, if it isn't too much effort to get the frontend stuff working for it. I wish there was a better database solution to this (since year-only dates will be indistinguishable from books actually published on January 1st), but I'm not thinking of one! Which is all to say, go for it @void-witch

mouse-reeve avatar Apr 05 '21 20:04 mouse-reeve

cool! yeah, the only "better" solution i can think of would be a custom field that saves to a string, but that's super complex and also you lose db optimizations because of not using a date type i'll look into it and report back when i have something! :3

ghost avatar Apr 05 '21 20:04 ghost

This issue is still open but the associated PR is closed (rather than merged) and the user working on it is no longer registered. @arkhi @mouse-reeve do you know the current status? This kinda annoys me every time I add a book because I only ever have the year of publication (which usually is all we want), so I'd be happy to assist if help is needed.

hughrun avatar Jan 17 '22 07:01 hughrun

@hughrun: As far as I know (from a few months back), this issue is stalled and could definitely use a hand. Thanks for bringing that up!

arkhi avatar Jan 18 '22 07:01 arkhi

The change to the date picker widget that I have a PR for above should make the UI aspect of this much more straightforward. The form validation still requires a full date at this point, however.

mouse-reeve avatar Mar 19 '22 15:03 mouse-reeve

Instead of using the flag … would it be an option to split the field up into three parts? Akin https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input/date#html

Implementation wise that would be a custom input instead of Django's native ones.

Ryuno-Ki avatar May 03 '22 14:05 Ryuno-Ki

Yep! We had the exact same idea, and a couple months ago I switched to a custom three part Django form widget for publication dates. The fields are still all required, but from a UI perspective it's ready for that, and the flag is no longer necessary.

Current UI: Screen Shot 2022-05-03 at 7 59 05 AM

mouse-reeve avatar May 03 '22 15:05 mouse-reeve

Any news on this? Just ran into the same issue when I tried to manually add a book and it wouldn't accept 2021 as publishing date, but I don't know the exact day it was published on.

mxamber avatar Sep 07 '22 12:09 mxamber

Unfortunately this is still stalled (it bugs me all the time, too). I had a vague recollection of there being a way to store dates like this in Postgres but I can't find it and now I wonder if it was just wishful thinking. Barring that, perhaps the best solution is to store the date precision as an enum (down to the year, month, or day) in addition to the date, and default to January 1st for absent information. From the user's perspective, you would leave the day and/or month field blank, in the database it would be stored as a regular date, and then in the display of the book, only the relevant part of the date would be shown.

mouse-reeve avatar Sep 08 '22 17:09 mouse-reeve

If we're storing a date object in Postgres it has to have a day and month:

https://www.postgresql.org/docs/current/datatype-datetime.html

I was working on this a couple of months ago but gave up because I couldn't work out how to set a default value if the input is empty when the user saves the form. As far as I can tell that's the only solution: set any empty values to 01 before storing in the database.

hughrun avatar Sep 08 '22 21:09 hughrun

If the data is not necessarily a date (just YYYY, a YYYY-MM or a full date) and it’s annoying for everyone, then maybe the data type is not the right one?

Could this be three fields made of numbers (0-31, 1-12, -infity to current year) and that’s it? That would allow to not add erroneous data (January 1st) in many cases. In case of a full date, the switch mentioned in a previous comment could work too but that would make the DB more difficult to deal with, I guess.

arkhi avatar Sep 11 '22 13:09 arkhi

Drawback are invalid dates such as 31st February …

Ryuno-Ki avatar Sep 24 '22 17:09 Ryuno-Ki

Could this be three fields made of numbers (0-31, 1-12, -infity to current year) and that’s it? That would allow to not add erroneous data (January 1st) in many cases. In case of a full date, the switch mentioned in a previous comment could work too but that would make the DB more difficult to deal with, I guess.

Drawback are invalid dates such as 31st February …

Since data should be checked before being stored anyway, what would be the roadblock with checking for validity before the date or its components are stored?

arkhi avatar Sep 30 '22 15:09 arkhi

Dates can be tricky: https://github.com/kdeldycke/awesome-falsehood#dates-and-time

Just saying. I see a lot of maintenance burden here.

Ryuno-Ki avatar Sep 30 '22 15:09 Ryuno-Ki

Dates are tricky overall, indeed, but we’re not aiming for precision here, quite the opposite. :)

I’m no python developer but wouldn’t a dateutil.parser.isoparse be enough?

arkhi avatar Sep 30 '22 16:09 arkhi

I defer to @mouse-reeve for a decision. Keep in mind that migrations are likely necessary. They has a better connection to fellow instances to make a judgement call, whether it is worth it.

Ryuno-Ki avatar Sep 30 '22 16:09 Ryuno-Ki

The reality is that the vast majority of bibliographic metadata in the world only lists a publication year, or at most a month as well. The only reason to care about a specific day is that the Bookwyrm database field was originally a datetime.

hughrun avatar Oct 01 '22 07:10 hughrun

As I see it, both database-level solutions (either using a datetime field and storing the precision, or storing the year and month and day as separate date fields) have advantages and disadvantages, and it's not super obvious which is better in the application as it is. I'm favoring using a datetime field and precision enum because it would mean that it's not super hard to do date math. If you're manipulating the dates in python, @arkhi is quite right that parsing the date after loading the object would be a simple solution. However, if you wanted to query, for example, every book published between 3 and 5 years ago, or sort a queryset by publication date, you'd have a very challenging query ahead of you.

Since querying based on publication time seems like a pretty expected use case to me (it may also be how the author page is sorted, I don't recall off the top of my head), I'm inclined to keep the database field as a datetime field. Does that make sense to yall? Am I missing something in my reasoning? Extremely grateful for all your input ❤️

mouse-reeve avatar Oct 14 '22 19:10 mouse-reeve

I think there may possibly be a solution that pleases everyone here.

@mouse-reeve's explanation makes sense. Generally dates should always be Dates as @Ryuno-Ki points out above.

However the original point of this issue is that it's a crappy user experience to have to enter full dates, given that most of the time the publication month and day are unknown to the user and almost everyone else. If seems unlikely that there would be a pressing use-case for searching publication dates with more specificity than a year, so can we set the value of a "blank" day or month to 1 such that if a user enters only a year, Bookwyrm set the date to 1 January {year}?

I did some testing and it seems this might be as easy as swapping out two lines of code in SelectDateWidget within forms/widgets.py:

# old
if not self.is_required:
    month_choices.insert(0, self.month_none_value) # self.month_none_value equates to "(0, '---')"
# new
if not self.is_required:
    month_choices.insert(0, (1, '---'))

I find Django widgets a little bamboozling, however, so it's possible this might cause problems I haven't anticipated.

hughrun avatar Oct 15 '22 01:10 hughrun

Agreed! I don't think there's anything up in the air about how the UI should work from the user's perspective; you should be able to leave the day and/or month blank as fitting. The reason for the database discussion is, once you've create a date that's like 2022-01-01, how do you know if that's a book that was published in 2022, or a book that was published in January of 2022. If the year really only ever mattered, it would be a trivial problem, but I do think there can be publication dates that are meaningful down to the day (when I'm waiting for the next book in a series, for example, I care very much when specifically it will get released).

I'm glad you dug into that widget; I think I copy/pasted it nearly wholesale from the django source code so that's a valuable insight into how it works even though git blame acts like I wrote it 😂

mouse-reeve avatar Oct 15 '22 02:10 mouse-reeve

Once we get around to fixing this on a database level, #2660 needs attention as well given that any book coming in via ActivityPub's federation, or the connectors which transform the data into ActivityPub's format first, uses dateutil.parser.parse which fills in the blanks with the current date and turns a string like "2022" into datetime.datetime(2022, 2, 13, 0, 0) (Feb 13 being the date today).

chdorner avatar Feb 13 '23 18:02 chdorner

I've been low-key thinking about this a bit over the past days. What do you think about this proposal:

We create a new Django field type. Naming is hard, but let's say for now we'd call it DateWithNullablePartsField, it would work like this:

  • on a database level it's a plain old string storing the date as YYYY-MM-DD
  • in Python the field is a value object with data accessors for .day, .month, .year
  • Day and month parts would be allowed to be null, not year, in which case the whole field and column should be null
  • when translating the field from Python to the value that Django will send to the database we:
    1. construct an ephemeral string with the format YYYY-MM-DD field, important here is that for nullable months and days we use the value 01, because:
    2. we parse this ephemeral string into a Python date with a strict parser (not dateutil) to validate the date
    3. if valid, construct a similar string, but replace the nullable parts with 00 (i.e. 2023-02-00 for February 2023)
    4. send this string with the null parts zeroed out to Django to send to the database
  • when translating the field from the database to Python we:
    1. parse the string with a regex (since 2023-02-00 is an invalid date)
    2. fill in the values into the value object

I'm still not entirely sure how to support ordering based on the first-/published dates with those field types. Maybe the solution to that could be that we store two columns each, one as described above, and one as an actual date field where the nullable parts default to 01. We could then use that date field for ordering.

chdorner avatar Feb 17 '23 11:02 chdorner

I have two commits in this draft PR each showcasing two separate solutions to this. Both are proofs of concept and only deal with the Book edit form rendering and submitting. They don't include any changes for where we render the dates or federating them out to other instances.

I will humbly remove the "good first issue" label because this is anything but easy 😅

chdorner avatar Feb 25 '23 19:02 chdorner

Just ran into this again. tbh it's baffling, I don't think I've ever seen any book that had a full YYYY MM DD date in it, only ever years.

mxamber avatar Mar 26 '23 10:03 mxamber

I'm manually importing all the niche books from my Goodreads import that aren't in the database (speaking of which: Inventaire often imports complete word salad), and the inability to file books with only a year is currently messing it all up.

mxamber avatar Mar 26 '23 13:03 mxamber

I’m mentioning my previous proposal again. :)

arkhi avatar Mar 27 '23 11:03 arkhi

Just ran into this again. tbh it's baffling, I don't think I've ever seen any book that had a full YYYY MM DD date in it, only ever years.

@mxamber: I can give you a couple of example:

  • https://bookwyrm.social/book/487779/s/skating-polly
  • https://bookwyrm.social/book/860271/s/la-tristesse-de-lelephant
  • https://bookwyrm.social/book/894692/s/la-societe-vue-du-don
  • https://bookwyrm.social/book/361882/s/le-monde-sans-fin
  • https://bookwyrm.social/book/846250/s/la-tyrannie-du-divertissement
  • https://bookwyrm.social/book/567256/s/culottees-2
  • https://bookwyrm.social/book/645428/s/dictionnaire-bilingue-lsffrancais
  • https://bookwyrm.social/book/618692/s/parce-que-les-tatouages-sont-notre-histoire
  • https://bookwyrm.social/book/303166/s/lorigine-du-monde
  • https://bookwyrm.social/book/611457/s/le-traite-de-miamologie-les-legumes

Most of the books I added recently, in fact. The dates come from the Publisher’s website.

arkhi avatar Mar 27 '23 11:03 arkhi