Gruja82 Ответов: 5

Как извлечь дату из строки?


Я из Сербии, и в нашей стране у каждого гражданина есть свой уникальный "номер", данный при рождении, называемый JMBG. Он содержит ровно 13 цифр. Он выглядит как "0704982763816", где первые 7 цифр представляют дату рождения (ДД,ММ, гггг). Как преобразовать это в тип datetime, чтобы я мог запросить таблицу для записей с датой рождения больше или меньше от этой даты?

Что я уже пробовал:

string unos = "0704982";
            DateTime datum= DateTime.ParseExact(unos, "ddmmyyy", System.Globalization.CultureInfo.InvariantCulture);
            MessageBox.Show(datum.ToString());

Это возвращает 7.4.0982, но мне нужно 7.4.1982. Также проблема есть и у людей, родившихся после 1999 года. год, например 0704001 - возвращает 7.4.0001

5 Ответов

Рейтинг:
41

Maciej Los

Прежде всего, [mm] зарезервировано на минуты, а не на месяцы. Воспользуйся [MM] вместо этого!

Проверить это:

string[] unosarray = new string[]{"0704982", "0704001"};
foreach(string unos in unosarray)
{
	string y = unos.Substring(4,1)=="9" ? "19" :  "20";
	string sdate = $"{unos.Substring(0,4)}{y}{unos.Substring(5,2)}";
	DateTime datum= DateTime.ParseExact(sdate, "ddMMyyyy", System.Globalization.CultureInfo.InvariantCulture);
	Console.WriteLine(datum.ToString("yyyy-MM-dd"));
}


результат:
1982-04-07
2001-04-07


Gruja82

Я знаю, что в течение нескольких минут я совершал ошибку.

TheRealSteveJudge

Эффективный подход без лишнего кода! 5*

Maciej Los

Спасибо.

Рейтинг:
2

TheRealSteveJudge

В дополнение к хорошему ответу Мацейса есть еще один.
Это будет работать для дат с 1900 по 2899 год...

using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;

namespace JBMG
{
    class Program
    {
        private const string PatternJmbg = "(?<DAY>[\\d]{2})(?<MONTH>[\\d]{2})(?<YEAR>[\\d]{3})\\d{6}";

        static void Main()
        {
            var jmbgList = new List<string>
            {
                "0101006500006",
                "1311970000000"
            };

            foreach (var jmbg in jmbgList)
            {
                var match = Regex.Match(jmbg, PatternJmbg);

                if (match.Success)
                {
                    var dayString = match.Groups["DAY"].Value;
                    var monthString = match.Groups["MONTH"].Value;
                    var yearString = GetCompleteYear(match.Groups["YEAR"].Value);

                    var day = int.Parse(dayString);
                    var month = int.Parse(monthString);
                    var year = int.Parse(yearString);

                    var dateTime = GetDateTime(day, month, year);

                    // Now you have a DateTime object...
                }
            }

            Console.ReadKey();
        }

        private static DateTime GetDateTime(int day, int month, int year)
        {
            return new DateTime(year, month, day);
        }

        private static string GetCompleteYear(string partialYear)
        {
            if(string.IsNullOrWhiteSpace(partialYear)) throw new Exception("Input string must not be empty.");
            if(partialYear.Length != 3) throw new Exception("The length of the input string must be 3.");

            return partialYear[0] == '9' ? $"1{partialYear}" : $"2{partialYear}";
        }
    }
}


Maciej Los

Регулярное выражение-хорошая альтернатива!

TheRealSteveJudge

Спасибо!

Richard Deeming

Я был бы склонен сделать GetCompleteYear работа с разобранными int а не веревка. Таким образом, вы избегаете дополнительной конкатенации строк.

private static int GetCompleteYear(int partialYear)
{
    if (partialYear > 999) throw new ArgumentOutOfRangeException();
    return partialYear + (partialYear >= 900 ? 1000 : 2000);
}
...
var yearString = match.Groups["YEAR"].Value;
int year = GetCompleteYear(int.Parse(yearString));


Вы также можете сделать регулярное выражение немного более конкретным:
private const string PatternJmbg = @"^(?<DAY>([012]\d)|(3[01]))(?<MONTH>(0\d)|(1[012]))(?<YEAR>[\d]{3})\d{6}$";

TheRealSteveJudge

Хорошие подсказки! Особенно в отношении шаблона регулярных выражений. Я знал, что мое регулярное выражение было недостаточно строгим.

Рейтинг:
1

Patrice T

Цитата:
Как извлечь дату из строки?

Как вы можете видеть, преобразование строки даты с отсутствующей информацией не восстанавливает эту отсутствующую информацию, это происходит потому, что формат даты не является стандартным.
Вам нужно стандартизировать строку до стандартного формата даты, вам нужно заново вставить недостающую тысячу лет, и для этого вам нужно использовать свои знания о том, что это день рождения человека.
Чтобы стандартизировать строку, вам нужно извлечь столетие и вывести, что такое недостающая тысячная цифра.
Цитата:
Есть ли другой способ?

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


Рейтинг:
1

Gruja82

Спасибо вам всем за ваши решения. Я использовал решение, опубликованное компанией

Maciej Los
в сочетании с моим решением, но я решил создать sql-функцию и использовать ее в вычисляемом столбце, который содержит дату рождения, извлеченную из JMBG.


Рейтинг:
0

Gruja82

Я нашел это:

if (unos.Substring(4,1)=="9")
            {
               unos= unos.Insert(4, "1");

            }
            else if (unos.Substring(4,1)=="0")
            {
              unos=  unos.Insert(4, "2");
            }

Есть ли другой способ?


Maciej Los

Да, есть! Пожалуйста, смотрите мой ответ.