La functión DateAdd nos habilita agregar o restar epocas a una fecha- desde milisegundos hasta años.
Generalmente la función devuelve resultados logicos y previstos, a menos que se trate de agregación de meses o de trimestres o de años a fechas que estan en fines de meses.
Por ejemplo- si agregáramos un mes a 30/04/2012 a que fecha llegaríamos- 31/05/2012 o 30/05/2012?
De lo contrario- si agregáramos un mes a 31/05/2012 llegaríamos a 30/06/2012 o a 01/07/2012?
Vamos a probar algunos casos extremos problematicos:
If Object_ID('tempdb..#T','U') Is Not Null Drop Table #T;
Go
Create Table #T(D DateTime);
Go
Insert
Into #T
Select '20120430' Union All
Select '20120430 13:00:00.000' Union All
Select '20110228' Union All
Select '20120228' Union All
Select '20120401' Union All
Select '20120429' Union All
Select '20110228' Union All
Select '20120227' Union All
Select '20120229' Union All
Select '20120131' Union All
Select '20120130' Union All
Select '20120129';
Go
Select D,
DateAdd(Month,1,D) [AddMonth],
DateAdd(Quarter,1,D) [AddQuarter],
DateAdd(Year,1,D) [AddYear]
From #T;

Los resultados son interesantes (los numeros son de las filas):
1. Un mes despues de 30/04/2012 (el fin de Abril) – la funcion devuelve 30/05/2012 en lugar de 31/05/2012.
3. Un mes despues de 28/02/2011 (el fin de Febrero) – la funcion devuelve 28/03/2011 en lugar de 31/03/2011.
4. Un mes despues de 28/02/2012 (el dia anterior al fin de Febrero) – la función devuelve logicamente 28/03/2012.
9. Un año despues de 29/02/2012 – la función devuelve 28/02/2013 (correcto).
10, 11, 12. Un mes despues de 29-30-31/01/2012 la función devuelve en los tres casos 29/02/2012 (parece correcto a menos que intentasemos el ultimo dia, el dia anterior el ultimo dia, el dia anterior al dia anterior el ultimo dia de Enero; respectivamente).
Esperamos de la función que devuelve por el dia de entrada – el mismo dia del mes en la salida, y si no existe- el mas cercano en el mes.
Solución possible puede ser el siguiente: antes de invocar la función hay que añadir un dia, y despues hay que restar un dia. La razon es que cuando el dia no es el ultimo del mes – las dos operaciones descontan una por el otra (por ejemplo- añadimos un dia a 15/04 sale 16/04, añadimos un mes sale 16/05, restamos un dia sale 15/05 – la respuesta correcta); y cuando el dia es el ultimo en el mes- la adición y la invocación de la función nos trae al principio del mes despues del siguiente y la resta al fin del mes siguiente.
Select D,
DateAdd(Month,1,D+1)-1 [AddMonth],
DateAdd(Quarter,1,D+1)-1 [AddQuarter],
DateAdd(Year,1,D+1)-1 [AddYear]
From #T;

El problema de los fines de meses ha sido resuelta (por ejemplo en fila 1 la recuperación devuelve que un mes despues de 30/04/2012 es 31/05/2012, y lo mismo con 28/02/2011 en fila 3), pero ha sido creado un problema nueva con los dias anteriores a los fines de meses:
4. Un año despues de 28/02/2012 el resultado es 27/02/2013 en lugar de 28/02/2013 .
11-12. Un mes despues de 29-30/01/2012 sale 28/02/2012 en lugar de 29/02/2012.
Hay un poco de logica en los erores en las filas 4 & 11 (por el dia anterior al fin del mes el calculo nos devuelve el dia anterior al fin del mes apropriado), pero es muy dificil explicar el resultado de fila 12..
No tenemos otra opción que complicar mas la recuperación y añadir & restar un dia solamente en los fines de meses (fin de mes es un dia que su mes es distinto del mes de su dia siguiente):
Select D,
Case When Month(D)=Month(D+1) Then DateAdd(Month,1,D)
Else DateAdd(Month,1,D+1)-1
End [AddMonth],
Case When Month(D)=Month(D+1) Then DateAdd(Quarter,1,D)
Else DateAdd(Quarter,1,D+1)-1
End [AddQuarter],
Case When Month(D)=Month(D+1) Then DateAdd(Year,1,D)
Else DateAdd(Year,1,D+1)-1
End [AddYear]
From #T;

Ahora los resultados son correctos, incluye casos extremos como en fila 4 en cual los tres resultados de la fecha 28/02/2012 (que es el dia anterior al fin del mes) son el 28 en el mes apropriado.