3
juillet
2007
Ecart de date en SQL (pas DateDiff)
juillet
2007
J’avais demandé à Christian comment obtenir la différence entre deux dates mais la vraie différence. Si on fait un DateDiff avec Year, on obtient la différence entre les années, sans se soucier du reste de la date. C’était justement ça qui me génait. Christian vient de bloguer sur la solution pour ce cas là.
Cet algo me plait beaucoup. En C#, la classe TimeSpan permet de connaître l’écart entre deux dates mais sa plus grande unité est le jour. On pourrait donc faire ceci :
public static int ConvertDateToInt(DateTime date)
{
return date.Year * 10000 + date.Month * 100 + date.Day;
}
public static int Age(DateTime d1)
{
int d1Int = ConvertDateToInt(d1);
int d2Int = ConvertDateToInt(DateTime.Now);
int ecart = d2Int - d1Int;
return ecart / 10000;
}
[...]
Console.WriteLine(String.Format("Age : {0} an(s)", Age(new DateTime(1981, 11, 18))));
[...]
{
return date.Year * 10000 + date.Month * 100 + date.Day;
}
public static int Age(DateTime d1)
{
int d1Int = ConvertDateToInt(d1);
int d2Int = ConvertDateToInt(DateTime.Now);
int ecart = d2Int - d1Int;
return ecart / 10000;
}
[...]
Console.WriteLine(String.Format("Age : {0} an(s)", Age(new DateTime(1981, 11, 18))));
[...]
SI vous voulez plus de détails, voici comment faire :
public static int ConvertDateToInt(DateTime date)
{
return date.Year * 10000 + date.Month * 100 + date.Day;
}
public static DateTime Age(DateTime d1)
{
int d1Int = ConvertDateToInt(d1);
DateTime now = DateTime.Now;
int d2Int = ConvertDateToInt(now);
int ecart = d2Int - d1Int;
int annees = ecart / 10000;
int mois = ((ecart / 100) % 100) / 12;
DateTime dTmp = new DateTime(d1.Year + annees, d1.Month, d1.Day).AddMonths(mois);
return new DateTime(annees, mois, ((TimeSpan)(now - dTmp)).Days);
}
[...]
DateTime res = Age(new DateTime(1981, 11, 18));
Console.WriteLine(String.Format("Age : {0} an(s) {1} mois {2} jour(s)", res.Year, res.Month, res.Day));
[...]
{
return date.Year * 10000 + date.Month * 100 + date.Day;
}
public static DateTime Age(DateTime d1)
{
int d1Int = ConvertDateToInt(d1);
DateTime now = DateTime.Now;
int d2Int = ConvertDateToInt(now);
int ecart = d2Int - d1Int;
int annees = ecart / 10000;
int mois = ((ecart / 100) % 100) / 12;
DateTime dTmp = new DateTime(d1.Year + annees, d1.Month, d1.Day).AddMonths(mois);
return new DateTime(annees, mois, ((TimeSpan)(now - dTmp)).Days);
}
[...]
DateTime res = Age(new DateTime(1981, 11, 18));
Console.WriteLine(String.Format("Age : {0} an(s) {1} mois {2} jour(s)", res.Year, res.Month, res.Day));
[...]
Effectivement. J’avais utilisé DateTime comme type de retour par facilité mais c’est vrai qu’il serait préférable de faire une vraie structure pour cela.
Nouvelle remarque (après avoir réfléchi au problème du « new DateTime(0) ») :
renvoyer une structure DateTime pour représenter un intervalle de temps ne semble pas très adapté car les jours, mois et années ‘0’ n’existent pas….
Pour exemple, si tu testes aujourd’hui la date « 03/11/1981″ (bref, si le « 03 » correspond à aujourd’hui…), ta fonction renverra une erreur car « ((TimeSpan)(now – dTmp)).Days » renverra 0 qui est un jour invalide.
(et globalement, on ne peut pas représenter un intervalle de moins d’1 an de cette façon)
Autre argument : les différences dans les nombres de jours par mois et par ans (vive les années bissextiles…) font que la classe DateTime n’est pas adaptée à la représentation d’intervalles… (ils expliquent aussi pourquoi il n’y a pas de propriétés « Months » ou « Years » dans TimeSpan… les notions de mois ou d’années ne pouvant pas être associés à des durées fixes…)
Effectivement, mon résultat n’est pas correct car j’avais oublié que :
new DateTime(0) correspond à la date « 01/01/0001 00:00:00″ [et non pas à 00/00/0000 …] !!
Par conséquent pour obtenir une date qui corresponde à ce que tu calculais, il faut faire par exemple :
public static DateTime Age(DateTime d1) <br />
{ <br />
return new DateTime(DateTime.Now.AddYears(-1).AddMonths(-1).AddDays(-1).Subtract(date1).Ticks) <br />
} <br />
On perd en lisibilité…
Sauf que ça marche pas !
Le résultat obtenu ainsi n’est pas correct !
Je connaissais pas.
Merci pour l’info.
Autre façon de faire :
public static DateTime Age(DateTime d1)
{
return new DateTime(DateTime.Now.Subtract(d1).Ticks);
}
En passant par la propriété « Ticks » on peut facilement transformer un TimeSpan en DateTime (a condition que le TimeSpan représenté soit positif).
