Standard cron syntax is quite simple, it does not support exclusions.
In some cases it is possible to create a list of several/many cron entries to implement such logic, but that tends be tedious and hard to understand or maintain; this approach is not applicable in your case though (not least because standard cron has no notion of the calendar year).
It's not a great plan to make cron commands complicated, but you can do this with something relatively straightforward like:
0,30 18-20 * * sat,sun [ "$(date +\%Y\%m\%d)" = "20140510" ] || mycommand
0 21 * * sat,sun [ "$(date +\%Y\%m\%d)" = "20140510" ] || mycommand
0,30 18-21" the task would also run at 21:30; you need the second line if you wish to run also at 21:00, if not then omit it)
NOTE: In some crontabs you must escape percentage signs (they are used to indicate newlines when stuffing inline data into standard input of the command), though not in Dillon's cron.
The cron command is really a shell command list, the
|| control operator provides short-circuit evaluation of commands. Commands in the list are attempted one at a time, from left to right, but the execution stops when first one returns true.
If the date string comparison returns true (only true for one day)
mycommand is not run, when the date comparison returns false
mycommand is run.
Note however, many things can differ in the way cron starts programs. The most robust approach is to use a wrapper script to implement your conditional logic.