UTC 时间戳比较
UTC Timestamp comparison
我正在开发客户端-服务器自定义应用程序(在 linux 上 运行),我发送的其中一个帧包含时间戳(即帧的时间正在发送)。
为了使我的应用程序可靠,我使用 gmtime
在客户端上生成时间。我在比利时,所以现在客户端 VM 的时间比 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 分):
Time Stamp now : 06-04-2016 07:33:30
服务器端: 检索时间戳的功能,生成新的时间戳,并比较它们:
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 recieved : 06-04-2016 07:33:30
Time Stamp now (server) : 06-04-2016 08:33:31
为什么服务器时间 (8h33) 既不是本地时间 (9h33) 也不是 UTC 时间 (7h33)?
我是不是弄错了?我不明白在哪里,因为这些是与客户端完全相同的代码...
时间戳是一个绝对值。它不依赖于时区或 DST。它表示自过去某个固定时刻以来的秒数。 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"
。顺便说一句,您发布的代码现在在对 strptime()
的调用中读取 "%d-%m-%Y %I:%M:%S"
,这将在下午给您带来另一个问题。
备注
我总是使用 "%Y-%m-%d %H:%M:%S %Z"
,因为它明确且与区域设置无关。 06-04-2016
可以解释为 April 6
或 June 4
,具体取决于 reader.
的母语
你的代码中有几个错误,有些是你的错,有些不是。这里最大的问题是 C <time.h>
API 非常糟糕、令人困惑、不完整且容易出错,以至于像这样的错误几乎是强制性的。稍后会详细介绍。
第一个问题是这一行:
struct tm TimeStampRecu;
它创建一个未初始化的 tm
,然后将其传递给 strptime
。 strptime
可能无法填写 TimeStampRecu
的所有字段。您应该像这样对 TimeStampRecu
进行零初始化:
struct tm TimeStampRecu{};
下一题:
strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu);
如果没有 AM/PM 说明符,%I
表示的 12 小时时间是不明确的。我怀疑这只是一个 type-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,可以在此处使用更安全的 date/time 库 (free/open-source):
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;
}
我正在开发客户端-服务器自定义应用程序(在 linux 上 运行),我发送的其中一个帧包含时间戳(即帧的时间正在发送)。
为了使我的应用程序可靠,我使用 gmtime
在客户端上生成时间。我在比利时,所以现在客户端 VM 的时间比 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 分):
Time Stamp now : 06-04-2016 07:33:30
服务器端: 检索时间戳的功能,生成新的时间戳,并比较它们:
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 recieved : 06-04-2016 07:33:30
Time Stamp now (server) : 06-04-2016 08:33:31
为什么服务器时间 (8h33) 既不是本地时间 (9h33) 也不是 UTC 时间 (7h33)?
我是不是弄错了?我不明白在哪里,因为这些是与客户端完全相同的代码...
时间戳是一个绝对值。它不依赖于时区或 DST。它表示自过去某个固定时刻以来的秒数。 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"
。顺便说一句,您发布的代码现在在对 strptime()
的调用中读取 "%d-%m-%Y %I:%M:%S"
,这将在下午给您带来另一个问题。
备注
我总是使用 "%Y-%m-%d %H:%M:%S %Z"
,因为它明确且与区域设置无关。 06-04-2016
可以解释为 April 6
或 June 4
,具体取决于 reader.
你的代码中有几个错误,有些是你的错,有些不是。这里最大的问题是 C <time.h>
API 非常糟糕、令人困惑、不完整且容易出错,以至于像这样的错误几乎是强制性的。稍后会详细介绍。
第一个问题是这一行:
struct tm TimeStampRecu;
它创建一个未初始化的 tm
,然后将其传递给 strptime
。 strptime
可能无法填写 TimeStampRecu
的所有字段。您应该像这样对 TimeStampRecu
进行零初始化:
struct tm TimeStampRecu{};
下一题:
strptime(TimsStamp_str.c_str(), "%d-%m-%Y %I:%M:%S", &TimeStampRecu);
如果没有 AM/PM 说明符,%I
表示的 12 小时时间是不明确的。我怀疑这只是一个 type-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,可以在此处使用更安全的 date/time 库 (free/open-source):
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;
}