Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este artículo se examina cómo se controlan los datos con formato, como los datos numéricos y los datos de fecha y hora, para mostrar y para el almacenamiento.
Al desarrollar con .NET, utilice formato culturalmente sensible para mostrar datos que no son cadenas, como números y fechas, en una interfaz de usuario. Use el formato con la referencia cultural invariable para conservar datos que no son de cadena en forma de cadena. No use el formato específico de la cultura para conservar datos numéricos o de fecha y hora como cadenas de texto.
Mostrar datos con formato
Cuando se muestran datos que no son de cadena, como números y fechas y horas a los usuarios, dé formato a ellos mediante la configuración cultural del usuario. De forma predeterminada, los siguientes elementos usan la referencia cultural actual al dar formato a las operaciones:
- Cadenas interpoladas compatibles con los compiladores de C# y Visual Basic .
- Operaciones de concatenación de cadenas que usan los operadores de concatenación de C# o Visual Basic o que llaman al String.Concat método directamente.
- Método String.Format.
- Métodos
ToString
de los tipos numéricos y tipos de fecha y hora.
Para especificar explícitamente que se debe dar formato a una cadena mediante las convenciones de una referencia cultural designada o la referencia cultural invariable, puede hacer lo siguiente:
Al usar los métodos String.Format y
ToString
, llame a una sobrecarga que tenga un parámetroprovider
, como String.Format(IFormatProvider, String, Object[]) o DateTime.ToString(IFormatProvider), y pásele la propiedad CultureInfo.CurrentCulture, una instancia CultureInfo que representa la referencia cultural deseada, o la propiedad CultureInfo.InvariantCulture.En el caso de la concatenación de cadenas, no permita que el compilador realice ninguna conversión implícita. En su lugar, realice una conversión explícita mediante una llamada a una sobrecarga
ToString
que tenga un parámetroprovider
. Por ejemplo, el compilador usa implícitamente la referencia cultural actual al convertir un Double valor en una cadena en el código siguiente:string concat1 = "The amount is " + 126.03 + "."; Console.WriteLine(concat1);
Dim concat1 As String = "The amount is " & 126.03 & "." Console.WriteLine(concat1)
En su lugar, puede especificar explícitamente la referencia cultural cuyas convenciones de formato se usan en la conversión llamando al Double.ToString(IFormatProvider) método , como hace el código siguiente:
string concat2 = "The amount is " + 126.03.ToString(CultureInfo.InvariantCulture) + "."; Console.WriteLine(concat2);
Dim concat2 As String = "The amount is " & 126.03.ToString(CultureInfo.InvariantCulture) & "." Console.WriteLine(concat2)
Para la interpolación de cadenas, en lugar de asignar una cadena interpolada a una String instancia, asígnela a .FormattableString A continuación, puede llamar a su FormattableString.ToString() método para generar una cadena de resultado que refleje las convenciones de la referencia cultural actual, o bien puede llamar al FormattableString.ToString(IFormatProvider) método para generar una cadena de resultado que refleje las convenciones de una referencia cultural especificada.
También puede pasar la cadena con formato al método estático FormattableString.Invariant para generar una cadena de resultados que refleje las convenciones de la cultura invariable. En el ejemplo siguiente se muestra este enfoque. (La salida del ejemplo refleja una referencia cultural actual de
en-US
).using System; using System.Globalization; class Program { static void Main() { Decimal value = 126.03m; FormattableString amount = $"The amount is {value:C}"; Console.WriteLine(amount.ToString()); Console.WriteLine(amount.ToString(new CultureInfo("fr-FR"))); Console.WriteLine(FormattableString.Invariant(amount)); } } // The example displays the following output: // The amount is $126.03 // The amount is 126,03 € // The amount is ¤126.03
Imports System.Globalization Module Program Sub Main() Dim value As Decimal = 126.03 Dim amount As FormattableString = $"The amount is {value:C}" Console.WriteLine(amount.ToString()) Console.WriteLine(amount.ToString(new CultureInfo("fr-FR"))) Console.WriteLine(FormattableString.Invariant(amount)) End Sub End Module ' The example displays the following output: ' The amount is $126.03 ' The amount is 126,03 € ' The amount is ¤126.03
Nota:
Si usa C# y aplica formato a la referencia cultural invariable, es más eficaz llamar a String.Create(IFormatProvider, DefaultInterpolatedStringHandler) y pasar CultureInfo.InvariantCulture para el primer parámetro. Para obtener más información, vea Interpolación de cadenas en C# 10 y .NET 6.
Conservar datos con formato
Puede conservar datos que no son de cadena como datos binarios o como datos con formato. Si decide guardarlos como datos con formato, debe llamar a una sobrecarga del método de formato que incluya un parámetro provider
y pasarle la propiedad CultureInfo.InvariantCulture . La cultura invariable proporciona un formato coherente para los datos formateados que son independientes de la cultura y de la máquina. Por el contrario, guardar datos formateados utilizando culturas distintas de la cultura invariable presenta una serie de limitaciones.
- Es probable que los datos no se puedan usar si se recuperan en un sistema que tiene una referencia cultural diferente o si el usuario del sistema actual cambia la referencia cultural actual e intenta recuperar los datos.
- Las propiedades de una referencia cultural en un equipo específico pueden diferir de los valores estándar. En cualquier momento, un usuario puede personalizar la configuración de visualización sensible a la cultura. Debido a esto, es posible que los datos con formato guardados en un sistema no se puedan leer después de que el usuario personalice la configuración cultural. Es probable que la portabilidad de datos con formato entre equipos sea aún más limitada.
- Estándares internacionales, regionales o nacionales que rigen el formato de números o fechas y horas cambian con el tiempo, y estos cambios se incorporan a las actualizaciones del sistema operativo Windows. Cuando cambian las convenciones de formato, los datos con formato que se aplicaron mediante las convenciones anteriores pueden volverse ilegibles.
En el siguiente ejemplo se ilustra la limitada portabilidad que resulta de usar un formato sensible a la cultura para almacenar datos. En el ejemplo se guarda una matriz de valores de fecha y hora en un archivo. Se les da formato utilizando las convenciones de la cultura inglesa (Estados Unidos). Una vez que la aplicación cambia la referencia cultural actual a francés (Suiza), intenta leer los valores guardados mediante las convenciones de formato de la referencia cultural actual. El intento de leer dos de los elementos de datos produce una FormatException excepción y la matriz de fechas ahora contiene dos elementos incorrectos que son iguales a MinValue.
using System;
using System.Globalization;
using System.IO;
using System.Text;
using System.Threading;
public class Example
{
private static string filename = @".\dates.dat";
public static void Main()
{
DateTime[] dates = { new DateTime(1758, 5, 6, 21, 26, 0),
new DateTime(1818, 5, 5, 7, 19, 0),
new DateTime(1870, 4, 22, 23, 54, 0),
new DateTime(1890, 9, 8, 6, 47, 0),
new DateTime(1905, 2, 18, 15, 12, 0) };
// Write the data to a file using the current culture.
WriteData(dates);
// Change the current culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH");
// Read the data using the current culture.
DateTime[] newDates = ReadData();
foreach (var newDate in newDates)
Console.WriteLine(newDate.ToString("g"));
}
private static void WriteData(DateTime[] dates)
{
StreamWriter sw = new StreamWriter(filename, false, Encoding.UTF8);
for (int ctr = 0; ctr < dates.Length; ctr++) {
sw.Write("{0}", dates[ctr].ToString("g", CultureInfo.CurrentCulture));
if (ctr < dates.Length - 1) sw.Write("|");
}
sw.Close();
}
private static DateTime[] ReadData()
{
bool exceptionOccurred = false;
// Read file contents as a single string, then split it.
StreamReader sr = new StreamReader(filename, Encoding.UTF8);
string output = sr.ReadToEnd();
sr.Close();
string[] values = output.Split( new char[] { '|' } );
DateTime[] newDates = new DateTime[values.Length];
for (int ctr = 0; ctr < values.Length; ctr++) {
try {
newDates[ctr] = DateTime.Parse(values[ctr], CultureInfo.CurrentCulture);
}
catch (FormatException) {
Console.WriteLine($"Failed to parse {values[ctr]}");
exceptionOccurred = true;
}
}
if (exceptionOccurred) Console.WriteLine();
return newDates;
}
}
// The example displays the following output:
// Failed to parse 4/22/1870 11:54 PM
// Failed to parse 2/18/1905 3:12 PM
//
// 05.06.1758 21:26
// 05.05.1818 07:19
// 01.01.0001 00:00
// 09.08.1890 06:47
// 01.01.0001 00:00
// 01.01.0001 00:00
Imports System.Globalization
Imports System.IO
Imports System.Text
Imports System.Threading
Module Example
Private filename As String = ".\dates.dat"
Public Sub Main()
Dim dates() As Date = {#5/6/1758 9:26PM#, #5/5/1818 7:19AM#, _
#4/22/1870 11:54PM#, #9/8/1890 6:47AM#, _
#2/18/1905 3:12PM#}
' Write the data to a file using the current culture.
WriteData(dates)
' Change the current culture.
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("fr-CH")
' Read the data using the current culture.
Dim newDates() As Date = ReadData()
For Each newDate In newDates
Console.WriteLine(newDate.ToString("g"))
Next
End Sub
Private Sub WriteData(dates() As Date)
Dim sw As New StreamWriter(filename, False, Encoding.Utf8)
For ctr As Integer = 0 To dates.Length - 1
sw.Write("{0}", dates(ctr).ToString("g", CultureInfo.CurrentCulture))
If ctr < dates.Length - 1 Then sw.Write("|")
Next
sw.Close()
End Sub
Private Function ReadData() As Date()
Dim exceptionOccurred As Boolean = False
' Read file contents as a single string, then split it.
Dim sr As New StreamReader(filename, Encoding.Utf8)
Dim output As String = sr.ReadToEnd()
sr.Close()
Dim values() As String = output.Split({"|"c})
Dim newDates(values.Length - 1) As Date
For ctr As Integer = 0 To values.Length - 1
Try
newDates(ctr) = DateTime.Parse(values(ctr), CultureInfo.CurrentCulture)
Catch e As FormatException
Console.WriteLine("Failed to parse {0}", values(ctr))
exceptionOccurred = True
End Try
Next
If exceptionOccurred Then Console.WriteLine()
Return newDates
End Function
End Module
' The example displays the following output:
' Failed to parse 4/22/1870 11:54 PM
' Failed to parse 2/18/1905 3:12 PM
'
' 05.06.1758 21:26
' 05.05.1818 07:19
' 01.01.0001 00:00
' 09.08.1890 06:47
' 01.01.0001 00:00
' 01.01.0001 00:00
'
Sin embargo, si reemplaza la CultureInfo.CurrentCulture propiedad por CultureInfo.InvariantCulture en las llamadas a DateTime.ToString(String, IFormatProvider) y DateTime.Parse(String, IFormatProvider), los datos de fecha y hora persistentes se restauran correctamente, como se muestra en la salida siguiente:
06.05.1758 21:26
05.05.1818 07:19
22.04.1870 23:54
08.09.1890 06:47
18.02.1905 15:12