我正在尝试使用C ++在不同的时区(PST)获得时间。
#define PST (-8);
char* Time::getSecondSystemTime() {
time_t rawtime;
struct tm * timeinfo;
char buffer[80];
time(&rawtime);
timeinfo = gmtime(&rawtime);
timeinfo->tm_hour = timeinfo->tm_hour + PST;
strftime(buffer, 80, "%I:%M %p", timeinfo);
std::string temp = std::string(buffer); // to get rid of extra stuff
std::string extraInfo = " Pacific Time ( US & Canada )";
temp.append(extraInfo);
return (char*) (temp.c_str());
}
这里的问题是,当GMT时间少于8小时(例如,现在,早上3点的时间),从它减去8小时不起作用!
在Unix中获取不同时区的正确方法是什么?
答案 0 :(得分:6)
既然你说过“UNIX”,那就是使用TZ,但是,TZ=[what goes here]
你需要找出你系统上的[这里有什么]。它可能是“America / LosAngeles”或PST的其他几个字符串之一。
如果您的系统是POSIX:TZ = PST8PST保证可以正常工作。但它可能不是最佳的。
原始非生产代码假定TZ目前尚未使用。这是C,而不是C ++,因为你的标签是C:
setenv("TZ", "PST8PST", 1); // set TZ
tzset(); // recognize TZ
time_t lt=time(NULL); //epoch seconds
struct tm *p=localtime(<); // get local time struct tm
char tmp[80]={0x0};
strftime(tmp, 80, "%c", p); // format time use format string, %c
printf("time and date PST: %s\n", tmp); // display time and date
// you may or may not want to remove the TZ variable at this point.
答案 1 :(得分:4)
我有以下C代码藏起来处理问题。效率不是第一个浮现在脑海中的词(两次调用setenv()
,两次调用tzset()
),但标准C库并不容易做得更好:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
static void time_convert(time_t t0, char const *tz_value)
{
char old_tz[64];
strcpy(old_tz, getenv("TZ"));
setenv("TZ", tz_value, 1);
tzset();
char new_tz[64];
strcpy(new_tz, getenv("TZ"));
char buffer[64];
struct tm *lt = localtime(&t0);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", lt);
setenv("TZ", old_tz, 1);
tzset();
printf("%ld = %s (TZ=%s)\n", (long)t0, buffer, new_tz);
}
int main(void)
{
time_t t0 = time(0);
char *tz = getenv("TZ");
time_convert(t0, tz);
time_convert(t0, "UTC0");
time_convert(t0, "IST-5:30");
time_convert(t0, "EST5");
time_convert(t0, "EST5EDT");
time_convert(t0, "PST8");
time_convert(t0, "PST8PDT");
}
在原始代码中,您必须担心在更改小时偏移后规范化时间结构。您可以使用mktime()
功能执行此操作。这是一个基于问题中的函数的程序,它是纯C并且避免了返回指向局部变量的指针的问题(以及用分号结尾的#define
):
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#define PST (-8)
extern int getSecondSystemTime(char *buffer, size_t buflen);
int getSecondSystemTime(char *buffer, size_t buflen)
{
time_t rawtime = time(0);;
struct tm *timeinfo;
char t_buff[32];
timeinfo = gmtime(&rawtime);
timeinfo->tm_hour = timeinfo->tm_hour + PST;
time_t pst_time = mktime(timeinfo);
assert(pst_time != (time_t)-1);
int len = strftime(t_buff, sizeof(t_buff), "%Y-%m-%d %H:%M:%S", timeinfo);
assert(len != 0);
int rv = snprintf(buffer, buflen, "%ld = %s (%s)", (long)rawtime, t_buff,
"Pacific Time (US & Canada)");
assert(rv > 0);
return rv;
}
int main(void)
{
char buffer[128];
getSecondSystemTime(buffer, sizeof(buffer));
printf("%s\n", buffer);
return(0);
}
显然,更好的接口会将UTC时间值和时区偏移量(以小时和分钟为单位)作为参数传递。尽管我的计算机默认运行在美国/太平洋(或美国/洛杉矶)时区,但我测试TZ设置为各种值(包括US / Eastern,IST-05:30)并获得正确的值;根据过去的经验,我有理由相信计算是正确的。
我有另一个程序尝试剖析-1
从mktime()
返回的是{0}}是由于错误还是因为转换后的时间对应(time_t)-1
:
/* Attempt to determine whether time is really 1969-12-31 23:59:59 +00:00 */
static int unix_epoch_minus_one(const struct tm *lt)
{
printf("tm_sec = %d\n", lt->tm_sec);
if (lt->tm_sec != 59)
return(0);
printf("tm_min = %d\n", lt->tm_min);
/* Accounts for time zones such as Newfoundland (-04:30), India (+05:30) and Nepal (+05:45) */
if (lt->tm_min % 15 != 14)
return(0);
/* Years minus 1900 */
printf("tm_year = %d\n", lt->tm_year);
if (lt->tm_year != 69 && lt->tm_year != 70)
return(0);
printf("tm_mday = %d\n", lt->tm_mday);
if (lt->tm_mday != 31 && lt->tm_mday != 1)
return(0);
/* Months 0..11 */
printf("tm_mon = %d\n", lt->tm_mon);
if (lt->tm_mon != 11 && lt->tm_mon != 0)
return(0);
/* Pretend it is valid after all - though there is a small chance we are incorrect */
return 1;
}
答案 2 :(得分:2)
这是一种更简洁的方法(此示例获取GMT时间,包括DST偏差):
struct STimeZoneFromRegistry
{
long Bias;
long StandardBias;
long DaylightBias;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
};
static SYSTEMTIME GmtNow()
{
FILETIME UTC;
GetSystemTimeAsFileTime(&UTC);
SYSTEMTIME GMT;
TIME_ZONE_INFORMATION tz = {0};
STimeZoneFromRegistry binary_data;
DWORD size = sizeof(binary_data);
HKEY hk = NULL;
TCHAR zone_key[] = _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Time Zones\\GMT Standard Time");
if ((RegOpenKeyEx(HKEY_LOCAL_MACHINE, zone_key, 0, KEY_QUERY_VALUE, &hk) == ERROR_SUCCESS) &&
(RegQueryValueEx(hk, "TZI", NULL, NULL, (BYTE *) &binary_data, &size) == ERROR_SUCCESS))
{
tz.Bias = binary_data.Bias;
tz.DaylightBias = binary_data.DaylightBias;
tz.DaylightDate = binary_data.DaylightDate;
tz.StandardBias = binary_data.StandardBias;
tz.StandardDate = binary_data.StandardDate;
}
SystemTimeToTzSpecificLocalTime(&tz, &UTC, &GMT);
return GMT;
}