C:如何打印特定时区中的特定“时间”值(按偏移量)?
我正在用 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
我需要更改 < code>TZ 环境变量(也许调用 tzset
)?似乎应该有一种方法来操作数据结构并获得正确的结果,但上述方法肯定行不通(无论如何,在 MacOS X 10.6 上 - 在 Linux 上效果很好)。
作为解决方法,我想我可以从格式字符串中删除 %z 并自己创建该部分。
不过,理想情况下,我希望对我的 struct tm 进行修改,或者我可以使用其他一些函数调用(例如 strftime,但带有额外的参数或其他参数,或者可能是替代函数)相反,本地时间的形式),这将使事情做正确的事情。
由于Linux似乎表现良好(尽管即使在那里,上述解决方案也不是很理想,因为我捏造了我的time_t
值;我更喜欢有一个参数来改变struct tm
是计算出来的),这是我应该报告为针对 MacOS 的错误吗?
或者,是否有我可以调用的一组不同的库例程,即使最终需要第三方(我想象来自 GNU 人员的东西)库?我更愿意保留 C,但我会考虑 ObjC 或 C++ 选项。
I'm writing an application in C that parses data files recorded by an external program (over which I have no control). It's storing binary data, one field of which is a time in standard UNIX "epoch" format (seconds since January 1st, 1970, UTC).
Another field is the timezone, stored as an offset in seconds from UTC.
Cool, I've got everything I need to make a date/time string representing that information in the timezone it was recorded in, right? Well... it doesn't seem so, and/or I'm not sure how to do it.
I've boiled things down to a fairly simple test case:
#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;
}
When I run this on MacOS X 10.6, I get:
before: 2011-02-23T00:53:04-0800
after: 2011-02-23T10:16:04-0800
What I would expect (and in fact get, on a Linux box) would be:
before: 2011-02-23T00:53:04-0800
after: 2011-02-23T10:16:04+0123
Do I need to change the TZ
environment variable (and maybe call tzset
)? It seems like there ought to be a way to manipulate the data structures and get the right thing, but the above certainly isn't working (on MacOS X 10.6, anyway -- works great on Linux).
As a workaround, I suppose I can drop the %z from my format string and create that part myself.
Ideally, though, I'd like to have either a modification of my struct tm
, or some other function call that I can use (like strftime, but with an extra parameter or something, or perhaps an alternate form of localtime, instead), that would make things do the right thing.
Since Linux seems to behave (though even there, the above solution isn't quite ideal, because I'm fudging my time_t
value; I'd prefer to have a parameter that changes how the struct tm
is calculated), is this something that I should report as a bug against MacOS?
Alternately, is there a different set of library routines I could call, even if that ends up requiring a third-party (something from the GNU folks, I'm imagining) library? I'd prefer to keep to C, though I'd consider ObjC or C++ options.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我更喜欢使用
mktime()
而不是修改time_t
值。但是,这会应用TZ
偏移量(就像localtime()
解决方案一样),因此需要mkgmtime()
实现。I prefer to use
mktime()
instead of modifying thetime_t
value. However, this applies theTZ
offset (just like thelocaltime()
solution), so amkgmtime()
implementation is required.我认为最好的方法是
将您的值读取到
time_t
变量中;按照这些指南设置 TZ 环境变量。另请参阅此页面,了解有关如何指定 TZ 的信息;
调用
localtime()
。尽管我无法在 MacOS 平台上测试它,但应该保证它可以工作。
I think that the best approach would be
read your value into a
time_t
variable;set the TZ environment variable following these guidelines. See also this page for info on how you should specify TZ;
invoke
localtime()
.This should be guaranteed to work, althought I can't test it on a MacOS platform.
我个人喜欢在 bash 代码中嵌入小的 python 脚本。 Python 拥有许多强大的开箱即用库,可满足您所需的功能。
您可以将 python 代码嵌入到 bash 脚本中,如下所示(假设已安装 python)
您可以根据需要在不同时区中显示来更改时区设置。请查看 http://pytz.sourceforge.net/ 了解更多详细信息。
I personally like to embed small python scripts in my bash code. Python has many powerful out-of-the-box libraries for functionalities like you require.
You can embed python code in a bash script as follows (Assuming python is installed)
You can change the timezone setting as you wish to display in different timezones. Have a look at http://pytz.sourceforge.net/ for more details.