2010-01-07 74 views
24

Esta es una cuestión de mejores prácticas. Tengo una utilidad que toma un año de dos dígitos como una cadena y necesito convertirlo en un año de cuatro dígitos como una cadena. en este momento lo hagoConvierta un año de dos dígitos en un año de cuatro dígitos

//DOB's format is "MMM (D)D YY" that first digit of the day is not there for numbers 1-9 
string tmpYear = rowIn.DOB.Substring(rowIn.DOB.Length - 3, 2); //-3 because it is 0 indexed 
if (Convert.ToInt16(tmpYear) > 50) 
    tmpYear = String.Format("19{0}", tmpYear); 
else 
    tmpYear = String.Format("20{0}", tmpYear); 

Estoy seguro de que lo estoy haciendo terriblemente mal, ¿algún indicio?

+15

Creo que debe elegir al azar entre 19-- y 20--. ¿Nadie aprendió de Y2K a no usar años de 2 dígitos? –

+3

Algunos clientes tienen sus cabezas hasta ahora en sus culos mandato uso de años de 2 dígitos. –

+0

¿Hay alguna otra información de fecha en el archivo db para ayudar? ¿Años? ¿Última visita al veterinario? ¿La última imagen? IsAlive? DODeath? Con suerte, puede presionar para actualizar el db. – Jess

Respuesta

52

El marco .NET tiene un método que hace exactamente lo que quiere:

int fourDigitYear = CultureInfo.CurrentCulture.Calendar.ToFourDigitYear(twoDigitYear) 

De esa manera se le apliquen correctamente las configuraciones actuales de la región como se define en el Panel de control (o de grupo):

Regional settings

+0

¿Existen diferencias regionales que influyan en la conversión del año de 2 a 4 dígitos? – Tomas

+0

o System.Globalization.CultureInfo.CurrentCulture o CultureInfo.CurrentUICulture o CultureInfo.DefaultThreadCurrentCulture, etc. – jnm2

+3

Me encuentro con esto en algún código actual. Usar la configuración cultural tailandesa significa que un año de 2000, almacenado como 00, se interpreta como 3100 en la era budista, o 3100-543 = 2557 en el sistema. Error muy confuso hasta que te des cuenta de lo que está pasando. –

16

Dado que hay personas vivas ahora nacidas antes de 1950, pero ninguna nacida después de 2010, su uso de 50 como el punto de partida parece roto.

Para la fecha de nacimiento, ¿no puede establecer el punto de inflexión al 'año del ahora' (es decir, 10) en su aplicación? Incluso entonces tendrá problemas con los nacidos antes de 1911 ...

No hay una manera perfecta de hacer esto: está creando información de la nada.

He asumido DOB ​​= fecha de nacimiento. Para otros datos (por ejemplo, el vencimiento de un instrumento financiero) la elección puede ser diferente, pero igual de imperfecta.

+0

Tiene razón acerca de la fecha de nacimiento, pero son para animales y no para humanos, y su esperanza de vida es como máximo de 40 años. pero tienes razón sobre usar un objetivo en movimiento. Ahora usaré 'if (Convert.ToInt16 (String.Format (" 20 {0} ", tmpYear [2]))> DateTime.Today.Year + 3) // Causa Y2.1K problema, pero me retiraré para entonces. ' –

+0

Como un animal _Logan's Run_ eh? Con un año de umbral en movimiento, y dado que no tiene una vida útil de 100 años, debería estar bien. Supuse que los humanos obviamente. Podría abordar el problema del Y2K1 haciendo que la parte Century se derive de Today también ... –

4

Podría ser más inteligente comprobar tmpYear> currentYear% 100. Si es así, entonces es 19XX, de lo contrario 20XX.

5

creo que Java tiene una buena aplicación de la presente:

http://java.sun.com/javase/6/docs/api/java/text/SimpleDateFormat.html#year

La gente rara vez especifican años en el futuro el uso de un código de dos dígitos. La implementación de Java maneja esto asumiendo un rango de 80 años atrás y 20 años antes del año actual. Entonces, en este momento, 30 sería 2030, mientras que 31 sería 1931. Además, esta implementación es flexible, modificando sus rangos a medida que pasa el tiempo, para que no tenga que cambiar el código cada década más o menos.

Acabo de probar, y Excel también utiliza estas mismas reglas para la conversión de 2 dígitos del año. 1/1/29 se convierte en 1/1/2029. 1/1/30 se convierte en 1/1/1930.

+2

JFYI, seis años después, las hojas de cálculo de Excel y Google todavía usan 30 como el año decisivo, por lo que aunque Java puede tener una ventana flotante, Excel y GS podría no ser tan inteligente –

+1

@ChrisB, la implementación original de Excel no fue tan inteligente, ahora ambos se apegan a esas reglas por razones de compatibilidad :) –

6

Una vez que haya tomado las otras sugerencias sobre cuándo cambiar las suposiciones del siglo del 19 al 20, lo mejor de todos los mundos posibles consiste en actualizar su fuente de datos de una vez por todas con años de 4 dígitos para que pueda parar haciendo suposiciones todo el tiempo.

+0

Lamentablemente no tengo control sobre la fuente de datos. –

0

Por curiosidad, ¿de dónde obtienes estos datos? De una forma? En ese caso; Simplemente le pediría al usuario que complete (o seleccione de alguna manera) el año con cuatro dígitos u obtenga los usuarios la edad y el mes/día de nacimiento, y use esa información para determinar en qué año nacieron. De esta manera, no tendría que preocuparse por este problema en absoluto :)

Editar: Utilice DateTime para trabajar con este tipo de datos.

+1

Si le preguntas a un perro por el año que nació, ¡no querrás esperar hasta que empiece a ladrar hasta 2003! 3 quick yaps es más eficiente ... – AdamV

6

También puede usar el método DateTime.TryParse para convertir su fecha. Utiliza los ajustes actuales de cultivo para definir el año de pivote (en mi caso es 2029)

DateTime resultDate; 
Console.WriteLine("CultureInfo.CurrentCulture.Calendar.TwoDigitYearMax : {0}", System.Globalization.CultureInfo.CurrentCulture.Calendar.TwoDigitYearMax); 
DateTime.TryParse("01/01/28", out resultDate); 
Console.WriteLine("Generated date with year=28 - {0}",resultDate); 
DateTime.TryParse("01/02/29",out resultDate); 
Console.WriteLine("Generated date with year=29 - {0}", resultDate); 
DateTime.TryParse("01/03/30", out resultDate); 
Console.WriteLine("Generated date with year=30 - {0}", resultDate); 

La salida es:

CultureInfo.CurrentCulture.Calendar.TwoDigitYearMax: 2029

fecha obtenida mediante años = 28 - 01/01/2028 00:00:00

fecha obtenida mediante años = 29 - 01/02/2029 00:00:00

Generado fecha con el año = 30 - 01/03/1930 00:00:00

Si desea cambiar el comportamiento, puede crear una cultura con el año que desea usar como pivote. Este hilo muestra un ejemplo

DateTime.TryParse century control C#

Pero como se dijo Martin, si desea administrar un período de tiempo que abarca más de 100 años, no hay manera de hacerlo con sólo 2 dígitos.

+3

FYI TwoDigitYearMax se configura en el panel de control. En Opciones regionales y de idioma. – Ray

+0

@Ray: gracias por la actualización. No lo sabía – FrenchData

0

probar este código simple

método // Invocar TextBoxDateFormat con la fecha como parámetro.

Método

public void TextBoxDateFormat(string str1) 

{ 

// Takes the current date format if MM/DD/YY or MM/DD/YYYY 

DateTime dt = Convert.ToDateTime(str1); 

//Converts the requested date into MM/DD/YYYY and assign it to textbox field 

TextBox = String.Format("{0:MM/dd/yyyy}", dt.ToShortDateString()); 


//include your validation code if required 

} 
0

Tenía un problema similar, y se le ocurrió esta ... HTH!

value = this.GetDate() 

if (value.Length >= 6)//ensure that the date is mmddyy 
{ 
    int year = 0; 

    if (int.TryParse(value.Substring(4, 2), out year)) 
    { 
     int pastMillenium = int.Parse(DateTime.Now.ToString("yyyy").Substring(0, 2)) - 1; 

     if (year > int.Parse(DateTime.Now.ToString("yy")))//if its a future year it's most likely 19XX 
     { 
      value = string.Format("{0}{1}{2}", value.Substring(0, 4), pastMillenium, year.ToString().PadLeft(2, '0')); 
     } 
     else 
     { 
      value = string.Format("{0}{1}{2}", value.Substring(0, 4), pastMillenium + 1, year.ToString().PadLeft(2, '0')); 
     } 
    } 
    else 
    { 
     value = string.Empty; 
    } 
} 
else 
{ 
    value = string.Empty; 
} 
0

Mi respuesta no coincidirá con su pregunta, pero para las tarjetas de crédito que acaba de añadir 2 dígitos del año en curso

private int UpconvertTwoDigitYearToFour(int yearTwoOrFour) 
    { 
     try 
     { 
      if (yearTwoOrFour.ToString().Length <= 2) 
      { 
       DateTime yearOnly = DateTime.ParseExact(yearTwoOrFour.ToString("D2"), "yy", null); 
       return yearOnly.Year; 
      } 
     } 
     catch 
     { 
     } 

     return yearTwoOrFour; 
    } 
+0

Excepción: cadena no reconocida como un DateTime válido. – MarwaAhmad

5

La implementación de

System.Globalization.CultureInfo.CurrentCulture.Calendar.ToFourDigitYear 

es

public virtual int ToFourDigitYear(int year) 
{ 
    if (year < 0) 
    throw new ArgumentOutOfRangeException("year", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum")); 
    if (year < 100) 
    return (this.TwoDigitYearMax/100 - (year > this.TwoDigitYearMax % 100 ? 1 : 0)) * 100 + year; 
    else 
    return year; 
} 

Espero que esto ayude!

+1

También debe mostrar cómo TwoDigitYearMax se completa mientras lo hace. – Vedran

0

Si se calcula para una persona que probablemente no será de más de 100 años ...

Ej: 751212

var nr = "751212"; 
var century = DateTime.Now.AddYears(-100).Year.ToString().Substring(0, 2); 

var days = (DateTime.Now - DateTime.Parse(century + nr)).Days; 
decimal years = days/365.25m; 
if(years>=99) 
century = DateTime.Now.Year.ToString().Substring(0, 2); 

var fullnr = century+nr; 
0

Para cambiar un 2 dígitos del año de 4 dígitos actual o anterior -

year = year + (DateTime.Today.Year - DateTime.Today.Year%100); 
if (year > DateTime.Today.Year) 
       year = year - 100; 
0

Esta solución la usamos para fechas de caducidad, el usuario ingresa MM y YY en campos separados. Esto da como resultado fechas 31 o 30 y 28 o 29 también para febrero.

/// <summary> 
/// Creates datetime for current century and sets days to end of month 
/// </summary> 
/// <param name="MM"></param> 
/// <param name="YY"></param> 
/// <returns></returns> 
public static DateTime GetEndOfMonth(string MM, string YY) 
{ 
    // YY -> YYYY #RipVanWinkle 
    // Gets Current century and adds YY to it. 
    // Minus 5 to allow dates that may be expired to be entered. 
    // eg. today is 2017, 12 = 2012 and 11 = 2111 
    int currentYear = DateTime.Now.Year; 
    string thisYear = currentYear.ToString().Substring(0, 2) + YY; 
    int month = Int32.Parse(MM); 
    int year = Int32.Parse(thisYear); 
    if ((currentYear - 5) > year) 
     year += 100; 

    return new DateTime(year, month, DateTime.DaysInMonth(year, month)); 
} 
Cuestiones relacionadas