Zero crossing detector that is resistant to being fooled by noise/interference

There are plenty of examples of how to extract a clock signal from a clean waveform, but how do you deal with noise/interference close to the zero point that would trigger a false early detection?
Any kind of low pass filter is going to give a phase shift, so that isn’t an option.

You can avoid multiple subsequent triggers using hysteresis or a blanking period (http://www.ti.com/lit/an/sbaa356/sbaa356.pdf) , but how do you deal with the first early trigger?

Depending on the frequency, but if we talk main, a simple LP filter will give neglectable phase shift.

And again, depending on the application but assuming detecting mains, you can do some stuff in software like an average etc.

I have a mains voltage and frequency measurement circuit that uses a resistive divider to drop mains to the correct input voltage to the the A2D in a PIC. It has a 0μ1 capacitor to remove noise. It does indeed induce a small phase shift, which is compensated for in software.

There are two answers to this.

One is to use a Phase Locked Loop. Easily done in software. (We presume you mean zero crossing of a relatively steady, single frequency sinewave; that is, the power mains.) This automatically facilitates phase compensation.

The other is to use a debouncing algorithm. Polling at the frequency of the main code loop() - which should be well in excess of a thousand cycles per second, you decide that a zero crossing is detected when every one of five successive polls - or every poll while millis() advances by 5 - is the opposite of the state before the crossing. Adjusted to allow for frequencies other than 60 Hz.

Paul__B:
There are two answers to this.

One is to use a Phase Locked Loop. Easily done in software. (We presume you mean zero crossing of a relatively steady, single frequency sinewave; that is, the power mains.) This automatically facilitates phase compensation.

The other is to use a debouncing algorithm. Polling at the frequency of the main code loop() - which should be well in excess of a thousand cycles per second, you decide that a zero crossing is detected when every one of five successive polls - or every poll while millis() advances by 5 - is the opposite of the state before the crossing. Adjusted to allow for frequencies other than 60 Hz.

The PLL approach sounds plausible as presumably the noise will average out to zero over many cycles.
Not too sure about the debounce idea as it sounds like it adds a constant time delay beyond the zero point.

Not too sure about the debounce idea as it sounds like it adds a constant time delay beyond the zero point.

It won't be constant, it will jitter. However, it will be constant on average, so can be compensated for. The very fact we are discussing this points to a truth though; because of noise there is no exact, always definable, unvarying mains crossing point, noise will always make it jitter a bit. What is important, I suggest, is designing your circuit to take this into account in a way that is appropriate for your application.