2014-06-18 16 views
6

Dato il seguente codice C#:date Interpretazione: Console.Writeline vs string.Format

var dt = DateTime.Now; 
Console.WriteLine("{0:MM/dd/yy} ... {1}", dt, string.Format("{0:MM/dd/yy}", dt)); 

... quando la data breve (sotto Windows 7, Control Panel -> Region and Language -> Additonal Settings -> Date) è impostato su Stati Uniti standard di "M/d/yyyy " ottengo questo:

06/17/14 ... 06/17/14 

Tuttavia, quando cambio la data breve per "ddd dd MMM yyyy," ottengo questo:

06/17/14 ... 06 17 14 

Ho avuto l'impressione che Console.WriteLine e string.Format sempre stringa formattato identicamente i valori DateTime. Qual è la spiegazione di questa discrepanza?

MODIFICA: Sembra che ciò avvenga solo nell'output di test dell'unità standard (Visual Studio), che è il luogo in cui originariamente ho visto il problema. Quando il codice viene eseguito in un'app console, l'output è 06 17 14 ... 06 17 14.

+0

Non dovrebbe importare quali siano le impostazioni di sistema quando si imposta in modo esplicito la stringa di formato. Penso che qualcos'altro stia succedendo qui. – Enigmativity

+0

In realtà può essere importante poiché "/" non sono caratteri letterali ma separatori e l'output effettivo dipende dalla cultura, ad es. in Germania sarebbe un ".". Ma questo non spiega perché l'output è diverso quando si utilizza lo stesso formato esplicito in 'Console.WriteLine' e' String.Format'. – Dirk

+0

@Enigmativity: Beh, modificare la data breve equivale a modificare la cultura, per quanto riguarda .NET. Mi chiedo solo perché le due chiamate al metodo non si comportano allo stesso modo. – MiloDC

risposta

3

Questa situazione si verifica perché quando MSTest reindirizza l'output della console alla finestra di test, passa CultureInfo.InvariantCulture allo TextWriter associato alla console.

Lo si può verificare con il seguente:

var threadCulture = Thread.CurrentThread.CurrentCulture; 
var consoleCulture = Console.Out.FormatProvider; 

Console.WriteLine(threadCulture.Equals(CultureInfo.InvariantCulture)); 
Console.WriteLine(consoleCulture.Equals(CultureInfo.InvariantCulture)); 

A meno che non la si cambia, la cultura corrente del thread è di solito qualcosa come en-US, o qualunque sia il vostro computer è impostato su. Quindi il primo oggetto sarà solitamente falso.

Ma il secondo elemento varia a seconda di dove viene eseguito. Come applicazione console, la cultura di output della console deve essere predefinita per la cultura del thread corrente, quindi sarà falsa. Nei test XUnit o NUnit, anche il risultato è falso. Ma in MSTest, il risultato è vero.

Se si scava attraverso la .NET Framework Reference Source, vedrai che

Non credo che le fonti per la MSTest test runner sono disponibili al pubblico, ma si può concludere che essi devono fare qualcosa di simile da qualche parte:

Console.Out = new SomeWriter(CultureInfo.InvariantCulture); 

Dove SomeWriter crea l'uscita di test ed eredita da TextWriter.

D'altra parte, String.Format utilizzerà sempre la cultura corrente del thread, a meno che non forniate specificatamente una cultura diversa.

Un modo per ovviare a questo sarebbe impostare in modo esplicito la cultura corrente del thread sulla cultura invariabile.

Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; 
+0

Grazie per la spiegazione, Matt! – MiloDC

+1

Grazie per la bella domanda! –

1

Ciò è dovuto al modo in cui il metodo Format interpreta il simbolo /.

Da MSDN

Se una stringa di formato personalizzato comprende il "/" identificatore di formato, il metodo DateTime.ToString visualizza il valore di DateSeparator al posto della "/" nel risultato stringa.

La proprietà DateSeparator definisce la stringa che sostituisce il separatore di data ("/" identificatore di formato di data e ora personalizzato) in una stringa di risultati in un'operazione di formattazione. Definisce anche la stringa del separatore della data in un'operazione di analisi.

Quando si modifica il formato, il simbolo predefinito viene cambiato in carattere spazio.

Se è necessario visualizzare il carattere /, è possibile farlo scorrere utilizzando \. Pertanto, la modifica della stringa di formato su {0:MM\/dd\/yy} mostrerà sempre /.

+0

Lo so già. Il problema non è che la barra sia cambiata in spazio bianco, il problema è che le due chiamate al metodo producono risultati diversi. Come ho notato, questo sembra accadere solo nell'output di test. – MiloDC