mobeigi / fb2cal

Fetch Facebook Birthdays events and create an ICS file for use with calendar apps
https://go.mobeigi.com/fb2cal
GNU General Public License v3.0
422 stars 73 forks source link

ValueError: day is out of range for month #57

Closed drzel closed 4 years ago

drzel commented 4 years ago

I get the following output on Python 3.7.1

[2020-03-05 01:16:18,223] fb2cal INFO (main) A total of 543 birthdays were found.
[2020-03-05 01:16:18,223] fb2cal INFO (main) Creating birthday ICS file...
Traceback (most recent call last):
  File "src/fb2cal.py", line 815, in <module>
    main()
  File "src/fb2cal.py", line 127, in main
    c = populate_birthdays_calendar(birthdays)
  File "src/fb2cal.py", line 800, in populate_birthdays_calendar
    e.begin = f'{year}-{month}-{day} 00:00:00'
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/ics/event.py", line 155, in begin
    value = get_arrow(value)
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/ics/utils.py", line 196, in get_arrow
    return arrow.get(value)
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/arrow/api.py", line 21, in get
    return _factory.get(*args, **kwargs)
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/arrow/factory.py", line 207, in get
    dt = parser.DateTimeParser(locale).parse_iso(arg)
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/arrow/parser.py", line 131, in parse_iso
    return self._parse_multiformat(string, formats)
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/arrow/parser.py", line 312, in _parse_multiformat
    _datetime = self.parse(string, fmt)
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/arrow/parser.py", line 205, in parse
    return self._build_datetime(parts)
  File "/home/sheldon/.pyenv/versions/3.7.1/lib/python3.7/site-packages/arrow/parser.py", line 301, in _build_datetime
    tzinfo=parts.get("tzinfo"),
ValueError: day is out of range for month
mobeigi commented 4 years ago

Wonder if its a leap year issue with a birthdate on 29 Feb. What language is your Facebook in?

drzel commented 4 years ago

English

benceszabo commented 4 years ago

Hi, thank you for the script! I had the same error and it seems it has to do with the leap year, the script ran fine when I changed all parts with datetime.now() in cur_date and start_date to datetime(2020, 1, 1, 9, 40, 6, 659499).

mobeigi commented 4 years ago

Hmm so from the looks of it there is a friend with a birthday on 29 Feb but it tries to add in a date into the calendar with the year of (cur_date + relativedelta(years=1)).year which is not a leap year. So this is a bug that would have also started occurring since we past the 29th.

Wouldn't have been fixed in: 7da11cf

mindyourlifeguide commented 4 years ago

I have a similar behavior. Although everything worked fine in January.

[2020-03-20 21:56:14,847] fb2cal INFO (main) Creating birthday ICS file...
Traceback (most recent call last):
  File "./fb2cal.py", line 815, in <module>
    main()
  File "./fb2cal.py", line 127, in main
    c = populate_birthdays_calendar(birthdays)
  File "./fb2cal.py", line 800, in populate_birthdays_calendar
    e.begin = f'{year}-{month}-{day} 00:00:00'
  File "/usr/lib/python3.8/site-packages/ics/event.py", line 155, in begin
    value = get_arrow(value)
  File "/usr/lib/python3.8/site-packages/ics/utils.py", line 196, in get_arrow
    return arrow.get(value)
  File "/usr/lib/python3.8/site-packages/arrow/api.py", line 21, in get
    return _factory.get(*args, **kwargs)
  File "/usr/lib/python3.8/site-packages/arrow/factory.py", line 207, in get
    dt = parser.DateTimeParser(locale).parse_iso(arg)
  File "/usr/lib/python3.8/site-packages/arrow/parser.py", line 131, in parse_iso
    return self._parse_multiformat(string, formats)
  File "/usr/lib/python3.8/site-packages/arrow/parser.py", line 312, in _parse_multiformat
    _datetime = self.parse(string, fmt)
  File "/usr/lib/python3.8/site-packages/arrow/parser.py", line 205, in parse
    return self._build_datetime(parts)
  File "/usr/lib/python3.8/site-packages/arrow/parser.py", line 293, in _build_datetime
    datetime(
ValueError: day is out of range for month
kasnder commented 4 years ago

Can confirm I had this error with a friend whose birthday is on 29 Feb.

POIZ87 commented 4 years ago

when i delete my friend who has birthday on feb 29. this would be a workaround?

Haha yes deleted the friend and than it worked fine :)

johnameen commented 4 years ago

So I just looked into this. The issue isn't the fact that there's a person with a leap year in the data, but rather that when there does exist a person with a leap year, the scraper scrapes the dates out of order towards the end of February. The person with the leap year birthday is inserted into the birthdays list in between all the 4/28 birthdays. Confirmed this by first trying a birthdays list with no leap year birthdays, and trying a list without any 4/28 birthdays but with a leap year birthday.

Seems like a pretty easy fix since it doesn't really involve dates, just how the birthdays are being inserted into the birthdays list. A hotfix could be as simple as a sort in the populate_birthdays_calendar function.

Also this could really benefit from an optional caching function. It was painful seeing all the work go away when I hit the error right during export.

Would love to help. Just lmk.

ghost commented 4 years ago

Hi, I got this as well today. The console (only) its showing the following at the tail:-

[2020-05-09 13:02:42,399] fb2cal INFO (main) A total of 99 birthdays were found. [2020-05-09 13:02:42,399] fb2cal INFO (main) Creating birthday ICS file... Traceback (most recent call last): File "src/fb2cal.py", line 815, in main() File "src/fb2cal.py", line 127, in main c = populate_birthdays_calendar(birthdays) File "src/fb2cal.py", line 800, in populate_birthdays_calendar e.begin = f'{year}-{month}-{day} 00:00:00' File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/ics/event.py", line 155, in begin value = get_arrow(value) File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/ics/utils.py", line 196, in get_arrow return arrow.get(value) File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/arrow/api.py", line 21, in get return _factory.get(*args, **kwargs) File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/arrow/factory.py", line 207, in get dt = parser.DateTimeParser(locale).parse_iso(arg) File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/arrow/parser.py", line 131, in parse_iso return self._parse_multiformat(string, formats) File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/arrow/parser.py", line 312, in _parse_multiformat _datetime = self.parse(string, fmt) File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/arrow/parser.py", line 205, in parse return self._build_datetime(parts) File "/Users/davidwishart/.pyenv/versions/3.7.7/lib/python3.7/site-packages/arrow/parser.py", line 301, in _build_datetime tzinfo=parts.get("tzinfo"), ValueError: day is out of range for month

Interestingly (or not) the debug level logging to logs\fb2cal.log has the last line of

[2020-05-09 13:02:42,399] fb2cal INFO (main) Creating birthday ICS file...

It looks like this has already been identified as a bug so I was wondering what if anything I could do so someone could look at resolving?

johnameen commented 4 years ago

I forked your repo @mobeigi and did a pretty ugly/unoptimized fix and also added an caching function for faster testing of bugs closer towards the end (just saving the birthday list to a pickle file) on the forked repo so you can decide if you want to implement the quick-fix. Thank you for this repo. It's really helped.

mobeigi commented 4 years ago

Fixed in #64 . Thanks!

esambe commented 3 months ago

Another good way is to write a python script in Django which runs automatically to delete invalid date entries. For example

myApp/management/commands/fix_invalid_dates.py

class Command(BaseCommand):
    help = 'Fix invalid dates in the database'

    def handle(self, *args, **kwargs):
        with connection.cursor() as cursor:
            # Delete existing records with invalid dates
            cursor.execute("""
                DELETE FROM table_name 
                    WHERE date_field LIKE '%-2-30'
                    OR date_field LIKE '%-2-31'
                    OR date_field LIKE '%-4-31'
                    OR date_field LIKE '%-6-31'
                    OR date_field LIKE '%-9-31';
            """)
        self.stdout.write(self.style.SUCCESS('Successfully fixed invalid dates and updated the database'))

In myApp/apps.py

class myAppConfig(AppConfig):
    name = 'myapp'

    def ready(self):
        try:
            call_command('fix_invalid_dates')
        except Exception as e:
            import logging
            logger = logging.getLogger(__name__)
            logger.error(f"Failed to fix invalid dates: {e}")

This command python manage.py fix_invalid_dates will run automatically or can choose to run it manually. Hope this helps :-)