【问题标题】:Why is mktime() changing the year day of my tm struct?为什么 mktime() 改变了我的 tm 结构的年份?
【发布时间】:2012-03-05 22:38:09
【问题描述】:

我在两个字符串中读取年份、儒略日(年日)、小时、分钟和观测值。

我使用 sscanf 提取相关变量:

sscanf(tide_str1.c_str(), "%d %d %d %d %Lf", &y1, &j1, &h1, &m1, &obs1);
sscanf(tide_str2.c_str(), "%d %d %d %d %Lf", &y2, &j2, &h2, &m2, &obs2);

对于这个特定的数据集,值为 2011 083 23 22 1.1

然后我创建并填充一个 tm 结构,并运行 mktime,在其间的那一天使用 cout 调用,它从 083 变为 364。

int y1=2011, j1=83, h1=23, m1=22;
struct tm time_struct = {0, 0, 0, 0, 0, 0, 0, 0, 0}, *time_ptr = &time_struct;
time_t tv_min;
time_struct.tm_year = y1 - 1900;
time_struct.tm_yday = j1;
cout << time_struct.tm_yday << endl;
time_struct.tm_hour = h1;
time_struct.tm_min = m1;
time_struct.tm_isdst = -1;
cout << time_struct.tm_yday << endl;
tv_min = mktime(time_ptr);
cout << time_struct.tm_yday << endl;

这是为什么呢?是因为 tm_mday 和 tm_mon 设置为 0 吗?我最初尝试不将其全部初始化为零,但随后 mktime 返回 -1。如果我只知道年日而不知道月日,我应该怎么做?

【问题讨论】:

  • 一年中的某一天有时被错误地称为“儒略日”。事实上,Julian Day 数字是自公元前 4713 年 1 月 1 日以来的天数;它用于天文学。
  • 是的,但它在某些专业中被广泛使用(不正确),以至于在实践中是正确的。只要一个领域内的每个人都使用相同的行话……交流就会发生。

标签: c++ mktime


【解决方案1】:

mktime() 正在做它应该做的事情。

引用 C 标准:

mktime函数将分解的时间进行转换,表示为 本地时间,在 timeptr 指向的结构中放入日历 与返回的值具有相同编码的时间值 时间函数。 tm_wday 的原始值和 结构体的tm_yday组件被忽略,其他组件的原始值不限于范围 如上所示。成功完成后, 结构的tm_wdaytm_yday组件设置适当,其他组件设置为代表 指定的日历时间,但其值强制为范围 如上所示; tm_mday 的最终值直到 tm_mon 才设置 和 tm_year 已确定。

mktime() 可以计算来自其他成员的tm_mdaytm_yday 的值;它并非旨在计算来自这些字段的其他成员的值。

不过,您可以做的是使用超出范围的值初始化 struct tm。例如,如果您希望 tm_yday 为 200(一年中的第 200 天),您可以初始化一个 struct tm 代表一月的第 200 天。然后mktime() 会将其规范化为正确的日期,产生一个time_t 值,然后您可以将其提供给gmtime()localtime()

这是一个简单的例子:

#include <iostream>
#include <ctime>

int main()
{
    struct tm t = { 0 };
    t.tm_sec = t.tm_min = t.tm_hour = 0; // midnight
    t.tm_mon = 0;                        // January
    t.tm_year = 2012 - 1900;
    t.tm_isdst = -1;                     // unknown

    t.tm_mday = 200;                     // January 200th?

    time_t when = mktime(&t);
    const struct tm *norm = localtime(&when);   // Normalized time

    std::cout << "month=" << norm->tm_mon << ", day=" << norm->tm_mday << "\n";
    std::cout << "The 200th day of 2012 starts " << asctime(norm);
}

输出是:

month=6, day=18
The 200th day of 2012 starts Wed Jul 18 00:00:00 2012

【讨论】:

  • 我尝试了您的建议并像这样初始化: struct tm time_struct = {0, 0, 0, 200, 200, 0, 200, 0, 0} 并且当我调用它时的结果是一天77 应该是 83,这比之前的 364 更接近,但仍然关闭。
  • 标准不保证struct tm成员的顺序,所以这样初始化不一定有效。您应该按名称初始化或分配所有成员。但是,如果它们以通常的顺序声明,则将 tm_mdaytm_mon 初始化为 200。我认为您不想要一年中的第 200 个月,或者更确切地说是第 201 个月。 (别忘了struct tm 将月份编号为 0 到 11,而不是 1 到 12。)
  • 要清楚,如果我想要年 83,我应该将月份设置为 0,将月份设置为 83?
  • @RuQu:是的。第 0 个月是 1 月,因此将 tm_mon 设置为 0 并将 tm_mday 设置为 83 指定 1 月 83 日,然后在闰年将其标准化为 3 月 24 日,否则为 3 月 25 日。
  • 是的,这行得通,从使用 0 而不是 1 开始明显偏移了 1 天。谢谢。这里有点新……我如何投票赞成你的答案,因为它在 cmets 中?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 2016-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多