2010-03-23 6 views
12

Ho bisogno di arrotondare le ore in base ai minuti in una variabile DateTime. La condizione è: se i minuti sono inferiori a 30, i minuti devono essere impostati su zero e nessuna modifica alle ore, altrimenti se minuti> = 30, quindi le ore devono essere impostate su ore + 1 e i minuti sono nuovamente impostati su zero. I secondi vengono ignorati.Come arrotondare le ore in base al processo verbale (ore + 0 se min <30, ore + 1 altrimenti)?

esempio:
11/08/2008 04:30:49 dovrebbe diventare 11/08/2008 05:00:00
e 11/08/2008 04:29:49 dovrebbe diventare 11/08/2008 04:00:00

Ho scritto il codice che funziona perfettamente bene, ma volevo solo sapere un metodo migliore se potrebbe essere scritto e anche apprezzerebbe metodo alternativo (S).

string date1 = "11/08/2008 04:30:49"; 
DateTime startTime; 
DateTime.TryParseExact(date1, "MM/dd/yyyy HH:mm:ss", null,  
    System.Globalization.DateTimeStyles.None, out startTime); 

if (Convert.ToInt32((startTime.Minute.ToString())) > 29) 
{ 
    startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}", 
     startTime.Month.ToString(), startTime.Day.ToString(), 
     startTime.Year.ToString(), startTime.Hour.ToString(), "00", "00")); 
    startTime = startTime.Add(TimeSpan.Parse("01:00:00")); 
    Console.WriteLine("startTime is :: {0}", 
     startTime.ToString("MM/dd/yyyy HH:mm:ss")); 
} 
else 
{ 
    startTime = DateTime.Parse(string.Format("{0}/{1}/{2} {3}:{4}:{5}", 
     startTime.Month.ToString(), 
     startTime.Day.ToString(), startTime.Year.ToString(), 
     startTime.Hour.ToString(), "00", "00")); 

     Console.WriteLine("startTime is :: {0}", 
     startTime.ToString("MM/dd/yyyy HH:mm:ss")); 
} 
+0

Grazie a tutti per le discussioni utili e post. :-) –

+0

Sono accettabili anche suggerimenti da Russell_Steen, Hans_Kesting e Hojo. –

+0

possibile duplicato di [C'è un modo migliore per tagliare un DateTime con una precisione specifica?] (Http://stackoverflow.com/questions/152774/is-there-a-better-way-to-trim-a-datetime -a-una-precisione-specifica) –

risposta

21

Proprio come alternativa:

public static DateTime Round(DateTime dateTime) 
{ 
    var updated = dateTime.AddMinutes(30); 
    return new DateTime(updated.Year, updated.Month, updated.Day, 
         updated.Hour, 0, 0, dateTime.Kind); 
} 
+0

Si potrebbe voler aggiornare la risposta includendo la conservazione del tipo DateTime- vedere il mio post http://stackoverflow.com/questions/2499479/how-to-round-off-hours-based-on-minuteshours0-if-min30- ore1-altrimenti/2906684 # 2906684 – CrimsonX

+0

@CrimsonX - aggiornato. – tvanfosson

+0

molto spiritoso :) :) –

3
DateTime s = DateTime.Now; 
    if (s.Minute > 30) s = s.AddHours(1); //only add hours if > 30 
    if (s.Minute == 30 && s.Second > 0) s = s.AddHours(1); //add precision as needed 
    s = new DateTime(s.Year, s.Month, s.Day, s.Hour, 0, 0); 
+0

Hai perso i secondi, saranno lasciati intatti. È meglio creare 1 nuovo DateTime, copiando solo i valori necessari. –

+0

@Russell, non so perché ma il metodo AddHours() non funziona ... anche se se la condizione viene soddisfatta, lo –

+0

ha perso un incarico. devo assegnare il risultato degli addhours a s. typo –

6

Che dire:

public static DateTime RoundToHours(DateTime input) 
{ 
DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0); 

    if (input.Minute > 29) 
     return dt.AddHours(1); 
    else 
     return dt; 
} 

Non c'è bisogno di convertire in stringa e viceversa!

EDIT:
Usando un input.Hour+1 nel costruttore fallirà se l'Ora è 23. La .AddHours(1) sarà correttamente tradurrà in '0:00' il giorno successivo.

+0

ohk .. thanx .. :-) funziona. –

1
DateTime dtm = DateTime.Now; 
if (dtm.Minute < 30) 
{ 
    dtm = dtm.AddMinutes(dtm.Minute * -1); 
} 
else 
{  
    dtm = dtm.AddMinutes(60 - dtm.Minute); 
} 
dtm = dtm.AddSeconds(dtm.Second * -1); 
+0

+1 per il codice più semplice e comprensibile :-) –

3

Estendere Hans Kestings buona risposta:

public DateTime RoundToHours(DateTime input) 
{ 
     DateTime dt = new DateTime(input.Year, input.Month, input.Day, input.Hour, 0, 0); 
     return dt.AddHours((int)(input.Minutes/30)); 
} 

L'(int) Cast potrebbe non essere necessaria.

MODIFICA: adattato le correzioni effettuate da Hans Kesting nella sua risposta.

+0

grazie mille per aver raggiunto il requisito. :-) –

22

Se la velocità è un problema, il seguente dovrebbe essere il modo più veloce:

static DateTime RoundToHour(DateTime dt){ 
    long ticks = dt.Ticks + 18000000000; 
    return new DateTime(ticks - ticks % 36000000000, dt.Kind); 
} 

E 'anche un modo abbastanza straight-forward e semplice per farlo.

Per spiegare, una struttura DateTime in realtà non ha campi che memorizzano l'anno, il mese, il giorno, l'ora, il minuto, ecc. Memorizza un singolo valore long, il numero di "tick" da una certa epoca (Gen 1, 1 AD). Un segno di spunta è 100 nanosecondi o 10.000.000 di secondo.

Ogni volta che si utilizza una qualsiasi delle proprietà data/ora, questa si divide in base alla costante corretta.

Quindi qui, aggiungiamo una costante pari a 30 minuti (30 * 60 * 1e7 = 18000000000 zecche), quindi sottrarre il resto dopo aver diviso per una costante pari a un'ora (60 * 60 * 1e7 = 36000000000 zecche).

+0

Eeeek !!! [15 caratteri] –

+0

grazie per la spiegazione. Cerco di implementare questa tecnica altrimenti, se necessario. –

+0

È anche possibile modificare l'istruzione return in 'return new DateTime (ticks - ticks% 36000000000, dt.Kind))' per preservare il tipo DateTime del valore DateTime passato. –

3

di migliorare alcuni degli altri metodi, ecco un metodo che anche preservare la DateTime Tipo:

/// <summary> 
/// Rounds a DateTime to the nearest hour. 
/// </summary> 
/// <param name="dateTime">DateTime to Round</param> 
/// <returns>DateTime rounded to nearest hour</returns> 
public static DateTime RoundToNearestHour(this DateTime dateTime) 
{ 
    dateTime += TimeSpan.FromMinutes(30); 

    return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, dateTime.Hour, 0, 0, dateTime.Kind); 
} 
2

qui va!

var rounded = date.AddMinutes(30).Date.AddHours(date.AddMinutes(30).Hour); 

E per coloro che vogliono pavimentata

var floored = date.Date.AddHours(date.Hours) 
1

Sulla base di soluzione di P papà, propongo di non hardcode quel grande numero di tick per un'ora. Hardcoding è malvagio, non è vero? Con questa soluzione modificata, è ora possibile arrotondare qualsiasi momento a qualsiasi numero di minuti:

public DateTime RoundToMinutes(DateTime dt, int NrMinutes) 
    { 
     long TicksInNrMinutes = (long)NrMinutes * 60 * 10000000;//1 tick per 100 nanosecond 
     long ticks = dt.Ticks + TicksInNrMinutes/2; 
     return new DateTime(ticks - ticks % TicksInNrMinutes, dt.Kind); 
    } 

Io lo uso per l'arrotondamento alla 5 minuti, per esempio 22:23 diventa 22:25.

anni fa ho utilizzato lo stesso metodo per arrotondare le somme di denaro al centesimo più vicino, ad es. $ 22,23 diventa $ 22,25. Ma il project manager a volte cambiò idea, ma cambiare l'arrotondamento al 10 o 5 cent più vicino sarebbe banale. Allo stesso modo ora non devo innervosirmi quando il mio progetto mgr desidera tempi di arrotondamento per un altro round di minuti.

Quindi questo metodo di arrotondamento è rapido e flessibile.


Il mio metodo è stato già trovato e pubblicato nel this 2008 SO solution

Problemi correlati