Dans mon application C #, je passe une variable de chaîne au format aaaammjj-aaaammjj qui représente les dates de début et de fin. Je veux obtenir les heures de début et de fin pour ces dates respectivement. Actuellement, j'ai le code ci-dessous mais je me demandais s'il y avait plus d'une solution élégante?
Donc, pour pdr = 20090521-20090523, on obtient "20090521 00:00:00" et "20090523 23:59:59"
private void ValidateDatePeriod(string pdr, out DateTime startDate,
out DateTime endDate)
{
string[] dates = pdr.Split('-');
if (dates.Length != 2)
{
throw new Exception("Date period is of incorrect format");
}
if (dates[0].Length != 8 || dates[1].Length != 8)
{
throw new Exception("Split date periods are of incorrect format");
}
startDate = DateTime.ParseExact(dates[0] + " 00:00:00",
"yyyyMMdd HH:mm:ss", null);
endDate = DateTime.ParseExact(dates[1] + "23:59:59",
"yyyyMMdd HH::mm:ss", null);
}
Si vous êtes seulement inquiet pour la précision .Net ...
startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddTicks(-1).AddDays(1);
Vous n'avez vraiment pas besoin de concaténer des valeurs supplémentaires sur la chaîne pour la partie heure.
En complément, si vous utilisez ceci pour une requête contre, par exemple, une base de données ...
startDate = DateTime.ParseExact(dates[0], "yyyyMMdd");
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddDays(1);
Avec une requête de ...
WHERE "startDate" >= @startDate AND "endDate" < @endDate
Ensuite, les problèmes de précision notés dans les commentaires n'auront aucune importance. La endDate dans ce cas ne ferait pas partie de la plage, mais la limite extérieure.
Je suis surpris de voir comment réponse incorrecte a reçu autant de votes positifs:
La version correcte serait la suivante:
public static DateTime StartOfDay(this DateTime theDate)
{
return theDate.Date;
}
public static DateTime EndOfDay(this DateTime theDate)
{
return theDate.Date.AddDays(1).AddTicks(-1);
}
Vous pouvez définir deux méthodes d'extension quelque part, dans une classe d'utilitaires comme ceci:
public static DateTime EndOfDay(this DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, 23, 59, 59, 999);
}
public static DateTime StartOfDay(this DateTime date)
{
return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0);
}
Et ensuite, utilisez-les dans le code comme ceci:
public DoSomething()
{
DateTime endOfThisDay = DateTime.Now.EndOfDay();
}
L'objet DateTime
a une propriété appelée Date
qui ne renverra que la partie date. (L'heure est définie par défaut sur 12:00).
Je recommanderais comme solution plus élégante (IMHO) que, si vous souhaitez autoriser une date/heure le dernier jour, ajoutez 1 jour à la date et comparez pour autoriser des heures supérieures ou égales à la date de début, mais strictement inférieures. que la date de fin (plus 1 jour).
// Calling code. beginDateTime and endDateTime are already set.
// beginDateTime and endDateTime are inclusive.
// targetDateTime is the date you want to check.
beginDateTime = beginDateTime.Date;
endDateTime = endDateTime.Date.AddDays(1);
if ( beginDateTime <= targetDateTime &&
targetDateTime < endDateTime )
// Do something.
C'est à peu près ce que je ferais, avec quelques petits ajustements (vraiment pas grave, juste une minuscule):
TryParse()
/TryParseExact()
doivent être utilisées pour renvoyer false
au lieu de lancer des exceptions.FormatException
est plus spécifique que Exception
ParseExact()
/TryParseExact()
le fera"00:00:00"
et "23:59:59"
ne sont pas nécessairestrue
/false
si vous avez pu analyser, au lieu de lancer une exception (n'oubliez pas de vérifier la valeur renvoyée par cette méthode!)Code:
private bool ValidateDatePeriod(string pdr, out DateTime startDate,
out DateTime endDate)
{
string[] dates = pdr.Split('-');
if (dates.Length != 2)
{
return false;
}
// no need to check for Length == 8 because the following will do it anyway
// no need for "00:00:00" or "23:59:59" either, I prefer AddDays(1)
if(!DateTime.TryParseExact(dates[0], "yyyyMMdd", null, DateTimeStyles.None, out startDate))
return false;
if(!DateTime.TryParseExact(dates[1], "yyyyMMdd", null, DateTimeStyles.None, out endDate))
return false;
endDate = endDate.AddDays(1);
return true;
}
J'utilise ce qui suit en C #
public static DateTime GetStartOfDay(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 0, 0, 0, 0);
}
public static DateTime GetEndOfDay(DateTime dateTime)
{
return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999);
}
Ensuite, dans MS SQL, je fais ce qui suit:
if datepart(ms, @dateEnd) = 0
set @dateEnd = dateadd(ms, -3, @dateEnd)
Cela se traduira par une heure MS SQL de 23: 59: 59,997, qui est l'heure maximale avant de devenir le lendemain.
Vous pouvez simplement utiliser:
new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999);
Ce qui fonctionnera dans MS SQL, mais ce n’est pas aussi précis dans le côté .Net.
Je pense que nous le faisons mal. Il n'y a rien de tel que la fin de journée. AddTick(-1)
ne fonctionne que dans la convention selon laquelle il n'y a pas d'intervalle de temps inférieur à un tick. Qui dépend de la mise en œuvre. Certes, la question vient avec une implémentation de référence, à savoir la classe .Net Framework DateTime
, mais nous devrions néanmoins considérer cela comme un indice du fait que la fonction que nous souhaitons réellement n'est pas EndOfDay()
mais StartOfNextDay()
public static DateTime StartOfNextDay(this DateTime date)
{
return date.Date.AddDays(1);
}
Pour SQL Server (version 2008 R2 testée), cela fonctionne.
StarDate '2016-01-11 00: 00: 01.990' EndDate '2016-01-19 23: 59: 59.990'
On dirait que les tiques sont plus grandes que la dernière seconde du jour et automatiquement arrondies au lendemain. Donc, je teste et fonctionne, j'ai fait une table factice avec deux dates pour vérifier quelles valeurs est capture SQL Server et insérer dans la procédure stockée ces paramètres.