UTC时间戳比较

时间:2016-04-06 07:42:15

标签: c++ linux timestamp utc localtime

我正在研究客户端 - 服务器自定义应用程序(在linux上运行),我发送的其中一个帧包括时间戳(即帧发送的时间)。

为了使我的应用程序可靠,我使用gmtime在客户端上生成时间。我在比利时,所以现在客户端虚拟机的小时比UTC时间晚2小时(因为夏令时)。

在服务器端,我首先将收到的字符串转换为time_t类型。我这样做是为了使用difftime函数来查看时间戳是否太旧。 然后,我使用gmtime再次生成时间戳(以UTC时间为单位),并将其转换为time_t

我比较两个time_t以查看时差。

我在服务器端转换时间时出现问题。 我使用与客户端相同的代码,但输出的gmtime不同......

客户端:函数生成时间戳,并将其导出为字符串(time_str):

    std::string getTime()
    {
    time_t rawtime;
    struct tm * timeinfo;
    char buffer[80];

    time (&rawtime);              // Get time of the system
    timeinfo = gmtime(&rawtime);  // Convert it to UTC time

    strftime(buffer,80,"%d-%m-%Y %H:%M:%S",timeinfo);
    std::string time_str(buffer); // Cast it into a string
    cout<<"Time Stamp now (client) : "<<time_str<<endl;

    return time_str;
    }

它产生了这个(当地时间9点33分):

  

时间戳现在:06-04-2016 07:33:30

服务器端:功能,以检索时间戳,生成newx时间戳并进行比较:

bool checkTimeStamp(std::string TimsStamp_str, double delay)
{
    cout<<"TimeStamp recieved: "<<TimsStamp_str<<endl;
    /* Construct tm from string */
    struct tm TimeStampRecu;
    strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu);
    time_t t_old = mktime(&TimeStampRecu);

    /* Generate New TimeStamp */
    time_t rawtime;
    struct tm * timeinfo;
    time (&rawtime);  // Get time of the system
    timeinfo = gmtime(&rawtime);  // convert it to UTC time_t
    time_t t2 = mktime(timeinfo);  // Re-Cast it to timt_t struct
    /* Convert it into string (for output) */
        char buffer[80];
        strftime(buffer,80,"%d-%m-%Y %H:%M:%S",timeinfo);
        std::string time_str(buffer); // Cast it into a string
        cout<<"Time Stamp now (server) : "<<time_str<<endl;

    /* Comparison */
    double diffSecs = difftime(t2, t_old);
    cout<<diffSecs<<endl;
    bool isTimeStampOK;
    if (diffSecs < delay)
        isTimeStampOK = true;
    else
        isTimeStampOK = false;

return isTimeStampOK;
}

它产生了这个(比利时9点33分):

  

TimeStamp收到:06-04-2016 07:33:30

     

现在时间戳(服务器):06-04-2016 08:33:31

为什么服务器时间(8h33)既不在本地时间(9h33),也不在UTC时间(7h33)?

我这一代人犯了错误吗?我不明白哪里,因为这些代码与客户端完全相同......

2 个答案:

答案 0 :(得分:4)

您的代码中有一些错误,有些是您的错,有些则不是。这里最大的问题是C <time.h> API非常糟糕,令人困惑,不完整且容易出错,因此这类错误几乎是强制性的。稍后会详细介绍。

第一个问题是这一行:

struct tm TimeStampRecu;

它会创建一个未初始化的tm,然后将其传递到strptimestrptime可能无法填写TimeStampRecu的所有字段。你应该像这样对TimeStampRecu进行零初始化:

struct tm TimeStampRecu{};

下一个问题:

strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu);

%I表示的12小时时间不明确,没有AM / PM说明符。我怀疑这只是一个类型o,因为它是你使用它的唯一地方。

下一个问题:

gmtime  time_t -> tm  UTC to UTC
mktime  tm -> time_t  local to UTC

也就是说,mtkime根据运行它的计算机的本地时间来解释输入tm。你需要的是:

timegm  tm -> time_t  UTC to UTC

不幸的是timegm不是标准C(或C ++)。幸运的是,它可能存在于您的系统中。

通过这些更改,我认为您的代码将按预期运行。

如果你使用的是C ++ 11,那么这里有一个更安全的日期/时间库(免费/开源):

https://github.com/HowardHinnant/date

以下代码已翻译为使用此更高级别的库:

std::string getTime()
{
    using namespace std::chrono;
    auto rawtime = time_point_cast<seconds>(system_clock::now());
    auto time_str = date::format("%d-%m-%Y %H:%M:%S", rawTime);
    std::cout<<"Time Stamp now (client) : "<<time_str<< '\n';

    return time_str;
}

bool checkTimeStamp(std::string TimsStamp_str, std::chrono::seconds delay)
{
    using namespace std::chrono;
    std::cout<<"TimeStamp recieved:       "<<TimsStamp_str<< '\n';
    /* Construct tm from string */
    std::istringstream in{TimsStamp_str};
    time_point<system_clock, seconds> t_old;
    date::parse(in, "%d-%m-%Y %H:%M:%S", t_old);

    /* Generate New TimeStamp */
    auto rawtime = time_point_cast<seconds>(system_clock::now());
    auto time_str = date::format("%d-%m-%Y %H:%M:%S", rawTime);
    in.str(time_str);
    time_point<system_clock, seconds> t2;
    date::parse(in, "%d-%m-%Y %H:%M:%S", t2);
    cout<<"Time Stamp now (server) : "<<time_str<<endl;

    /* Comparison */
    auto diffSecs = t2 - t_old;
    cout<<diffSecs.count()<<endl;
    bool isTimeStampOK;
    if (diffSecs < delay)
        isTimeStampOK = true;
    else
        isTimeStampOK = false;

    return isTimeStampOK;
}

答案 1 :(得分:1)

时间戳是绝对值。它不依赖于时区或夏令时。它表示自过去固定时刻以来的秒数。无论服务器的时区是什么,time()返回的值都是相同的。

您的代码不会生成时间戳,但会为人类消费格式化日期。

我建议您在内部使用时间戳,并将其格式化为仅在UI中可供人阅读的日期。但是,如果您需要在应用程序的各个组件之间将日期作为字符串传递,请将时区放在其中。

我会像这样编写代码(仅使用时间戳):

// The client side
time_t getTime()
{
    return time(NULL);
}


// The server side
bool checkTimeStamp(time_t clientTime, double delay)
{
    time_t now = time(NULL);

    return difftime(now, clientTime) < delay;
}

<强>更新

如果必须使用字符串在客户端和服务器之间进行通信,那么您所要做的就是更新用于将时间戳格式化为日期(在客户端上)的格式字符串,并将日期解析回时间戳(在服务器上) ),包括用于格式化日期的时区。

这意味着将%Z添加到代码中的所有格式中。使用"%d-%m-%Y %H:%M:%S %Z"。顺便说一句,您发布的代码现在在"%d-%m-%Y %I:%M:%S"的调用中显示strptime(),这将在下午给您带来另一个问题。

<强>备注

我总是使用"%Y-%m-%d %H:%M:%S %Z"因为它是明确的,并且与语言环境无关。 06-04-2016可以解释为April 6June 4,具体取决于读者的母语。