C ++ Int на любую дату без внешней библиотеки - PullRequest
1 голос
/ 28 октября 2019

Мне нужно конвертировать integers в date. Прежде всего, я знаю библиотеку Boost :: Gregorian, но я не могу ее использовать, потому что она не будет компилироваться с Clang, и именно там мое приложение достигает максимальной производительности.

Я анализирую необработанные файлы базы данных, поэтому производительность будет важна, поскольку преобразования будут происходить сотни тысяч раз для представления дат рождения, отметок времени, времени встреч и т. Д.

У меня естьНесколько разных дат происхождения в зависимости от того, какую базу данных я анализирую. Даты происхождения, которые я использую:

System 1: 1706-02-24
System 2: 1840-01-01

Я пробовал таким образом, но я получаю ошибку, что timeinfo2 является нулевым, когда я пытаюсь распечатать его:

time_t rawtime;
struct tm* timeinfo;
time(&rawtime);
timeinfo = localtime(&rawtime);
timeinfo->tm_year = 1706 - 1900;
timeinfo->tm_mon = 2 - 1;
timeinfo->tm_mday = 24;
timeinfo->tm_mday += 98040; // days since origin

time_t newtime;

struct tm* timeinfo2;
newtime = mktime(timeinfo);
timeinfo2 = localtime(&newtime);

Результат должен быть: 1968-08-12

Ответы [ 2 ]

0 голосов
/ 29 октября 2019

Я очень уважаю то, что собрал Говард, но мне нужно было что-то, что выполнялось бы как можно быстрее, и я беспокоился о включении всей библиотеки дат, когда все, что мне было нужно, это от int до date.

Вот что я придумал:

string GetDateFromDaysSincePointInTime(int days)
{
    int a, b, c, d, e, m, dd, mm, yyyy;
    a = days + 2374475;

    b = (4 * a + 3) / 146097;
    c = -b * 146097 / 4 + a;
    d = (4 * c + 3) / 1461;
    e = -1461 * d / 4 + c;
    m = (5 * e + 2) / 153;
    dd = -(153 * m + 2) / 5 + e + 1;
    mm = -m / 10 * 12 + m + 3;
    yyyy = b * 100 + d - 4800 + m / 10;
    return  to_string(yyyy) + "-" + to_string(mm) + '-' + to_string(dd);
}

Чтобы использовать это, просто назовите его с помощью int GetDateFromDaysSincePointInTime(113908). Это даст вам дату. Предполагая, что моя начальная точка отличается от вашей начальной точки, перейдите на сайт https://www.timeanddate.com/date/dateadd.html и добавьте / вычтите желаемую дату из даты, которая была выведена. Затем измените значение int для переменной a на эту сумму и снова запустите, чтобы получить исправленную дату.

Оттуда ее можно легко изменить, чтобы при желании иметь начальные нули:

std::ostringstream month;
month << std::setw(2) << std::setfill('0') << mm;
std::ostringstream day;
day << std::setw(2) << std::setfill('0') << dd;
return  to_string(yyyy) + "-" + month.str() + '-' + day.str()

Альтернативный способ

Вот еще один способ, который является более читабельным, и, кажется, нет никакого реального снижения производительности на 30 000 записей:

 string GetDateFromInt(int days)
 {
    int startYear = 1600;
    int year = days / 365.2421875;
    float peryear = 365.2421875;
    int remainder = fmod(days, peryear); // here you could add what day of the year to get a date in the middle of the year
    bool leapyear= ((year & 3) == 0  && (year % 100 != 0));
    int leapYearIndex = leapyear ? 1 : 0;
    int daysInYear = leapYearIndex ? 366 : 365;
    const unsigned short int __mon_yday[2][13] =
    {
        /* Normal years.  */
        { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
        /* Leap years.  */
        { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
    };
    int dayOfYear = remainder;

    if (dayOfYear >= 1 && dayOfYear <= daysInYear) {
        for (int mon = 0; mon < 12; mon++) {
            if (dayOfYear <= __mon_yday[leapYearIndex][mon + 1]) {
                int month = mon + 1;
                int dayOfMonth = dayOfYear - __mon_yday[leapYearIndex][mon];
                std::ostringstream months;
                months << std::setw(2) << std::setfill('0') << month;
                std::ostringstream day;
                day << std::setw(2) << std::setfill('0') << dayOfMonth;

                return  to_string(startYear + year) + "-" + months.str() + '-' + day.str();
            }
        }
    }
}
0 голосов
/ 29 октября 2019

Вот список общедоступных алгоритмов, которые моделируют Unix Time и проглептический григорианский календарь на миллионы лет назад и вперед во времени. Они чрезвычайно эффективны (без итераций, минимального ветвления, минимального перебора кеша)).

Вы можете использовать эти алгоритмы для создания собственной библиотеки дат, которая корректно обрабатывает даты до 1970 года. Это также те же алгоритмы, которые составляют основу чернового варианта Говарда Хиннанта для C ++ 20 предварительного просмотра библиотеки <chrono> .

...