2011-12-12 2 views
6

ho un tipo enum chiamato PaymentFrequency i cui valori indicano il numero di pagamenti per anno sono stati fatti ... Così hoQuanti giorni aggiungere per "semi-mensile"

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 
} 

Sulla base di NumberOfPayments, PaymentFrequency e FirstPaymentDate (di tipo DateTimeOffset) Voglio calcolare LastPaymentDate. Ma io sto avendo problema capire quante unità di tempo (giorni, mesi) per aggiungere in caso di 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"); 
    } 

Così, quanti giorni/mesi devo usare quando si utilizza Semimonthly? Questo è possibile anche senza conoscere il numero esatto di giorni per ogni mese in mezzo? Oppure è davvero semplice, e ho appena finito la caffeina e non vedo foresta per gli alberi :)

+6

Qual è il tuo fabbisogno aziendale per semestrale? Quali due giorni al mese? Sono riparati? O semplicemente sempre 2 giorni diversi a 15 giorni di distanza (ad es.2 & 17, 3 & 18, 4 & 19, 5 e 20, ecc.) –

+0

@James Michael Hare Diciamo il 1 ° e il 16 ° a titolo di domanda. Penso di sapere dove sta andando ... – zam6ak

+0

E sai per certo che il tuo primo mese di pagamento scenderà sempre al 1 ° posto? –

risposta

7

per semi-mensile, se il primo pagamento è stato sempre il primo pagamento del mese, come pure (cioè, in qualsiasi momento dalla 1 ° al 13 °, a partire da dopo il 13 è problematica come discusso nei commenti), si potrebbe fare come segue:

// 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); 

quindi, per il 1 ° pagamento, questo aggiungerà 0 mesi e 0 giorni in modo da essere prima data di pagamento. Per il 2 ° pagamento, questo aggiungerà 0 mesi (divisione iniziale, il resto è bloccato) e 15 giorni per il 16 ° mese. Per il 3 ° pagamento, questo aggiungerà 1 mese (1/3) e 0 giorni per il 1 ° del mese successivo, ecc.

Ciò presuppone che il FirstPaymentDate sarà il 1 ° di un determinato mese. Probabilmente puoi vedere da dove andare se vuoi consentire al 16 di essere una data di inizio, ecc.

Ha senso?

Quindi, per illustrare, se avessimo:

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); 
} 

Questo ciclo ci darebbe:

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

Bello, grazie ... Se volessi che l'utente abbia specificato date semestrali (1-15, 2-16, 3-17, ecc., Ecc.), Dovrei solo assicurarmi che 1) data diff = 15 giorni e 2) usa il 2 ° giorno nella 2a parte? – zam6ak

+0

@ zam6ak: Sì, la seconda data è sempre di 15 giorni dalla prima in qualsiasi schema semestrale che ho visto. La seconda parte è sempre la letterale 15. Cioè, '== 0? 15: 0' parte del codice è di aggiungere 15 giorni, non significa il 15. Quindi, questa logica funziona sempre per qualsiasi giorno di inizio che è

+0

@ zam6ak: Ha senso? Quindi, anche se FirstPaymentDate è il 12/05/2011, questo ti darà correttamente il 12/05/2011 e il 20/12/2011. L'unico * posto in cui ti imbatterai in problemi è se la data di inizio è> 13, perché allora avresti problemi con febbraio. –

1

Poiché i mesi hanno lunghezze variabili, non è possibile aggiungere solo un numero predefinito. Devi sapere con quale mese hai a che fare e andare da lì.

Se si sa che il 1 ° e il 16 di un mese sono le date di scadenza, l'ultimo pagamento è il 16 dicembre (presupponendo che si stia calcolando per un anno solare).

+0

Daniel - the LastPaymentDate dipende da NumberOfPayments. Quindi, se ho una frequenza semestrale con 48 pagamenti, e con FirstPaymentDate del 01/01/1978 - quale sarebbe LastPaymentDate .... Penso che, diversamente dagli altri casi, con SemiMonthly dovrò conoscere le 2 date e "camminare" ogni pagamento ... – zam6ak

+0

Ci sono solo 4 casi: il primo pagamento è il 1 ° del mese e NumberOfPayments è dispari; il primo pagamento è il 16 del mese e NumberOfPayments è dispari; il primo pagamento è il 1 ° del mese e NumberOfPayments è pari; il primo pagamento è il 16 del mese e NumberOfPayments è l'evento. In entrambi i casi l'ultimo pagamento sarà anche il 1 ° o il 16 °. Quindi, puoi dividere ogni mese in 2 pezzi: 1-15, 16 fine del mese. 2 periodi al mese e devi solo calcolare quanti periodi sono necessari per completare il pagamento. –

0

Le coppie di base per i pagamenti mensili semi sono:

  • 1 e 16 (il 1 ° e 16 ° giorno di un mese)
  • 15 e (2 | 3)? (Il 15 ° e l'ultimo giorno del mese)

Peek e scegli

0

Recentemente ho avuto lo stesso problema, ma avevo bisogno di permettere qualsiasi input data. È un po 'un casino e deve essere refactored, ma questo è quello che ho inventato finora. Febbraio ha avuto alcuni problemi che ho dovuto modificare.

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;