Wrong Dates in iCal Birthday Calendar

To keep track of people’s birthdays, I use Mac OS X’s1 Birthday Calendar feature of Address Book/iCal. I was going through my calendar the other day, and I noticed that a birthday which I knew was sometime in January wasn’t showing up. It was on the corresponding Address Book contact, though. I deleted the birthday from this contact and reentered it, which fixed that entry, but on the suspicion that more birthdays might be missing, I flipped through my calendar and found:2

Address Book says Mar 23, iCal says Mar 21

The Address Book birthday field has the misfeature that it forces a year to be specified.3 What a rude thing for Address Book to be asking! Anyway, I’d arbitrarily picked year 14 for the year for any contacts whose birth years I didn’t know. Maybe, I thought, the Gregorian reform was throwing things off. However, changing the year to 1900 didn’t help matters, and in fact made them worse:

Address Book says Mar 23, iCal says June 23

Turning the birthday calendar off (which wipes out iCal’s backing store for the calendar) and on didn’t help matters. A web search turned up some other people having the same problem, but the only useful solution they came up with was deleting and recreating entire contacts by hand.

I wanted to see if the raw data was wrong in Address Book’s database. Address Book uses Core Data in a way that makes the database difficult to work with at the SQLite command-line level, so instead I hacked /Developer/Examples/Python/PyObjC/AddressBook/Scripts/exportBook.py to emit the birthday field by adding ('Birthday', AddressBook.kABBirthdayProperty) to FIELD_NAMES and the following to encodeField:

 
    elif isinstance(value, AppKit.NSCalendarDate):
        return value.descriptionWithCalendarFormat_("%Y-%m-%d")
 

It turns out that a number of entries had negative years, e.g. -1900-03-23 instead of 1900-03-23. I’m not sure how this happened, but here’s a script (which you can download) to fix it:

  1.  
  2. #!/usr/bin/python
  3. """
  4. Fix negative birthday years in Address Book.
  5. This work is hereby released into the Public Domain.
  6. """
  7. import AddressBook
  8. import AppKit
  9.  
  10. def personName(person):
  11. return "%s %s" % (
  12. person.valueForProperty_(AddressBook.kABFirstNameProperty),
  13. person.valueForProperty_(AddressBook.kABLastNameProperty)
  14. )
  15.  
  16. def formatDate(date):
  17. return date.descriptionWithCalendarFormat_("%Y-%m-%d")
  18.  
  19. def fixBirthday(birthday):
  20. year = int(birthday.descriptionWithCalendarFormat_("%Y"))
  21. if year < 0:
  22. return birthday.dateByAddingYears_months_days_hours_minutes_seconds_(
  23. -year * 2, 0, 0, 0, 0, 0)
  24. else:
  25. return None
  26.  
  27. def fixPersonBirthday(person):
  28. birthdayProp = AddressBook.kABBirthdayProperty
  29.  
  30. birthday = person.valueForProperty_(birthdayProp)
  31. if birthday == None: return
  32.  
  33. fixedBirthday = fixBirthday(birthday)
  34. if fixedBirthday != None:
  35. print "Fixing up %s: %s -> %s" % (
  36. personName(person),
  37. formatDate(birthday),
  38. formatDate(fixedBirthday)
  39. )
  40. person.setValue_forProperty_(fixedBirthday, birthdayProp)
  41.  
  42. book = AddressBook.ABAddressBook.sharedAddressBook()
  43.  
  44. for person in book.people():
  45. fixPersonBirthday(person)
  46.  
  47. book.save()
  48.  

  1. 10.5.1, MacBook Pro Core 2 Duo 

  2. Names have been changed to protect the innocent. 

  3. There’s also an implementation flaw; I have my date format set to YYYY-MM-DD, and when I try to enter a year in the field, whether or not pressing a number on the keyboard will actually result in a digit appearing in the input field appears to be random. It also behaves very weirdly if there are four digits in the field already and I press another digit. I wish I could get a video of all this, but it’s not quite worth the effort of taking a screencast and a video of my fingers on the keyboard and then splice them together… 

  4. Anno Domini, not Anno Antidomini 

Tags: , ,

16 Responses to “Wrong Dates in iCal Birthday Calendar”

  1. frodo says:

    Matthew, would you mind sharing how would someone like me, who is unfamiliar with Python, go about executing this script on Leopard?

    Thanks,

    Frodo

  2. Matthew says:

    frodo:

    1. Copy the script to your clipboard
    2. Open TextEdit (in your Applications folder)
    3. Select Format > Make Plain Text from the menu bar
    4. Paste in the script
    5. Save the script to your home directory, naming it fixBirthdays . Uncheck If no extension is provided, use ".txt" in the save dialog.
    6. Open Terminal (in the Utilities folder, under Applications)
    7. Type python fixBirthdays and hit return.

    That should do it.

  3. frodo says:

    Hey Matt

    Thanks for the excellent instructions! It worked, but I still find it strange that Apple doesn’t address this issue more seriously along with the implementation flaw you described above. Anyways, thanks again!

    frodo

  4. Stephen says:

    Thanks so much! I had the exact same problem. The problem is, after I ran your script, my dates were off by 17 days. I couldn’t figure out why. Anyway, that was still a big help. =)

  5. Semi says:

    I ran your script but all I’m getting in Address Book is a place for the initial of the month (“M” for May e.g.) and then four digits of the year. Won’t let me enter a day and says all birthdays are on the first of the month. I’m on Leopard 10.5? Thanks!

  6. Semi says:

    I ran your script and now none of my dates in iCal will work. It won’t let me enter anything that lasts for longer than one day and it won’t allow me to put in the “day”, only the month and year - the same problem I have been having with birthdays.

  7. Samuel says:

    Thanks! It works!

  8. Orlin says:

    Thanks a lot for sharing the script! However, I’m unable to copy it - as well as having the line numbers, all the indentation gets lost and as far as I know it’s important in Python. Do you know of some workaround? If not, I’ll re-type it by hand…

  9. Matthew says:

    I’m unable to copy [the script] … Do you know of some workaround?

    Here’s a plaintext copy.

  10. Orlin says:

    Thanks a lot!

    It worked, though I had to manually add a year and 17 days to the birthdays (corrected the script for future use).

  11. jeby says:

    “ImportError: No module named AddressBook”

    something wrong…

  12. Pierre says:

    Hello, I have a bug with birthday date in AdressBook application. For example, if I enter april 17th 0001 in the AdressBook, it’s read: BDAY;value=date:1-04-15 when I edit the vCard and it shows on April 15th in iCal. I have the same problem with all my vCards with birthday. I don’t know hiw to fix this bug. Pierre.

  13. ken says:

    i get the error

    python fixBirthdays Traceback (most recent call last): File “fixBirthdays”, line 6, in import AddressBook ImportError: No module named AddressBook

    any way to make it work?

  14. BR says:

    Wondering if tila will fix the issues I’m having, where random days are added to the birthday. Example: mine is Feb 6, but iCal adds a day to it, making it the 7th. Another friend’s is 8.02.1960, and it’s added 10 days to the entry, and now reads 8.12.60!!?

    I’ve deleted the entry in address book, and re-entered data. It stays for awhile (maybe. Week?) and then today, I looke again and the date was changed back to the 12th (from the 2nd)

  15. c_alpha says:

    I also discovered that iCal cannot handle dates before 1900-01-01. So I extended the fixBirthday function as follows:

    def fixBirthday(birthday):
        year = int(birthday.descriptionWithCalendarFormat_("%Y"))
        if year < 0:
            return birthday.dateByAddingYears_months_days_hours_minutes_seconds_(
                -year * 2, 0, 0, 0, 0, 0)
        elif year < 1900:
            return birthday.dateByAddingYears_months_days_hours_minutes_seconds_(
                1900-year, 0, 0, 0, 0, 0)
        else:
            return None
    

    This moves all birthdays before 1900-01-01 to their respective date in the year 1900. Voila, all birthday headaches with iCal fixed.

    Thanks Matthew, for a) finding out about this brain-dead bug, and b) sharing your fix. Great job!

  16. Carles Tomás Martí says:

    I just stumbled onto this bug when I called a relative to congratulate her birthday… Geeez…

    Anyway, now it should be fixed. But checking the dates it strikes me that this bug has been around since 2007 and Apple still hasn’t fixed it.

Leave a Reply

Use Markdown, a wiki-like syntax, to write your comment. Basic HTML tags will also work. For source code with syntax hilighting and line numbers, wrap the code in <pre lang="language" lineno="1">...</pre>

Show Markdown help.

Write Markdown text as if you were writing a plain-text email. Some examples:

  • Paragraphs: Blank lines between blocks of text
  • Links: [link text](http://url.example.com/) or [link text][ref]
  • Bold and italic: *Single* and **double** asterisks respectively
  • Lists: List items start with * or 1.
  • Quoting: Like email, quoted lines start with >
The rise of the [hamburger](http://hamburger.example.com/)
as a form of *currency* can be **attributed** to several
aspects of [Akkadian][akad] [civilization][civ].

   [akad]: http://icanhasgilgamesh.example.com/
   [civ]: http://uruk.example.com/

Yes, the most delicious hamburger of all is not brown, but
green. The green of money. Denominations of hamburger
(and current value in USD:)

* 1/4-pounder ($3.79)
* Cuneiform, or "Cuney" ($8.00)

Problems with the currency:

1. Deflation due to hunger
2. Fraud (soy fillers)
3. Hamburgers not invented yet

As Dr. Tabi said:
> Wallets became foetid and repulsive.
> This was quite the boon for the influential
> Guild of Wallet-Washers.

The rise of the hamburger as a form of currency can be attributed to several aspects of Akkadian civilization.

Yes, the most delicious hamburger of all is not brown, but green. The green of money. Denominations of hamburger (and current value in USD:)

  • ¼-pounder ($3.79)
  • Cuneiform, or “Cuney” ($8.00)

Problems with the currency:

  1. Deflation due to hunger
  2. Fraud (soy fillers)
  3. Hamburgers not invented yet

As Dr. Tabi said:

Wallets became foetid and repulsive. This was quite the boon for the influential Guild of Wallet-Washers.

Comments will be sent to the moderation queue.

Subscribe without commenting