Добавление некоторого интервала к структурам ТМ - PullRequest
10 голосов
/ 18 ноября 2010

У меня есть одна структура тм .
И мне нужно добавить некоторый фиксированный интервал (дано в xx лет, xx месяцев, xx дней) в структуру tm .
Есть ли стандартная функция для этого?

Компилятор, который я использую, - MSVC 2005 на Windows XP.

Ответы [ 4 ]

10 голосов
/ 18 ноября 2010

Есть две функции, которые конвертируют форматы времени:

  1. mktime(), который преобразует struct tm (представляющее местное время) в time_t.
  2. localtime(), который конвертирует time_t в местное время в struct tm.

Интересно - это первое, которое принимает значения элементов структуры вне диапазона и в качестве побочного продукта преобразования устанавливает их (и все остальные) соответствующим образом. Это может использоваться для исправления значений данных поля после арифметических операций. Однако тип полей int, поэтому может возникнуть переполнение (в 16-битной системе), если e. г. Вы добавляете количество секунд в году.

Так что, если вы хотите иметь фактические даты, этот код поможет (измененная копия ответа от @pmg):

struct tm addinterval(struct tm x, int y, int m, int d) {
    x.tm_year += y;
    x.tm_mon += m;
    x.tm_mday += d;
    mktime(&x);
    return x;
}

Также обратите внимание на tm_isdst участника, заботьтесь об этом. Его значение может привести к смещению времени вперед и назад при переходе на даты перехода на летнее время.

9 голосов
/ 18 ноября 2010

Стандартный оператор сложения работает.

struct tm x;
/* add 2 years and 3 days to x */
x.tm_year += 2;
x.tm_mday += 3;

Редактировать: вы можете легко создать функцию

struct tm addinterval(struct tm x, int y, int m, int d) {
    x.tm_year += y;
    x.tm_mon += m;
    x.tm_mday += d;
    mktime(&x); /* normalize result */
    return x;
}

РЕДАКТИРОВАТЬ: добавлено mktime для нормализации результата

0 голосов
/ 30 августа 2017

Другие ответы приводят к крайне нестабильным результатам в зависимости от того, как ваша система инициализирует struct tm и правильно ли инициализированы значения времени в полдень.

Если все, что вас интересует, это изменения даты, а время остается неизменным, тогда установите tm_isdst, tm_hour, tm_sec все на 0, прежде чем переходить к mktime.Еще лучше, захватите их значения прежде и сбросьте их после для последовательности (и если они были непоследовательны прежде, они будут последовательно оставаться таковыми).Повторное использование кода из других ответов:

tm addinterval(tm t, int y, int m, int d)
{
    auto hour = t.tm_hour;
    auto min = t.tm_min;
    auto sec = t.tm_sec;

    // First we discover the DST Flag. By setting hour to 12
    //   we can assure the mktime does not shift the date
    //   because it will shift the hour!
    t.tm_isdst = 0;
    t.tm_hour = 12;
    t.tm_min = 0;
    t.tm_sec = 0;
    mktime(&t);

    // Now we can add the interval
    t.tm_year += y;
    t.tm_mon += m;
    t.tm_mday += d;
    mktime(&t);

    // Now reset the mid-day time values
    t.tm_hour = hour;
    t.tm_min = min;
    t.tm_sec = sec;

    // Return struct tm while keeping mid-day time the same
    //   while the only values that changed are the date and perhaps isdst.
    return t;
}

Хотелось бы, чтобы это было проще, но так оно и должно быть.

0 голосов
/ 18 ноября 2010

Предлагаю сначала преобразовать текущую дату в количество дней. Добавление интервала тогда тривиально. После этого конвертируйте число обратно в дату.

Вы можете найти алгоритмы для преобразования даты в число дней и обратно, например, на. http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

...