Преобразование года из двух цифр в год из четырех цифр

Это вопрос лучших практик. У меня есть служебная программа, которая принимает год из двух цифр в виде строки, и мне нужно преобразовать ее в год из четырех цифр в виде строки. прямо сейчас я делаю

//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);

Я уверен, что делаю это ужасно неправильно, есть указатели?


person Scott Chamberlain    schedule 07.01.2010    source источник
comment
Я думаю, вам следует наугад выбирать между 19 и 20. Разве никто не научился из 2000 года не использовать двузначные годы?   -  person Joe Phillips    schedule 08.01.2010
comment
Некоторые клиенты ‹strike› пока что не подозревают ‹/strike› требуют использования двухзначного числа лет.   -  person Ian Boyd    schedule 20.06.2010
comment
Есть ли другая информация о дате в базе данных, которая может помочь? Возраст? Последний визит к ветеринару? Последнее изображение? Является живым? DOD Смерть? Надеюсь, вы сможете обновить базу данных.   -  person Jess    schedule 19.08.2010


Ответы (16)


В .NET framework есть метод, который делает именно то, что вы хотите:

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

Таким образом, вы будете правильно придерживаться текущих региональных настроек, определенных в Панели управления (или групповой политике):

Региональные настройки

person Vedran    schedule 02.05.2012
comment
Существуют ли какие-либо региональные различия, влияющие на преобразование года от 2 до 4? - person Tomas; 18.04.2013
comment
Или System.Globalization.CultureInfo.CurrentCulture или CultureInfo.CurrentUICulture или CultureInfo.DefaultThreadCurrentCulture и т. Д. - person jnm2; 07.04.2014
comment
Я сталкиваюсь с этим на каком-то текущем коде. Использование тайских культурных традиций означает, что 2000 год, сохраненный как 00, интерпретируется как 3100 в буддийской эре, или 3100-543 = 2557 в системе! Очень запутанная ошибка, пока вы не поймете, что происходит. - person Sean Duggan; 18.07.2014
comment
Поворот сюжета: если вы сделаете .ToFourDigitYear("99"), он вернет 1999, но если вы сделаете .ToFourDigitYear("16"), он даст вам 2016. Похоже, что 0-29 даст вам 2000-е, а все, что больше, даст вам 1900-е. - person Sinaesthetic; 19.06.2015
comment
@Sinaesthetic Нет поворотов сюжета; он работает, как определено в региональных настройках. - person Vedran; 31.08.2015
comment
работать в моей системе с PersianCalendar, не работает на одном из серверов с таким же календарем - person deadManN; 02.08.2016
comment
@deadManN проверьте, какой календарь установлен для пользователя, под каким приложением запущено на сервере. - person Vedran; 08.02.2017
comment
это был не мой проект, и он его выполнил. кстати, спасибо за ответ - person deadManN; 08.02.2017
comment
Если я сделаю это с CultureInfo.InvariantCulture, будет ли диапазон навсегда зафиксирован на 1930-2029 годах или он будет как-то корректироваться с течением времени? - person FunctorSalad; 24.12.2017

Учитывая, что есть живые люди, родившиеся до 1950 года, но ни один из которых не родился после 2010 года, использование числа 50 в качестве точки перелома кажется неправильным.

Что касается даты рождения, разве вы не можете установить точку переключения на «текущий год» (т. Е. 10) в своем приложении? Даже тогда у вас будут проблемы с теми, кто родился до 1911 года ...

Для этого нет идеального способа - вы создаете информацию из воздуха.

Я предположил, что DOB = дата рождения. Для других данных (например, зрелости финансового инструмента) выбор может быть другим, но столь же несовершенным.

person martin clayton    schedule 07.01.2010
comment
Вы правы насчет DOB, но они предназначены для животных, а не для людей, и их продолжительность жизни составляет не более 40 лет. но вы правы, используя движущуюся цель. Теперь я буду использовать if (Convert.ToInt16(String.Format("20{0}", tmpYear[2])) > DateTime.Today.Year + 3) // Causes Y2.1K problem, but I will be retired by then. - person Scott Chamberlain; 08.01.2010
comment
Как животное Logan's Run, а? С подвижным пороговым годом и без продолжительности жизни более 100 лет все должно быть в порядке. Я, очевидно, предположил, что это люди. Вы можете решить проблему 2000 года, сделав часть Century заимствованной и из Today ... - person martin clayton; 09.01.2010

Вы также можете использовать метод DateTime.TryParse для преобразования даты. Он использует текущие настройки культуры для определения опорного года (в моем случае это 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);

Результат:

CultureInfo.CurrentCulture.Calendar.TwoDigitYearMax: 2029 г.

Созданная дата с годом = 28 - 01.01.2028 00:00:00

Сгенерированная дата с годом = 29 - 01/02/2029 00:00:00

Сгенерированная дата с годом = 30 - 01.03.1930 00:00:00

Если вы хотите изменить поведение, вы можете создать культуру с годом, который вы хотите использовать в качестве опорного. Эта ветка показывает пример

Элемент управления веком DateTime.TryParse C #

Но, как сказал Мартин, если вы хотите управлять периодом времени, охватывающим более 100 лет, нет способа сделать это с помощью только двух цифр.

person FrenchData    schedule 07.01.2010
comment
К вашему сведению, TwoDigitYearMax установлен на панели управления. В разделе "Язык и региональные стандарты". - person Ray; 08.11.2011

Я думаю, что у Java есть хорошая реализация этого:

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

Люди редко указывают годы в далеком будущем, используя двузначный код. Реализация Java справляется с этим, предполагая, что диапазон отстает на 80 лет и на 20 лет опережает текущий год. Итак, прямо сейчас 30 будет 2030, а 31 будет 1931. Кроме того, эта реализация является гибкой, изменяя свои диапазоны с течением времени, так что вам не нужно менять код каждые десять лет или около того.

Я только что протестировал, и Excel также использует те же правила для преобразования двухзначного года. 29.01.29 превращается в 01.01.2029. 01.01.30 превращается в 01.01.1930.

person jdmichal    schedule 07.01.2010
comment
JFYI, шесть лет спустя электронные таблицы Excel и Google по-прежнему используют 30 в качестве года водораздела, поэтому, хотя Java может иметь плавающее окно, Excel и GS могут быть не такими умными. - person Chris B; 19.02.2016
comment
@ChrisB ну, исходная реализация Excel была не такой уж и умной, теперь они оба придерживаются этих правил из соображений совместимости :) - person Tobias J; 08.02.2017

Реализация

System.Globalization.CultureInfo.CurrentCulture.Calendar.ToFourDigitYear 

is

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;
}

Надеюсь это поможет!

person RealWillyWoka    schedule 14.10.2013
comment
Вы также должны показать, как заполняется TwoDigitYearMax, пока вы на нем. - person Vedran; 10.02.2015

Возможно, будет разумнее проверить tmpYear> currentYear% 100. Если да, то это 19ХХ, иначе 20ХХ.

person Ponkadoodle    schedule 07.01.2010

Это решение, которое мы используем для дат истечения срока, пользователь вводит MM и YY в отдельные поля. Это приводит к 31 или 30 и 28 или 29 числам февраля.

/// <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));
}
person tyler_mitchell    schedule 13.06.2017

Этот метод может преобразовать последние два года кредитной карты в четырехлетние цифры.


private static int ToFourDigitYear(int year)
{
    string stringYear = year.ToString("00");
    if (stringYear.Length == 2)
    {
        int currentYear = DateTime.Now.Year;
        string firstTwoDigitsOfCurrentYear = currentYear.ToString().Substring(0, 2);
        year = Convert.ToInt32(firstTwoDigitsOfCurrentYear + stringYear);
        if (year < currentYear)
            year = year + 100;
    }
    return year;
}
person Shiv    schedule 28.09.2018
comment
Добро пожаловать в SO! Ответы, содержащие только код, не приветствуются, поскольку они не дают никакого представления о том, как решить возникшую проблему. Обновите свое решение, чтобы объяснить, как ваш код решает проблему OP :) - person Joel; 28.09.2018

Из любопытства, откуда вы берете эти данные? Из формы? В этом случае; Я бы просто попросил пользователя ввести (или как-то выбрать) год с четырьмя цифрами или получить возраст пользователя и месяц / день рождения и использовать эти данные, чтобы выяснить, в каком году они родились. Таким образом, вам вообще не придется беспокоиться об этой проблеме :)

Изменить: используйте DateTime для работа с такими данными.

person Leif    schedule 07.01.2010
comment
Если вы спросите собаку, в каком году она родилась, вам не захочется ждать, пока она лает до 2003 года! 3 быстрых тявкания эффективнее ... - person AdamV; 23.09.2011

Попробуйте этот простой код

// Вызов метода TextBoxDateFormat с датой в качестве параметра.

Метод

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

}
person Jags    schedule 01.12.2011

Была аналогичная проблема, и я придумал это ... 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;
}
person bizah    schedule 29.03.2012

Мой ответ не будет соответствовать вашему вопросу, но для кредитных карт я просто добавляю 2 цифры текущего года

    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;
    }
person Pawel Cioch    schedule 10.07.2013
comment
Исключение: строка не была распознана как допустимый DateTime. - person MarwaAhmad; 07.06.2016

Если посчитать на человека, ему, наверное, не больше 100 лет ...

Eg: 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;
person Mattias Engman    schedule 09.02.2015

Чтобы изменить год с 2 цифрами на текущий или более ранний с 4 цифрами:

year = year + (DateTime.Today.Year - DateTime.Today.Year%100);
if (year > DateTime.Today.Year)
                year = year - 100;
person Ellen22    schedule 22.11.2016

Мои два цента,

Учитывая возрастной диапазон = [18, 100+], год из двух цифр = 90, я могу сделать

current year - twoDigitsYear = 2018 - 90 = 1928, у меня 19, 28

следовательно, 19 - это первые две цифры года рождения, а 28 - возраст, то есть
год = 1990, возраст = 28.

Но это не сработает, когда возраст 0 и 100 включены в диапазон, как и некоторые другие ответы здесь.

person Beeing Jk    schedule 20.04.2018

Основываясь на приведенных выше решениях, вот мой, я использовал в Android при использовании java

он принимает текущий год в двухзначном формате, затем проверяет, равна ли длина входного года 2, если да, то он получает текущий год, и с этого года он разделяет первые две цифры века, затем добавляет это столетие с введенным пользователем годом. сделать год четырехзначным.

public static int getConvertedYearFromTwoToFourDigits(String year) {
        if (year.length() == 2) {
            int currentYear = Calendar.getInstance().get(Calendar.YEAR);
            String firstTwoDigitsOfCurrentYear = String.valueOf(currentYear).substring(0, 2);
            year = firstTwoDigitsOfCurrentYear + year;
        }
        return Integer.parseInt(year);
    }
person Abhishek Garg    schedule 23.01.2020