2010-01-13 4 views
0

Je dois créer une fonction pour retourner la prochaine date de traitement pour un article donné. Un élément a un nombre qui représente le mois au cours duquel il est traité, ainsi qu'un nombre qui représente la semaine du mois au cours duquel il est traité. Donc, étant donné la date de création d'un article particulier, j'ai besoin d'obtenir la prochaine date de traitement pour cet article, qui sera le premier jour de la semaine et du mois assignés dans un quart.Prochaine date au cours d'un trimestre

Notez que les semaines sont réparties sur 7 jours à compter du début du mois, quel que soit le jour de la semaine. Ainsi, le premier jour de la première semaine pourrait commencer le mardi ou n'importe quel autre jour aux fins de ce calcul.

Exemple:
Disons que j'ai un élément dont la date d'achèvement est le 1/8/2010. Cet élément a une valeur monthWithinQuarter de 2. Il a une valeur weekWithinMonth de 3. Donc pour cet élément qui se résout à la troisième semaine de février, je voudrais que la fonction renvoie une date du 15/02/2010.

La fonction devrait ressembler à ceci:

var nextProcessingDate = GetNextProcessingDate(
          itemCompletedDate, 
          monthWithinQuarter, 
          weekWithinMonth); 

Ce calcul doit être assez vite que ce calcul va se produire beaucoup, à la fois en temps réel pour afficher sur un site Web, ainsi que en mode batch lors du traitement d'éléments.

Merci,

~ Justin

+0

Quel est le résultat de 'GetNextProcessingDate (nouveau DateTime (2010, 3, 31), 3, 1)? En supposant que «31/31/2010» est le dernier jour du premier trimestre, je ne vois pas comment vous pourriez résoudre ce problème sans fournir d'autres spécifications. – jason

+0

Demander la date suivante étant donné une date de 3/31 et le mois 3 et la semaine 1 devrait se traduire par 6/1/2010. C'est la prochaine date de traitement disponible pour cet article. Le 3/1/2010 est déjà passé, il n'est donc pas disponible. – RationalGeek

+0

Bon, alors je pense que ma version actuelle devrait faire le travail pour vous. – jason

Répondre

0

D'accord, cela devrait le faire pour vous:

static DateTime GetNextProcessingDate(
    DateTime itemCompletedDate, 
    int monthWithinQuarter, 
    int weekWithinMonth 
) { 
     if (monthWithinQuarter < 1 || monthWithinQuarter > 3) { 
      throw new ArgumentOutOfRangeException("monthWithinQuarter"); 
     } 
     if (weekWithinMonth < 1 || weekWithinMonth > 5) { 
      throw new ArgumentOutOfRangeException("weekWithinMonth"); 
     } 
     int year = itemCompletedDate.Year; 
     DateTime[] startOfQuarters = new[] { 
      new DateTime(year, 1, 1), 
      new DateTime(year, 4, 1), 
      new DateTime(year, 7, 1), 
      new DateTime(year, 10, 1) 
     }; 
     DateTime startOfQuarter = startOfQuarters.Where(d => d <= itemCompletedDate) 
               .OrderBy(d => d) 
               .Last(); 
     int month = startOfQuarter.Month + monthWithinQuarter - 1; 
     int day = (weekWithinMonth - 1) * 7 + 1; 
     if (day > DateTime.DaysInMonth(year, month)) { 
      throw new ArgumentOutOfRangeException("weekWithinMonth"); 
     } 
     DateTime candidate = new DateTime(year, month, day); 
     if (candidate < itemCompletedDate) { 
      month += 3; 
      if(month > 12) { 
       year++; 
       month -= 12; 
      } 
     } 
     return new DateTime(year, month, day); 
    } 

En ce qui concerne l'efficacité, l'endroit où je vois le plus d'amélioration est la création à plusieurs reprises le tableau

DateTime[] startOfQuarters = new[] { 
    new DateTime(year, 1, 1), 
    new DateTime(year, 4, 1), 
    new DateTime(year, 7, 1), 
    new DateTime(year, 10, 1) 
}; 

Donc, nous allons Offload cela à une méthode et mémoize:

static Dictionary<int, DateTime[]> cache = new Dictionary<int, DateTime[]>(); 
public static DateTime[] StartOfQuarters(DateTime date) { 
    int year = date.Year; 
    DateTime[] startOfQuarters; 
    if(!cache.TryGetValue(year, out startOfQuarters)) { 
     startOfQuarters = new[] { 
      new DateTime(year, 1, 1), 
      new DateTime(year, 4, 1), 
      new DateTime(year, 7, 1), 
      new DateTime(year, 10, 1) 
     }; 
     cache.Add(year, startOfQuarters); 
    } 
    return startOfQuarters; 
} 

Si vous n'avez pas besoin de la flexibilité des quartiers en commençant peut-jours inhabituels, vous pouvez remplacer

DateTime[] startOfQuarters = new[] { 
    new DateTime(year, 1, 1), 
    new DateTime(year, 4, 1), 
    new DateTime(year, 7, 1), 
    new DateTime(year, 10, 1) 
}; 
DateTime startOfQuarter = startOfQuarters.Where(d => d <= itemCompletedDate).OrderBy(d => d).Last(); 
int month = startOfQuarter.Month + monthWithinQuarter - 1; 

avec

int month = 3 * ((itemCompletedDate.Month - 1)/3) + monthWithinQuarter; 
+0

Incontestablement similaire à ma solution, dans la plupart des régions ... La méthode de détection du quartier peut être soit exagérée soit ce que l'OP veut. Je ne peux pas être sûr avec les informations actuelles. – Noldorin

+0

Oui, ça dépend. Je viens d'un monde où les quarts de départ ne sont souvent pas «1/1», «4/1», «7/1», «10/1», donc je me prépare toujours à la possibilité qu'ils ne le soient pas. – jason

+0

@Downvoter: S'il vous plaît expliquer. – jason

-1

D'après ce que je comprends, cela devrait faire le travail:

public static DateTime GetNextProcessingDate(DateTime itemCreationDate, int monthWithinQuarter, 
    int weekWithinMonth) 
{ 
    var quarter = (itemCreationDate.Month - 1)/4; // Assumes quarters are divided by calendar year. 
    var month = quarter * 4 + monthWithinQuarter; // First quarter of month plus month within quarter 
    var dayInMonth = (weekWithinMonth - 1) * 7 + 1; // Weeks are counted from first day, regardless of day of week (as you mention). 
    return new DateTime(itemCreationDate.Year, month, dayInMonth); 
} 

Permettez-moi de savoir si tout cela est pas clair.

+0

Cela ne fonctionne pas pour 'itemCreationDate = new DateTime (2010, 3, 31), monthWithinQuarter = 3' et' weekWithinMonth = 1'. – jason

+0

Cela ne fonctionne pas non plus pour 'itemCreationDate = new DateTime (2010, 1, 1), monthWithinQuarter = 1 et weekWithinMonth = 1'. – jason

+0

@Jason. Bien sûr que oui. Je ne vois pas pourquoi pas ... Est-ce que cela méritait vraiment un vote négatif? – Noldorin

-2

Votre calcul, je suppose que devrait être réduite à

DateTime dt; 
    dt.AddDays(daysToAdd); 
    dt.AddMonths(monthsToAdd); 
    dt.AddHours(hoursToAdd); 
    dt.AddYears(yearsToAdd); 
Questions connexes