2009-05-24 11 views
35

Nel mio C# app, mi passa una variabile stringa che è di formato aaaammgg-aaaammgg che rappresenta una da e per la data. Voglio ottenere gli orari di inizio e fine rispettivamente per queste date. Attualmente ho il codice qui sotto, ma mi chiedevo se ci fosse più di una soluzione elegante?come ottenere i tempi di inizio e di fine di una giornata

Così per pdr = 20.090.521-20.090.523 otterrebbe "20.090.521 00:00:00" e "20.090.523 23:59:59"

private void ValidateDatePeriod(string pdr, out DateTime startDate, 
           out DateTime endDate) 
{ 
    string[] dates = pdr.Split('-'); 

    if (dates.Length != 2) 
    { 
     throw new Exception("Date period is of incorrect format"); 
    } 

    if (dates[0].Length != 8 || dates[1].Length != 8) 
    { 
     throw new Exception("Split date periods are of incorrect format"); 
    } 

    startDate = DateTime.ParseExact(dates[0] + " 00:00:00", 
     "yyyyMMdd HH:mm:ss", null); 
    endDate = DateTime.ParseExact(dates[1] + "23:59:59", 
     "yyyyMMdd HH::mm:ss", null); 
} 
+0

Come altri hanno affermato, EndOfDay è probabilmente un costrutto non necessario e impreciso, in quanto non ha un punto preciso nel tempo, tranne forse lo StartOfDay di domani. – user420667

risposta

13

Se siete preoccupati solo di .Net precisione ...

startDate = DateTime.ParseExact(dates[0], "yyyyMMdd"); 
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddTicks(-1).AddDays(1); 

Davvero non c'è bisogno di concatenare i valori aggiuntivi sulla stringa per la parte relativa all'ora.


Come un addendum, se si utilizza questo per una query, per esempio, un database ...

startDate = DateTime.ParseExact(dates[0], "yyyyMMdd"); 
endDate = DateTime.ParseExact(dates[1], "yyyyMMdd").AddDays(1); 

Con una query di ...

WHERE "startDate" >= @startDate AND "endDate" < @endDate 

Quindi i problemi di precisione indicati nei commenti non contano davvero. L'endDate in questo caso non sarebbe parte dell'intervallo, ma il limite esterno.

+0

NB: se si sta lavorando con un database, probabilmente si deve leggere la piccola stampa sulla precisione del database per 'end of day'. L'esempio che ho colpito era il tipo DateTime di SQL Server. È accurato a circa 3 millisecondi, quindi la fine della giornata diventa. AddMilliseconds (-3) –

+2

@ChrisFCarroll Personalmente, preferisco usare 'dtm> = start && dtm Tracker1

+0

Penso che mi hai fatto capire che la "fine della giornata" è in effetti una nozione inesistente, e quindi stiamo facendo del male. L'uso di '

9

L'oggetto DateTime ha una proprietà chiamata Date che restituirà solo la data di consegna. (La parte temporale è impostata di default alle 12:00).

Vorrei una soluzione più elegante (IMHO) che se si desidera consentire qualsiasi datetime nell'ultimo giorno, si aggiunge 1 giorno alla data e si confronta per consentire tempi maggiori o uguali alla data di inizio , ma strettamente inferiore alla data di fine (più 1 giorno).

// Calling code. beginDateTime and endDateTime are already set. 
// beginDateTime and endDateTime are inclusive. 
// targetDateTime is the date you want to check. 
beginDateTime = beginDateTime.Date; 
endDateTime = endDateTime.Date.AddDays(1); 

if (beginDateTime <= targetDateTime && 
    targetDateTime < endDateTime) 
    // Do something. 
+0

volevo restituire 2 datetimes dall'analisi di una stringa, quindi il metodo di chiamata potrebbe quindi utilizzare queste date per interrogare il mio db. – David

+1

@Matt: il tuo consiglio è particolarmente valido se i tempi possono avere una risoluzione inferiore al secondo. –

4

Questo è più o meno quello che avrei fatto, con alcune piccole modifiche (davvero un grosso problema, basta fare i difficili):

  • I TryParse()/TryParseExact() metodi devono essere utilizzati quale tornare false invece di buttare eccezioni .
  • FormatException è più specifico di Exception
  • Non c'è bisogno di verificare la presenza di Lunghezza == 8, perché ParseExact()/TryParseExact() farà questo
  • "00:00:00" e "23:59:59" non sono necessari
  • ritorno true/false è stati in grado di parse, invece di lanciare un'eccezione (ricordatevi di controllare valore restituito da questo metodo!)

Codice:

private bool ValidateDatePeriod(string pdr, out DateTime startDate, 
         out DateTime endDate) 
{ 
    string[] dates = pdr.Split('-'); 

    if (dates.Length != 2) 
    { 
     return false; 
    } 

    // no need to check for Length == 8 because the following will do it anyway 
    // no need for "00:00:00" or "23:59:59" either, I prefer AddDays(1) 

    if(!DateTime.TryParseExact(dates[0], "yyyyMMdd", null, DateTimeStyles.None, out startDate)) 
     return false; 

    if(!DateTime.TryParseExact(dates[1], "yyyyMMdd", null, DateTimeStyles.None, out endDate)) 
     return false; 

    endDate = endDate.AddDays(1); 
    return true; 
} 
+0

grazie per i commenti. bello sapere che ero sulla strada giusta e grato per i tweaks – David

33

Si potrebbe definire due metodi di estensione da qualche parte, in una classe di utilità in questo modo:

public static DateTime EndOfDay(this DateTime date) 
{ 
    return new DateTime(date.Year, date.Month, date.Day, 23, 59, 59, 999); 
} 

public static DateTime StartOfDay(this DateTime date) 
{ 
    return new DateTime(date.Year, date.Month, date.Day, 0, 0, 0, 0); 
} 

E poi utilizzarli nel codice in questo modo:

public DoSomething() 
{ 
    DateTime endOfThisDay = DateTime.Now.EndOfDay(); 
} 
+3

Risposta piacevole, ma errata. Si prega di vedere lo screenshot che ho fornito per vedere perché. –

+1

Infatti. Usa quello di Anar Khalilov, è meglio. –

+0

http://stackoverflow.com/a/20565672/1775459 – Vadim

103

Sono sorpreso di vedere come un incorrect answer ricevuto così tante upvotes:

Wrong value

La versione corretta sarebbe la seguente:

public static DateTime StartOfDay(this DateTime theDate) 
{ 
    return theDate.Date; 
} 

public static DateTime EndOfDay(this DateTime theDate) 
{ 
    return theDate.Date.AddDays(1).AddTicks(-1); 
} 
+2

come menzionato da @Chris F Carroll, -1 tick potrebbe non essere corretto anche. – liang

+2

@liang, ha detto: "AddTick (-1) funziona solo secondo la convenzione che non ci sono intervalli di tempo più piccoli di un tick". C'è un minor tempo inverval in .NET? –

+3

Ha dato esempio quando lavora con il database. L'implementazione del database varia. Quando in questi scenari, -1 tick potrebbe non essere più la fine della giornata. Almeno, non dovrebbe essere invocato per usare lo stesso confronto. Nello stesso spirito dei numeri fluttuanti, non è possibile stabilire quale sia il numero fluttuante più grande che è più piccolo di un numero affidabile che dipende dai dettagli dell'implementazione. Piuttosto maggiore/minore è probabilmente meglio. – liang

2

Penso che stiamo sbagliando. Non esiste una cosa come la fine della giornata. AddTick(-1) funziona solo in base alla convenzione che non ci sono intervalli di tempo inferiori a un segno di spunta. Quale è l'implementazione dipendente. È vero che la questione è dotato di un'implementazione di riferimento, vale a dire il DateTime classe .NET Framework, ma comunque dovremmo prendere questo come un indizio che la funzione che vogliamo in realtà non è EndOfDay() ma StartOfNextDay()

public static DateTime StartOfNextDay(this DateTime date) 
{ 
    return date.Date.AddDays(1); 
} 
+1

Perché non lo facciamo AddSeconds (-1), invece di aggiungere zecche? L'ultimo secondo della giornata è abbastanza preciso per la maggior parte degli scenari. – liang

2

Io uso il seguente in C#

public static DateTime GetStartOfDay(DateTime dateTime) 
{ 
    return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 0, 0, 0, 0); 
} 
public static DateTime GetEndOfDay(DateTime dateTime) 
{ 
    return new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999); 
} 

Poi in MS SQL faccio la seguente:

if datepart(ms, @dateEnd) = 0 
    set @dateEnd = dateadd(ms, -3, @dateEnd) 

Questo si tradurrà in MS SQL time 23: 59: 59.997 che è il tempo massimo prima di diventare il giorno successivo.

Si potrebbe semplicemente utilizzare:

new DateTime(dateTime.Year, dateTime.Month, dateTime.Day, 23, 59, 59, 999); 

che lavorerà in MS SQL, ma questo non è così preciso nella parte .Net.

0

Per SQL Server (versione 2008 R2 testata) questa gamma funziona.

StarDate '2016-01-11 00: 00: 01,990' DataFine '2016/01/19 23: 59: 59.990'

Sembra che le zecche è maggiore che l'ultimo secondo del giorno e automaticamente round Il giorno dopo. Così provo e lavoro, ho creato una tabella fittizia con due date per verificare quali valori è sql server che cattura e che inserisce nella stored procedure quei parametri.

Problemi correlati