Почему mktime() меняет день года моей структуры tm?

Я читаю две строки с годом, юлианским днем ​​(день года), часом, минутой и наблюдением.

Я вытаскиваю соответствующие переменные с помощью sscanf:

sscanf(tide_str1.c_str(), "%d %d %d %d %Lf", &y1, &j1, &h1, &m1, &obs1);
sscanf(tide_str2.c_str(), "%d %d %d %d %Lf", &y2, &j2, &h2, &m2, &obs2);

Для этого конкретного набора данных значения составляют 2011 083 23 22 1,1.

Затем я создаю и заполняю структуру tm и запускаю mktime с вызовами cout в промежутке между днями, и он меняется с 083 на 364.

int y1=2011, j1=83, h1=23, m1=22;
struct tm time_struct = {0, 0, 0, 0, 0, 0, 0, 0, 0}, *time_ptr = &time_struct;
time_t tv_min;
time_struct.tm_year = y1 - 1900;
time_struct.tm_yday = j1;
cout << time_struct.tm_yday << endl;
time_struct.tm_hour = h1;
time_struct.tm_min = m1;
time_struct.tm_isdst = -1;
cout << time_struct.tm_yday << endl;
tv_min = mktime(time_ptr);
cout << time_struct.tm_yday << endl;

Почему это? Это потому, что tm_mday и tm_mon установлены на 0? Сначала я пытался не инициализировать все это до нуля, но затем mktime вернул -1. Что я должен делать по-другому, если я знаю только день года, а не месяц и день месяца?


person RuQu    schedule 05.03.2012    source источник
comment
День в году иногда неправильно называют юлианским днем. На самом деле число Юлианского дня — это количество дней, прошедших с 1 января 4713 г. до н.э.; он используется в астрономии.   -  person Keith Thompson    schedule 06.03.2012
comment
Да, но оно настолько широко используется (неправильно) в определенных профессиях, что на практике может быть правильным. Пока все в поле используют один и тот же жаргин... общение происходит.   -  person RuQu    schedule 06.03.2012


Ответы (1)


mktime() делает то, что должен делать.

Цитирование стандарта C:

Функция mktime преобразует время в разбивке, выраженное как местное время, в структуре, на которую указывает timeptr, в значение календарного времени с той же кодировкой, что и значения возвращается функцией time. Исходные значения компонентов структуры tm_wday и tm_yday игнорируются, а исходные значения других компонентов не ограничиваются указанными выше диапазонами. При успешном завершении значения компонентов структуры tm_wday и tm_yday устанавливаются соответствующим образом, а остальные компоненты задаются для представления указанного календарного времени, но с их значениями. принудительно до указанных выше диапазонов; окончательное значение tm_mday не устанавливается до тех пор, пока не будут определены tm_mon и tm_year.

mktime() может вычислять значения tm_mday и tm_yday от других участников; он не предназначен для вычисления значений других членов из этих полей.

Что вы можете сделать, так это инициализировать struct tm со значениями вне допустимого диапазона. Например, если вы хотите, чтобы tm_yday равнялось 200 (200-й день года), вы можете инициализировать struct tm, представляющий 200-й день января. Затем mktime() нормализует его до правильной даты, получая значение time_t, которое затем можно передать в gmtime() или localtime().

Вот простой пример:

#include <iostream>
#include <ctime>

int main()
{
    struct tm t = { 0 };
    t.tm_sec = t.tm_min = t.tm_hour = 0; // midnight
    t.tm_mon = 0;                        // January
    t.tm_year = 2012 - 1900;
    t.tm_isdst = -1;                     // unknown

    t.tm_mday = 200;                     // January 200th?

    time_t when = mktime(&t);
    const struct tm *norm = localtime(&when);   // Normalized time

    std::cout << "month=" << norm->tm_mon << ", day=" << norm->tm_mday << "\n";
    std::cout << "The 200th day of 2012 starts " << asctime(norm);
}

Результат:

month=6, day=18
The 200th day of 2012 starts Wed Jul 18 00:00:00 2012
person Keith Thompson    schedule 05.03.2012
comment
Я попробовал ваш совет и инициализировал так: struct tm time_struct = {0, 0, 0, 200, 200, 0, 200, 0, 0}, и результат, когда я перезвонил, был 77-й день, когда он должен быть 83, что ближе, чем 364 раньше, но все еще выключен. - person RuQu; 06.03.2012
comment
Стандарт не гарантирует порядок элементов struct tm, поэтому такая инициализация не обязательно будет работать. Вы должны инициализировать или назначить все элементы по именам. Но если они объявлены в обычном порядке, вы инициализируете tm_mday и tm_mon значением 200. Я не думаю, что вам нужен 200-й или, скорее, 201-й месяц года. (И не забывайте, что struct tm нумерует месяцы от 0 до 11, а не от 1 до 12.) - person Keith Thompson; 06.03.2012
comment
Чтобы было ясно, если я хочу, чтобы день года был 83, я должен установить месяц на 0, а день месяца на 83? - person RuQu; 06.03.2012
comment
@RuQu: Да. Месяц 0 — это январь, поэтому установка tm_mon на 0 и tm_mday на 83 указывает на 83 января, которое затем будет нормализовано до 24 марта в високосный год, а в противном случае — до 25 марта. - person Keith Thompson; 06.03.2012
comment
Да, это сработало, с очевидным смещением на 1 день из-за использования 0 вместо 1 для начала. Спасибо. И что-то новое здесь ... как мне проголосовать за ваш ответ, так как он есть в комментариях? - person RuQu; 06.03.2012
comment
@RuQu: вы можете проголосовать за ответ (это означает, что он вам нравится), щелкнув стрелку вверх слева от него. Вы можете принять ответ (то есть тот, который решил вашу проблему), нажав на галочку. Сделайте либо то, и другое, либо ни то, ни другое по вашему выбору (это я не троллю за очки репутации). Вы также можете голосовать за (но не против) комментарии, если хотите, хотя это не так важно; при наведении курсора слева от комментария должна появиться стрелка вверх. Во всех случаях при наведении курсора на значок должен отображаться всплывающий текст, кратко объясняющий, что он делает. - person Keith Thompson; 06.03.2012