Rick York Ответов: 1

Проблема с локальным временем


Может ли кто-нибудь объяснить мне, что происходит с местным временем? Я знаю, что он использует статическую структуру tm, на которую он возвращает указатель. Здесь происходит то, что я передаю ему два разных значения, и он дает одинаковые результаты с обоими.

Я приложил код, который использую для проверки этого. Если вы замените трассировку printf, то получите консольный вывод. Вот результат, который я вижу из него:
16:11:37.571  PrimaryThread   time 1 data :
16:11:37.575  PrimaryThread   now is 1553123249
16:11:37.578  PrimaryThread   year  = 19
16:11:37.582  PrimaryThread   month =  2
16:11:37.585  PrimaryThread   day   = 30
16:11:37.588  PrimaryThread   hour  = 16
16:11:37.591  PrimaryThread   min   = 11
16:11:37.595  PrimaryThread   sec   = 37
16:11:37.598  PrimaryThread   time 2 data :
16:11:37.601  PrimaryThread   now is 1553987249
16:11:37.604  PrimaryThread   year  = 19
16:11:37.607  PrimaryThread   month =  2
16:11:37.610  PrimaryThread   day   = 30
16:11:37.613  PrimaryThread   hour  = 16
16:11:37.618  PrimaryThread   min   = 11
16:11:37.621  PrimaryThread   sec   = 37
16:11:37.624  PrimaryThread   difference in times is 864000 seconds
Как вы можете видеть из этого, время прохождения значения отличается, и оно отличается на эквивалент десяти дней, но значения из localtime одинаковы. Вот это меня и озадачивает. Я был бы готов использовать другую функцию, если бы она была доступна.

-edit - я нашел другую функцию. Это localtime_s, и он принимает структуру tm в качестве аргумента. Когда я перешел на эту функцию, этот тест работает правильно. Кстати, это касается vs2017 и windows 10.

Что я уже пробовал:

void TraceTime( time_t tv )
{
    struct tm *	ptm = localtime( &tv );

    trace( _T( "now is %I64d\n" ), tv );
    trace( _T( "year  = %2d\n" ), ptm->tm_year - 100 );
    trace( _T( "month = %2d\n" ), ptm->tm_mon );
    trace( _T( "day   = %2d\n" ), ptm->tm_mday );
    trace( _T( "hour  = %2d\n" ), ptm->tm_hour );
    trace( _T( "min   = %2d\n" ), ptm->tm_min );
    trace( _T( "sec   = %2d\n" ), ptm->tm_sec );
    trace( _T( "value = %d\n" ), value );
}


void DoLocaltimeTest()
{
    time_t now2 = 1553987249;
    time_t now1 = 1553123249;

    trace( _T( "time 1 data :\n" ) );
    TraceTime( now1 );

    trace( _T( "time 2 data :\n" ) );
    TraceTime( now2 );

    INT64 diff = now2 - now1;
    trace( _T( "difference in times is %I64d seconds\n" ), diff );
}

Richard MacCutchan

Странно, я только что запустил этот код, и результаты верны. Местное время отличается на 10 дней. Я не вижу никакого способа, чтобы использование не-threadsafe версии повлияло на вывод.

Rick York

Это действительно не имеет никакого смысла для меня. Я пошел по другой версии, и она работает правильно, так что я не хотел тратить на нее больше времени.

Stefan_Lang

Месяц 2, день 30? Я не знаю ни одного календаря, в котором была бы эта дата.
P.S.: может быть, вам стоит добавить 1 к tm_mon (он основан на 0). ;-)

Rick York

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

1 Ответов

Рейтинг:
2

CPallini

localtime это не потокобезопасно, поэтому вы можете столкнуться с проблемами, если вызываете его из разных потоков (является ли ваш инструмент трассировки многопоточным?)

На моем Linux-боксе код

#include <stdlib.h>
#include <stdio.h>
#include <time.h>


#define trace printf
#define _T(s) s

void TraceTime( time_t tv )
{
    struct tm * ptm = localtime( &tv );

    trace( _T( "now is %ld\n" ), tv );
    trace( _T( "year  = %2d\n" ), ptm->tm_year - 100 );
    trace( _T( "month = %2d\n" ), ptm->tm_mon );
    trace( _T( "day   = %2d\n" ), ptm->tm_mday );
    trace( _T( "hour  = %2d\n" ), ptm->tm_hour );
    trace( _T( "min   = %2d\n" ), ptm->tm_min );
    trace( _T( "sec   = %2d\n" ), ptm->tm_sec );
    //trace( _T( "value = %d\n" ), value );
}


void DoLocaltimeTest()
{
    time_t now2 = 1553987249;
    time_t now1 = 1553123249;

    trace( _T( "time 1 data :\n" ) );
    TraceTime( now1 );

    trace( _T( "time 2 data :\n" ) );
    TraceTime( now2 );

    long long diff = now2 - now1;
    trace( _T( "difference in times is %lld seconds\n" ), diff );
}

int main()
{
  DoLocaltimeTest();
  return 0;
}

вести себя корректно
time 1 data :
now is 1553123249
year  = 19
month =  2
day   = 21
hour  =  0
min   =  7
sec   = 29
time 2 data :
now is 1553987249
year  = 19
month =  2
day   = 31
hour  =  0
min   =  7
sec   = 29
difference in times is 864000 seconds


Rick York

Как и должно быть! Все это было в одном потоке на коробке windows. Я прочитал еще немного и нашел localtime_s, который берет указатель на структуру tm и ведет себя правильно.

Спасибо, что проверили!

CPallini

Это, конечно, решение, но вы не нашли корень проблемы. :-)
Добро пожаловать.

Stefan_Lang

31 февраля? Вы уверены, что он работает правильно? ;-p

CPallini

:большой палец вверх: хорошо! :-D

Rick York

Да, значения времени были установлены полуслучайно.

CPallini

Ну, вы можете выбрать значение time_t случайным образом, но местное время не дурак (на один поток код): 2-это Март нет Февраль У Стефана это была шутка.