2011-12-12 18 views
6

mam typu enum nazwie PaymentFrequency których wartości wskazują, ile rocznie płatności dokonywane są ... Więc mamIle dni, aby dodać do „pół-miesięczny”

public enum PaymentFrequency 
{ 
    None    = 0, 
    Annually   = 1, 
    SemiAnnually  = 2, 
    EveryFourthMonth = 3, 
    Quarterly  = 4, 
    BiMonthly  = 6, 
    Monthly   = 12, 
    EveryFourthWeek = 13, 
    SemiMonthly  = 24, 
    BiWeekly   = 26, 
    Weekly   = 52 
} 

podstawie NumberOfPayments, PaymentFrequency i FirstPaymentDate (typu DateTimeOffset) Chcę obliczyć LastPaymentDate. Ale mam problem na zastanawianie się, jak wiele jednostek czasu (dni, miesięcy), aby dodać w przypadku semimonthly ...

switch (paymentFrequency) 
    { 
     // add years... 
     case PaymentFrequency.Annually: 
      LastPaymentDate = FirstPaymentDate.AddYears(NumberOfPayments - 1); 
      break; 
     // add months... 
     case PaymentFrequency.SemiAnnually: 
      LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 6); // 6 months 
      break; 
     case PaymentFrequency.EveryFourthMonth: 
      LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 4); // 4 months 
      break; 
     case PaymentFrequency.Quarterly: 
      LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 3); // 3 months 
      break; 
     case PaymentFrequency.BiMonthly: 
      LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 2); // 2 months 
      break; 
     case PaymentFrequency.Monthly: 
      LastPaymentDate = FirstPaymentDate.AddMonths(NumberOfPayments - 1); 
      break; 
     // add days... 
     case PaymentFrequency.EveryFourthWeek: 
      LastPaymentDate = FirstPaymentDate.AddDays((NumberOfPayments - 1) * 4 * 7); // 4 weeks (1 week = 7 days) 
      break; 
     case PaymentFrequency.SemiMonthly: 
      // NOTE: how many days in semi month? AddMonths (0.5) does not work :) 
      LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1) * 0.5); // 2 weeks (1 week = 7 days) 
      break; 
     case PaymentFrequency.BiWeekly: 
      LastPaymentDate = FirstPaymentDate.AddDays((NumberOfPayments - 1) * 2 * 7); // 2 weeks (1 week = 7 days) 
      break; 
     case PaymentFrequency.Weekly: 
      LastPaymentDate = FirstPaymentDate.AddDays((NumberOfPayments - 1) * 7); // 1 week (1 week = 7 days) 
      break; 
     case PaymentFrequency.None: 
     default: 
      throw new ArgumentException("Payment frequency is not initialized to valid value!", "paymentFrequency"); 
    } 

tak, to ile dni/miesięcy powinno się używać przy użyciu semimonthly? Czy jest to możliwe bez znajomości dokładnych # dni dla każdego miesiąca pomiędzy? Czy to naprawdę proste, a ja po prostu zabrakło mi kofeiny i nie widzę lasu dla drzew :)

+6

Jakie są Państwa wymagania biznesowe w przypadku półrocza? Jakie dwa dni w miesiącu? Czy są naprawione? Lub po prostu zawsze 2 różne dni w odstępie 15 dni (tj.2 i 17, 3 i 18, 4 i 19, 5 i 20 itd.) –

+0

@ James Michael Hare Powiedzmy 1 i 16 na pytanie. Myślę, że wiem, dokąd to zmierza ... – zam6ak

+0

A czy wiesz, że twój pierwszy miesiąc płatności zawsze będzie poprawnie wypadał 1? –

Odpowiedz

7

Dla Semi miesiące, jeśli pierwsza wypłata była zawsze 1st wypłata w miesiącu, a także (to jest, zawsze z 1 do 13, zaczynając po 13 jest problematyczne, jak to omówiono w komentarzach), można to zrobić w następujący sposób:

// assuming first payment will be 1st of month, add month for every 2 payments 
// num payments/2 (int division, remainder is chucked) 
// then add 15 days if this is even payment of the month 
LastPaymentDate = FirstPaymentDate.AddMonths((NumberOfPayments - 1)/2) 
    .AddDays((NumberOfPayments % 2) == 0 ? 15 : 0); 

więc za 1 zapłaty, to doda 0 miesięcy i 0 dni tak być 1-te termin płatności. W przypadku drugiej płatności będzie to 0 miesięcy (podział na int, pozostała kwota zostanie dodana) i 15 dni na 16 dnia miesiąca. W przypadku trzeciej płatności, doda to 1 miesiąc (1/3) i 0 dni na 1 następnego miesiąca, itd.

Zakłada się, że FirstPaymentDate będzie pierwszego dnia danego miesiąca. Prawdopodobnie możesz zobaczyć, dokąd się udać, jeśli chcesz, aby data 16 była datą początkową, itp.

Czy masz sens?

Tak, aby zilustrować, jeśli mieliśmy:

DateTime LastPaymentDate, FirstPaymentDate = new DateTime(2011, 12, 5); 

for(int numOfPayments=1; numOfPayments<=24; numOfPayments++) 
{ 
    LastPaymentDate = FirstPaymentDate.AddMonths((numOfPayments - 1)/2) 
     .AddDays((numOfPayments % 2) == 0 ? 15 : 0); 

    Console.WriteLine(LastPaymentDate); 
} 

Pętla ta dałaby nam:

12/5/2011 12:00:00 AM 
12/20/2011 12:00:00 AM 
1/5/2012 12:00:00 AM 
// etc... 
10/20/2012 12:00:00 AM 
11/5/2012 12:00:00 AM 
11/20/2012 12:00:00 AM 
+0

Fajnie, dziękuję ... Gdybym chciała mieć określone przez użytkownika terminy półroczne (1-15, 2-16, 3-17 itd., Itp.), Muszę tylko upewnić się, że 1) data diff = 15 dni i 2) użyć drugiego dnia w drugiej części? – zam6ak

+0

@ zam6ak: Tak, druga data to zawsze 15 dni od pierwszej w dowolnym schemacie półrocznym, jaki widziałem. Druga część jest zawsze literalna 15. Oznacza to, że '== 0? 15: 0 "częścią kodu jest dodanie 15 dni, nie oznacza to 15. Tak więc ta logika zawsze działa dla każdego dnia początkowego, który jest <13 (większy niż 13 zaczynamy robić bałagan w lutym ...) –

+0

@ zam6ak: Czy to ma sens? Więc nawet jeśli FirstPaymentDate to 12/05/2011, to poprawnie wyświetli się 12/05/2011 i 12/20/2011. Jedyne * miejsce, w którym napotkasz problemy, to data początkowa> 13, ponieważ wtedy będziesz miał problemy z lutym. –

1

Ponieważ miesiące mają różne długości, nie można po prostu dodać wcześniej zdefiniowanego numeru. Musisz wiedzieć, z którym miesiącem masz do czynienia i iść stamtąd.

Jeśli wiesz, że 1 i 16 dnia miesiąca są datami płatności, ostatnia płatność przypada na 16 grudnia (zakładając, że obliczasz na rok kalendarzowy).

+0

Daniel - the LastPaymentDate zależy od NumberOfPayments. Więc jeśli mam częstotliwość SemiMonthly z 48 płatnościami i FirstPaymentDate z 01/01/1978 - jaka byłaby LastPaymentDate .... Myślę, w przeciwieństwie do innych przypadków, z SemiMonthly będę musiał znać 2 daty i "chodzić" każda płatność ... – zam6ak

+0

Istnieją tylko 4 przypadki: pierwsza płatność przypada na 1 dzień miesiąca, a NumberOfPayments jest nieparzysta; pierwsza płatność przypada na 16 dnia miesiąca, a NumberOfPayments jest nieparzysta; pierwsza płatność przypada na 1 dzień miesiąca, a NumberOfPayments jest parzysta; pierwsza płatność przypada na 16 dnia miesiąca, a zdarzenie NumberOfPayments. W obu przypadkach ostatnia płatność będzie również na 1 lub 16. Możesz podzielić każdy miesiąc na 2 części: 1-15, 16-koniec miesiąca. 2 okresy miesięcznie, po prostu trzeba obliczyć, ile takich okresów potrzeba, aby zakończyć płatność. –

0

Podstawowe pary dla naczep miesięczne płatności są:

  • 1 i 16 (1. i 16 dzień miesiąca)
  • 15 i (2 | 3)? (15. i ostatni dzień miesiąca)

Peek i wybierz

0

I niedawno miał ten sam problem, ale potrzebne, aby umożliwić wejście żadnej daty. To trochę bałaganu i trzeba go refaktoryzować, ale do tego doszedłem. Luty miał pewne problemy, które musiałem zhackować.

Date returnDate; 

if (numberOfPayments % 2 == 0) 
{ 
    returnDate = date.AddMonths(numberOfPayments/2); 

    if (date.Day == DateTime.DaysInMonth(date.Year, date.Month))//Last day of the month adjustment 
    { 
     returnDate = new Date(returnDate.Year, returnDate.Month, DateTime.DaysInMonth(returnDate.Year, returnDate.Month)); 
    } 
} 
else 
{ 
    returnDate = date.Day <= 15 ? date.AddDays(15).AddMonths((numberOfPayments - 1)/2) : date.AddDays(-15).AddMonths((numberOfPayments + 1)/2); 
    if (date.Day == DateTime.DaysInMonth(date.Year, date.Month))//Last day of the month adjustment 
    { 
     returnDate = new Date(returnDate.Year, returnDate.Month, 15); 
    } 
    else if (date.Month == 2 && date.Day == 14) 
    { 
     returnDate = returnDate.AddMonths(-1); 
     returnDate = new Date(returnDate.Year, returnDate.Month, returnDate.Month == 2 ? 28 : 29); 
    } 
    else if (date.Month == 2 && date.Day == 15) 
    { 
     returnDate = returnDate.AddMonths(-1); 
     returnDate = new Date(returnDate.Year, returnDateMonth, DateTime.DaysInMonth(returnDate.Year, returnDate.Month)); 
    } 
} 

return returnDate;