我正在用C语言编写一个解析由外部程序记录的数据文件的应用程序(我无法控制)。它存储二进制数据,其中一个字段是标准UNIX“纪元”格式的时间(1970年1月1日以来的秒数,UTC)。
另一个字段是时区,存储为UTC的秒数偏移量。
很酷,我已经拥有了制作日期/时间字符串所需的一切,该字符串表示记录在时区的信息,对吗?嗯......它似乎不是这样,和/或我不知道该怎么做。
我把事情简化为一个相当简单的测试用例:
#include <stdio.h>
#include <time.h>
int main(void)
{
time_t t;
struct tm *tm;
char buf[BUFSIZ];
int offset = 4980; /* slightly bizarre, just to test this - an hour
* and 23 minutes ahead of UTC */
t = time(NULL);
tm = localtime(&t);
strftime(buf, BUFSIZ, "%FT%T%z", tm);
printf("before: %s\n", buf);
/* since we're not telling localtime anything different,
* compensate here (by subtracting applied offset, and adding
* desired one): */
t += offset - tm->tm_gmtoff;
tm = localtime(&t);
tm->tm_zone = "XYZ"; // not used -- but it was in an earlier version
tm->tm_gmtoff = offset;
// on macos, I used to also have %+, which referenced tm_zone
strftime(buf, BUFSIZ, "%FT%T%z", tm);
printf("after: %s\n", buf);
return 0;
}
当我在MacOS X 10.6上运行时,我得到:
before: 2011-02-23T00:53:04-0800
after: 2011-02-23T10:16:04-0800
我期望的(事实上,在Linux机器上获得)将是:
before: 2011-02-23T00:53:04-0800
after: 2011-02-23T10:16:04+0123
我是否需要更改TZ
环境变量(也许可以调用tzset
)?似乎应该有一种方法来操纵数据结构并获得正确的东西,但上述肯定不起作用(无论如何,在MacOS X 10.6上 - 在Linux上运行良好)。
作为一种解决方法,我想我可以从格式字符串中删除%z并自己创建该部分。
理想情况下,我想要修改我的struct tm
或其他一些我可以使用的函数调用(比如strftime,但是有一个额外的参数或某些东西,或者可能是另一种形式相反,当地时间,这将使事情做正确的事。
由于Linux似乎表现得很好(尽管在那里,上面的解决方案并不是很理想,因为我正在捏造我的time_t
值;我更喜欢有一个参数来改变{{1}计算好的),这是我应该报告为MacOS的错误吗?
或者,是否有一组我可以调用的不同的库例程,即使最终需要第三方(来自GNU人员,我想象的)库?我宁愿保留C,但我会考虑ObjC或C ++选项。
答案 0 :(得分:2)
我更喜欢使用mktime()
而不是修改time_t
值。但是,这会应用TZ
偏移量(就像localtime()
解决方案一样),因此需要mkgmtime()
实现。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
static void set_timezone(char *tz)
{
static char var[1024];
snprintf(var, sizeof(var), "TZ=%s", tz);
putenv(var);
tzset();
}
static time_t mkgmtime(struct tm *tm)
{
char var[1024];
time_t t;
snprintf(var, sizeof(var), "%s", getenv("TZ") ? getenv("TZ") : "");
set_timezone("GMT0");
t = mktime(tm);
set_timezone(var);
return t;
}
int main(void)
{
time_t t;
struct tm tm;
char buf[BUFSIZ];
int offset = 4980; /* slightly bizarre, just to test this - an hour
* and 23 minutes ahead of UTC */
t = time(NULL);
tm = *localtime(&t);
strftime(buf, BUFSIZ, "%FT%T%z", &tm);
printf("before: %s\n", buf);
tm = *gmtime(&t);
tm.tm_sec += offset;
mkgmtime(&tm);
strftime(buf, BUFSIZ, "%FT%T%z", &tm);
printf("after: %s\n", buf);
return 0;
}
答案 1 :(得分:0)
我认为最好的方法是
答案 2 :(得分:-1)
我个人喜欢在我的bash代码中嵌入小python脚本。 Python有许多功能强大的开箱即用的库,可以满足您的需求。
你可以在bash脚本中嵌入python代码,如下所示(假设安装了python)
python << END
from pytz import timezone
south_africa = timezone('Africa/Johannesburg')
sa_time = datetime.now(south_africa)
print sa_time.strftime('%Y-%m-%d_%H-%M-%S')
END
您可以根据希望在不同时区显示的时区设置进行更改。有关详细信息,请查看http://pytz.sourceforge.net/。