Comment puis-je parcourir une plage de dates?
Je ne suis même pas sûr de savoir comment faire cela sans utiliser une horrible solution de type boucle / compteur. Voici le problème:
On me donne deux dates, une date de début et une date de fin et sur un intervalle spécifié, je dois prendre des mesures. Par exemple: pour chaque date entre le 3/10/2009 tous les trois jours jusqu'au 3/26/2009, je dois créer une entrée dans une liste. Donc, mes entrées seraient:
DateTime StartDate = "3/10/2009";
DateTime EndDate = "3/26/2009";
int DayInterval = 3;
Et ma sortie serait une liste qui a ce qui suit dates:
3/13/2009 3/16/2009 3/19/2009 3/22/2009 3/25/2009
Alors, comment diable ferais-je quelque chose comme ça? J'ai pensé à utiliser une boucle for qui itérerait entre tous les jours dans la plage avec un compteur séparé comme ceci:
int count = 0;
for(int i = 0; i < n; i++)
{
count++;
if(count >= DayInterval)
{
//take action
count = 0;
}
}
Mais il semble qu'il pourrait y avoir un meilleur moyen?
14 réponses
Eh bien, vous devrez les parcourir d'une manière ou d'une autre. Je préfère définir une méthode comme celle-ci:
public IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
for(var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
yield return day;
}
, Alors vous pouvez l'utiliser comme ceci:
foreach (DateTime day in EachDay(StartDate, EndDate))
// print it or whatever
De cette manière, vous pourriez frapper tous les deux jours, tous les trois jours, seulement en semaine, etc. Par exemple, pour revenir tous les trois jours à partir de la date de "début", vous pouvez simplement appeler AddDays(3)
dans la boucle au lieu de AddDays(1)
.
J'ai une classe Range
dans MiscUtil que vous pourriez trouver utile. Combiné avec les différentes méthodes d'extension, vous pouvez faire:
foreach (DateTime date in StartDate.To(EndDate).ExcludeEnd()
.Step(DayInterval.Days())
{
// Do something with the date
}
(Vous pouvez ou ne voulez pas exclure la fin-je pensais juste que je le fournirais à titre d'exemple.)
Il s'agit essentiellement d'une forme prête à l'emploi (et plus générale) de la solution de mquander.
Pour votre exemple, vous pouvez essayer
DateTime StartDate = new DateTime(2009, 3, 10);
DateTime EndDate = new DateTime(2009, 3, 26);
int DayInterval = 3;
List<DateTime> dateList = new List<DateTime>();
while (StartDate.AddDays(DayInterval) <= EndDate)
{
StartDate = StartDate.AddDays(DayInterval);
dateList.Add(StartDate);
}
Code de @Mquander et @yogourt le Sage utilisé dans les extensions:
public static IEnumerable<DateTime> EachDay(DateTime from, DateTime thru)
{
for (var day = from.Date; day.Date <= thru.Date; day = day.AddDays(1))
yield return day;
}
public static IEnumerable<DateTime> EachMonth(DateTime from, DateTime thru)
{
for (var month = from.Date; month.Date <= thru.Date || month.Month == thru.Month; month = month.AddMonths(1))
yield return month;
}
public static IEnumerable<DateTime> EachDayTo(this DateTime dateFrom, DateTime dateTo)
{
return EachDay(dateFrom, dateTo);
}
public static IEnumerable<DateTime> EachMonthTo(this DateTime dateFrom, DateTime dateTo)
{
return EachMonth(dateFrom, dateTo);
}
DateTime startDate = new DateTime(2009, 3, 10);
DateTime stopDate = new DateTime(2009, 3, 26);
int interval = 3;
for (DateTime dateTime=startDate;
dateTime < stopDate;
dateTime += TimeSpan.FromDays(interval))
{
}
1 An plus tard, peut-il aider quelqu'un,
Cette version comprend un prédicat, pour être plus flexible.
Utilisation
var today = DateTime.UtcNow;
var birthday = new DateTime(2018, 01, 01);
Tous les jours à mon anniversaire
var toBirthday = today.RangeTo(birthday);
Mensuel à mon anniversaire, Étape 2 mois
var toBirthday = today.RangeTo(birthday, x => x.AddMonths(2));
Chaque année à mon anniversaire
var toBirthday = today.RangeTo(birthday, x => x.AddYears(1));
Utilisez RangeFrom
à la place
// same result
var fromToday = birthday.RangeFrom(today);
var toBirthday = today.RangeTo(birthday);
Mise en œuvre
public static class DateTimeExtensions
{
public static IEnumerable<DateTime> RangeTo(this DateTime from, DateTime to, Func<DateTime, DateTime> step = null)
{
if (step == null)
{
step = x => x.AddDays(1);
}
while (from < to)
{
yield return from;
from = step(from);
}
}
public static IEnumerable<DateTime> RangeFrom(this DateTime to, DateTime from, Func<DateTime, DateTime> step = null)
{
return from.RangeTo(to, step);
}
}
Extras
Vous pouvez lancer une Exception si le fromDate > toDate
, mais je préfère retourner une plage vide à la place []
DateTime startDate = new DateTime(2009, 3, 10);
DateTime stopDate = new DateTime(2009, 3, 26);
int interval = 3;
while ((startDate = startDate.AddDays(interval)) <= stopDate)
{
// do your thing
}
Selon le problème, vous pouvez essayer ceci...
// looping between date range
while (startDate <= endDate)
{
//here will be your code block...
startDate = startDate.AddDays(1);
}
Merci......
Vous pouvez envisager d'écrire un itérateur à la place, ce qui vous permet d'utiliser une syntaxe de boucle 'for' normale comme '++'. J'ai cherché et trouvé une question similaire répondu ici sur StackOverflow qui donne des pointeurs pour rendre DateTime itérable.
Vous pouvez utiliser la fonction DateTime.AddDays()
pour ajouter votre DayInterval
au StartDate
et vérifier qu'il est inférieur au EndDate
.
DateTime begindate = Convert.ToDateTime("01/Jan/2018");
DateTime enddate = Convert.ToDateTime("12 Feb 2018");
while (begindate < enddate)
{
begindate= begindate.AddDays(1);
Console.WriteLine(begindate + " " + enddate);
}
Vous devez faire attention ici à ne pas manquer les dates où dans la boucle une meilleure solution serait.
Cela vous donne la première date de startdate et l'utilise dans la boucle avant de l'incrémenter et il traitera toutes les dates, y compris la dernière date de enddate d'où
, Donc la réponse ci-dessus est correcte.
while (startdate <= enddate)
{
// do something with the startdate
startdate = startdate.adddays(interval);
}
Vous pouvez utiliser ceci.
DateTime dt0 = new DateTime(2009, 3, 10);
DateTime dt1 = new DateTime(2009, 3, 26);
for (; dt0.Date <= dt1.Date; dt0=dt0.AddDays(3))
{
//Console.WriteLine(dt0.Date.ToString("yyyy-MM-dd"));
//take action
}
Itérer toutes les 15 minutes
DateTime startDate = DateTime.Parse("2018-06-24 06:00");
DateTime endDate = DateTime.Parse("2018-06-24 11:45");
while (startDate.AddMinutes(15) <= endDate)
{
Console.WriteLine(startDate.ToString("yyyy-MM-dd HH:mm"));
startDate = startDate.AddMinutes(15);
}