Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.89/18: Рейтинг темы: голосов - 18, средняя оценка - 4.89
1932 / 1761 / 822
Регистрация: 23.01.2014
Сообщений: 6,205
1

Human Time to Unix Timestamp

29.09.2015, 11:23. Просмотров 3347. Ответов 5
Метки нет (Все метки)

Запутался с переводом времени
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* Перевод времени из формата %d.%m.%y %H:%M:%S (UTC)
 * в метку времени Unix Timestamp
 */
std::string dateStr2str(std::string input)
{
    /* Ввожу 25.09.15 08:40:00
     * На выхоже ожидаю 1443170400
     * Вместо этого получаю разницу в -4 или -7 часов
     */
 
    std::string result = "";
    int day, month, year, hour, minute, second;
 
    sscanf(input.c_str(), "%d.%d.%d %d:%d:%d", &day, &month, &year, &hour, &minute, &second);
 
    std::tm dt;
    dt.tm_mday = day;
    dt.tm_mon = month - 1;
    dt.tm_year = year + 2000 - 1900;
    dt.tm_hour = hour;
    dt.tm_min = minute;
    dt.tm_sec = second;
    std::time_t t = std::mktime(&dt);
    // вывожу разницу в часах после mktime
    // результат 1443156000 -4
    std::cout << t << " " << (t - 1443170400) / 60 / 60 << std::endl;
    dt = *std::gmtime(&t);
    t = std::mktime(&dt);
    // вывожу разницу в часах после gmtime
    // результат 144314200 -7
    std::cout << t << " " << (t - 1443170400) / 60 / 60 << std::endl;
 
    result = std::to_string(t);
    return result;
}
Я, конечно, могу вручную добавлять 4 часа, но думаю это не совсем правильно.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.09.2015, 11:23
Ответы с готовыми решениями:

Unix timestamp замерить время работы программы
Как можно с помощью unix timestamp замерить время работы программы в секундах (с++)?

UNIX-time с нуля
Проблема следующая - реализовал я с нуля перевод из юникс -времени в человечную дату. А тут...

Преобразование даты в Unix-time
Нужна формула или функция для преобразование даты в Unix-time. Например: На вход дата: Sun Apr...

Как преобразовать время из строки в Unix Time?
Получаю &quot;Sat, 18 Jul 2015 19:56:37 +0300&quot; Знаю что можно strptime или бустом, но какой шаблон для...

5
13883 / 7419 / 1759
Регистрация: 30.01.2014
Сообщений: 12,412
29.09.2015, 14:29 2
Цитата Сообщение от pav1uxa Посмотреть сообщение
Запутался с переводом времени
Тут все просто:
mktime
....
This function performs the reverse translation that localtime does.
mktime для времени полученного через gmtime не совсем подходит.
Поэтому тут есть два пути.
Либо переводить все в "локальном" времени, а затем преобразовывать в UTC.
Либо, воспользоваться нестандартной функцией timegm вместо mktime.
0
1932 / 1761 / 822
Регистрация: 23.01.2014
Сообщений: 6,205
29.09.2015, 15:36  [ТС] 3
Цитата Сообщение от DrOffset Посмотреть сообщение
Либо переводить все в "локальном" времени, а затем преобразовывать в UTC.
Как?
Цитата Сообщение от DrOffset Посмотреть сообщение
Либо, воспользоваться нестандартной функцией timegm вместо mktime.
У меня OS Windows 7: error: 'timegm' was not declared in this scope
Пробовал _mkgmtime, пишет undefined reference to _mkgmtime.
0
13883 / 7419 / 1759
Регистрация: 30.01.2014
Сообщений: 12,412
29.09.2015, 16:13 4
Цитата Сообщение от pav1uxa Посмотреть сообщение
Как?
Использовать localtime вместо gmtime и сравнивать с значением локального времени.
Например, для моего часового пояса, 25.09.15 08:40:00 - это 1443156000.
Т.е. как-то так:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
std::string dateStr2str(std::string input)
{
    std::string result = "";
    int day, month, year, hour, minute, second;
 
    sscanf(input.c_str(), "%d.%d.%d %d:%d:%d", &day, &month, &year, &hour, &minute, &second);
 
    std::tm dt;
    dt.tm_mday = day;
    dt.tm_mon  = month - 1;
    dt.tm_year = year + 2000 - 1900;
    dt.tm_hour = hour;
    dt.tm_min  = minute;
    dt.tm_sec  = second;
 
    std::time_t t = mktime(&dt); // Это "локальное время"
 
    std::tm dt1 = *std::localtime(&t); // это локальное время в tm
    std::tm dt2 = *std::gmtime(&t);    // это UTC в tm
 
    std::time_t loct = mktime(&dt1);
 
    // Текущий часовой пояс
    std::cout << t << " " << (t - loct) / 60 / 60 << std::endl;
 
    // это уже смещенное время в UTC
    t = mktime(&dt2);
    std::cout << t << " " << (t - loct) / 60 / 60 << std::endl;
 
    result = std::to_string(t);
    return result;
}
Цитата Сообщение от pav1uxa Посмотреть сообщение
У меня OS Windows 7: error: 'timegm' was not declared in this scope
Правильно, потому что ОС надо сразу указывать в вопросе
А если серьезно, то функция POSIX, естественно ее нет в вин. В вин, наверняка что-то из win api придется дергать.

Добавлено через 10 минут
pav1uxa, можно еще вычислить разницу (заранее один раз) и корректировать затем время самостоятельно.
C++
1
2
    std::time_t cur  = std::time(nullptr);
    std::time_t diff = std::difftime(std::mktime(std::gmtime(&cur)), cur);
Добавлено через 48 секунд
Кстати, ты ведь знаешь, что функции типа localtime, gmtime не потокобезопасны?

Добавлено через 3 минуты
Вот, кстати, рабочий пример с timegm в *nix окружении.
http://rextester.com/ZXJZS49318
Чтобы тебе не думалось, что я тебя обманывал
2
1932 / 1761 / 822
Регистрация: 23.01.2014
Сообщений: 6,205
29.09.2015, 20:48  [ТС] 5
Цитата Сообщение от DrOffset Посмотреть сообщение
Вот, кстати, рабочий пример с timegm в *nix окружении.
http://rextester.com/ZXJZS49318
Чтобы тебе не думалось, что я тебя обманывал
даже не думал так думать) да я и сам находил эту функцию, очень много гуглил прежде чем создать тему.
Цитата Сообщение от DrOffset Посмотреть сообщение
Кстати, ты ведь знаешь, что функции типа localtime, gmtime не потокобезопасны?
нет, я в чистом c/c++ вообще мало чего знаю (оказывается). мне вообще не нравится sscanf и конструкция вида
C++
1
2
3
4
5
6
dt.tm_mday = day;
dt.tm_mon = month - 1;
dt.tm_year = year + 2000 - 1900;
dt.tm_hour = hour;
dt.tm_min = minute;
dt.tm_sec = second;
может это проще делается (стандартными библиотеками), или так сойдет?

Цитата Сообщение от DrOffset Посмотреть сообщение
Т.е. как-то так:
Этот код все равно не дает мне желаемого результата. Мне нужно вводить время в UTC (неважно в каком я часовом поясе, всегда считаем что время вводится в UTC) и получать метку timestamp. Для времени 25.09.15 08:40:00 UTC метка должна быть 1443170400. Все это вообще никак не должно быть привязано ни к каким поясам. В каком бы часовом поясе я не ввел бы 25.09.15 08:40:00, результат всегда должен быть одинм - 1443170400.

В этом примере в моем часовом поясе dt1 отличается от нужного результата на 3, а dt2 уходит еще дальше и отличается на 6.

Добавлено через 10 минут
Цитата Сообщение от DrOffset Посмотреть сообщение
std::time_t cur *= std::time(nullptr);
std::time_t diff = std::difftime(std::mktime(std::gmtime(&cur)), cur);
В принципе похоже на правду, если еще поменять местами аргументы у difftime показывает нормальный результат
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
std::string dateStr2str(std::string input)
{
    std::time_t cur  = std::time(nullptr);
    std::time_t diff = std::difftime(cur, std::mktime(std::gmtime(&cur)));
 
    std::string result = "";
    int day, month, year, hour, minute, second;
 
    std::sscanf(input.c_str(), "%d.%d.%d %d:%d:%d", &day, &month, &year, &hour, &minute, &second);
 
    std::tm dt;
    dt.tm_mday = day;
    dt.tm_mon  = month - 1;
    dt.tm_year = year + 2000 - 1900;
    dt.tm_hour = hour;
    dt.tm_min  = minute;
    dt.tm_sec  = second;
 
    std::time_t t = mktime(&dt);
    t += diff;
 
    result = std::to_string(t);
    return result;
}
Все же хотелось бы привести код к более аккуратному виду. Или сойдет?
0
13883 / 7419 / 1759
Регистрация: 30.01.2014
Сообщений: 12,412
30.09.2015, 13:47 6
Цитата Сообщение от pav1uxa Посмотреть сообщение
Все же хотелось бы привести код к более аккуратному виду. Или сойдет?
По причинам, которые мне сейчас неочевидны, а времени разбираться особо нет, этот код не работает правильно в онлайн компиляторе. Поэтому я условно считаю, что этот вариант некорректный.

Вообще, послушай меня. Последние лет 5 я все больше склоняюсь к мысли, что в определенных ситуациях лучше написать хороший платформозависимый код, чем плохой универсальный.
Поэтому хочу предложить тебе вот такое решение:
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <iostream>
#include <ctime>
#include <cstdio>
 
#ifdef _WIN32
#include <windows.h>
 
bool UTCToUnixTimeWin32(SYSTEMTIME const * stime, std::time_t * t)
{
    static SYSTEMTIME const t1970 = {
        1970, 1, 0, 1, 0, 0, 0, 0
    };
 
    FILETIME ftc, fts;
    if(::SystemTimeToFileTime(stime, &ftc)
    && ::SystemTimeToFileTime(&t1970, &fts))
    {
        ULARGE_INTEGER ltc = { { ftc.dwLowDateTime, ftc.dwHighDateTime } };
        ULARGE_INTEGER lts = { { fts.dwLowDateTime, fts.dwHighDateTime } };
        if(ltc.QuadPart >= lts.QuadPart)
        {
            *t = std::time_t( (ltc.QuadPart - lts.QuadPart) / 10000000 );
            return true;
        }
    }
    return false;
}
#endif
 
std::time_t UTCToUnixTime(std::string const & x)
{
    std::time_t tret = -1;
 
    int day,  month,  year;
    int hour, minute, second;
    if(std::sscanf(x.c_str(), "%d.%d.%d %d:%d:%d"
                   , &day, &month, &year
                   , &hour, &minute, &second) == 6)
    {
#ifdef _WIN32
        SYSTEMTIME const stime = {
            year / 100 == 0 ? 2000 + year : year, month, 0, day
          , hour, minute, second, 0
        };
        UTCToUnixTimeWin32(&stime, &tret);
#else
        std::tm dt = {};
        dt.tm_year = (year / 100 == 0 ? 2000 + year : year) - 1900;
        dt.tm_mon  = month - 1;
        dt.tm_mday = day;
        dt.tm_hour = hour;
        dt.tm_min  = minute;
        dt.tm_sec  = second;
 
        tret = ::timegm(&dt);
#endif
    }
    return tret;
}
 
int main()
{
    std::cout << UTCToUnixTime("25.09.15 08:40:00");
}

Запуск на win: http://rextester.com/KCW22877
Запуск на *nix: http://rextester.com/LBFF22059

On scanf в C++11 можно избавиться, там есть вот это: http://en.cppreference.com/w/cpp/io/manip/get_time
Но эта штука еще не везде работает, а там, где работает - работает по-разному, я проверил. Поэтому в примере ее нет.
Кроме того, в POSIX есть вот такая функция - strptime, с помощью которой всю твою задачу можно уложить в две строки.
Кликните здесь для просмотра всего текста
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
#include <ctime>
 
std::time_t GetTimeInUTC(std::string const & x)
{
    std::tm tm = {};
    ::strptime(x.c_str(), "%d.%m.%y %H:%M:%S", &tm);
    return ::timegm(&tm);    
}
 
int main()
{
    std::cout << GetTimeInUTC("25.09.15 08:40:00");
}

http://rextester.com/COEDK80206
Но на винде работать не будет.
0
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.09.2015, 13:47

Заказываю контрольные, курсовые, дипломные и любые другие студенческие работы здесь.

Не могу разобраться с заданием "Создайте класс Time с конструкторами Time(), Time( int hour)......"
/* Создайте класс Time с конструкторами Time(), Time( int hour), Time(int hour, int min),...

Unix timestamp adding two days to current day
как сделать проверку на то, когда был последний пост, загружено фото если ты получаешь ответ от в...

Перевести дату из Unix timestamp в привычный вид
как можно получить нормальную дату из Unix timestamp?

Как узнать время начала суток (unix timestamp)?
Есть переменная, которая содержит число (количество дней). Требуется узнать время начала суток, в...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2021, vBulletin Solutions, Inc.