2011-01-13 5 views
3

У меня есть функция, которую я написал (если есть хороший стандарт замена, пожалуйста, дайте мне знать ...)Преобразования в Отметку времени Unix некорректной

time_t get_unix_time(string time_str) { 
    time_t loctime; 
    time(&loctime); 

    struct tm *given_time; 
    time_str = time_str.substr(0, time_str.find_first_of('.')); 

    replace(time_str.begin(), time_str.end(), ':', ','); 
    replace(time_str.begin(), time_str.end(), '-', ','); 
    replace(time_str.begin(), time_str.end(), '/', ','); 
    replace(time_str.begin(), time_str.end(), ' ', ','); 

    given_time = localtime(&loctime); 
    vector<string> trecord = split_string(time_str, ','); 

    given_time->tm_year = atoi(trecord.at(0).c_str()) - 1900; 
    given_time->tm_mon = atoi(trecord.at(1).c_str()) - 1; 
    given_time->tm_mday = atoi(trecord.at(2).c_str()); 
    given_time->tm_hour = atoi(trecord.at(3).c_str()); 
    given_time->tm_min = atoi(trecord.at(4).c_str()); 
    given_time->tm_sec = atoi(trecord.at(5).c_str()); 

    return mktime(given_time); 
} 

входа (time_str), чтобы функция из формат 1970-01-01 00: 00: 00.0. Функция split_string() разбивает строку time_str в вектор, содержащий:

{1970, 01, 01, 00, 00, 00}

, который используется для заполнения в структуре given_time.

Я написал функцию для ее проверки и передал именно этот вход (начало эпохи). Тем не менее, время, которое он мне возвращает, составляет 21600, то есть 1970-01-01 06:00:00, или UTC + 6. Ожидаемый результат: (начало эпохи).

Примечание: что я нахожусь в центральном часовом поясе США, который является UTC - 6. В полночь 1 января 1970 года КНТ, время @ UTC будет 1 января 1970 года 06:00:00.

Есть ли что-нибудь в моей функции, что делает его конкретным для моего часового пояса? Я делаю что-то неправильно в этой функции, или могу ли я сделать что-то другое, чтобы сделать его независимым от зоны или, по крайней мере, всегда UTC.

+0

Кроме того, я не могу использовать библиотеку boost или любые другие дополнительные библиотеки. Я могу использовать только стандартные материалы на C++. – Sagar

+1

Обработка часового пояса в C++-библиотеке довольно некрасива. Если вы запустили свою программу с переменной окружения 'TZ', установленной в значение' UTC', этот фрагмент кода будет работать. – Omnifarious

+1

mktime интерпретирует данное время как местное время. Поэтому, если вы дадите 1970-01-01 00:00:00, это будет в ваше местное время, поэтому mktime вернет время UTC-0, то есть 1970-01-01 06:00:00 – Robert

ответ

5

Если вы используете glibc вы имеете функцию timegm в вашем распоряжении, который является версией mktime, который всегда интерпретирует время, как если бы это было в GMT часовом поясе. К сожалению, документация для этой функции в основном утверждает, что она не может быть реализована с использованием стандартных вызовов библиотеки. Так что вам не повезло, если у вас его нет.

+0

Спасибо! Это сработало отлично. Я смотрел на man-страницу для gmtime и ничего не видел. – Sagar

+1

@Sagar - Я нашел его на man-странице для 'mktime'. :-) – Omnifarious

1

Возможно, вы должны использовать gmtime вместо time, чтобы избавиться от проблем с часовым поясом.

Редактировать: Я не совсем понимаю, зачем вы заполняете структуру текущим временем, а затем перезаписываете все ее компоненты. Почему не просто:

time_t get_unix_time(const string& time_str) 
{ 
    vector<string> trecord = split_string(time_str, ','); 

    tm given_time; 
    given_time.tm_year = atoi(trecord.at(0).c_str()) - 1900; 
    given_time.tm_mon = atoi(trecord.at(1).c_str()) - 1; 
    given_time.tm_mday = atoi(trecord.at(2).c_str()); 
    given_time.tm_hour = atoi(trecord.at(3).c_str()); 
    given_time.tm_min = atoi(trecord.at(4).c_str()); 
    given_time.tm_sec = atoi(trecord.at(5).c_str()); 

    return mktime(&given_time); 
} 

Другой редактировать:

Тьфу, mktime считает местное время тоже. Я не совсем уверен, как вы можете обойти это, кроме как установить свой часовой пояс в UTC.

+0

- замена текущего времени и замена с тем, что мне нужно, на самом деле не проблема. Я попробовал вашу функцию, и она по-прежнему дает мне 21600 вместо 0. 21600 is = UTC + 6. – Sagar

+0

@Sagar: «Ugh, mktime также считает местное время. Я не совсем уверен, как вы можете обойти это, кроме настройки ваш часовой пояс в UTC ». Ты сделал это? Или вы просто ввели код, ничего не изменили и надеетесь на лучшее? –

+0

К сожалению, пока я могу изменить часовой пояс на моей машине разработки, это будет невозможно на машине клиента. – Sagar

0

Когда вы вызываете mktime, он интерпретирует параметр как локальное время. Вы также использовали функцию «localtime», которая кажется бесполезной, и я думаю, что вы можете ее удалить.

4

mktime занимает время в местном часовом поясе. Итак, если вы передадите его 1970-01-01 00:00:00 по местному времени, он возвращает 1970-01-01 06:00:00 UTC, как и должно быть.

В качестве альтернативы вы можете позвонить timegm, если вы используете glibc.Если вы не используете glibc, вы временно изменить местное время в UTC при вызове по баловаться указываете ей с переменной окружения TZ, как описано на timegm: страница руководства

time_t my_timegm (struct tm *tm) { 
    time_t ret; 
    char *tz; 
    tz = getenv("TZ"); 
    setenv("TZ", "", 1); 
    tzset(); 
    ret = mktime(tm); 
    if (tz) 
     setenv("TZ", tz, 1); 
    else 
     unsetenv("TZ"); 
    tzset(); 
    return ret; 
} 

Кроме того, ваш вызов localtime не требуется, и вы, вероятно, должны установить given_time->tm_isdst, чтобы избежать возможных проблем с летним временем.

+0

Спасибо. Я проверил timegm, и он делает то, что я хочу, но я обязательно проверю и установлю проблему dst. – Sagar

0

Вы можете написать обертку вокруг strptime, чтобы выполнить синтаксический анализ.

struct tm given_time; 

strptime(time_str.c_str(), "%Y-%m-%d %H:%M:%S", &given_time); 

return mktime(&given_time); 

@ Ответ Джош Келли объясняет проблему часового пояса полностью.

1

Просто избегайте этих неудобных функций и выполняйте математику самостоятельно. POSIX указывает, что time_t является арифметическим типом в виде секунд с «эпохи» (1970-01-01 00:00:00 GMT) без каких-либо ошибок в leapsecond (все дни равны 86400 календарных секунд, которые отличаются от SI секунд на крошечную сумму), поэтому в стороне от маленькой логики leapyear, вычисление чрезвычайно простое.

Календарные расчеты, подобные этому, являются стандартным вводным упражнением по программированию, поэтому я уверен, что вы сможете его решить или найти решения в Интернете.

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

+0

Я подумал, что если я не смогу найти решение этого вопроса, но подумал, есть ли такая функция, почему бы не попробовать ... это экономит мне дополнительную работу по тестированию. – Sagar

+0

Кстати, вот ссылка с формулой для другого направления: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_15 –