【问题标题】:Converting a long value into a date?将长值转换为日期?
【发布时间】:2013-02-28 11:10:56
【问题描述】:

我有一个以长值存储的日期,即 20130228,我需要对其执行操作,例如添加 30 天或 50 天等。关于如何将其转换为更合适的日期有什么建议吗?

【问题讨论】:

  • 你有没有尝试过?你在唱什么操作系统? IDE?
  • 您是否尝试使用 32 位来存储日期?您将不得不使用位掩码和固定格式。此外,它不会节省时间(快速),但会节省空间。无论如何,您必须再澄清一下您的意图,我们不会为您发明这种格式。
  • 转换为time_t, ...en.cppreference.com/w/c/chrono
  • 我用的是win7和visual studio 2010

标签: c date time


【解决方案1】:

如果是这样存储的

unsigned long d = 20130228;

你必须先用简单的算术把它拆分成一个struct tm

struct tm tm;
tm.tm_year = d / 10000 - 1900;
tm.tm_mon = (d % 10000) / 100 - 1;
tm.tm_mday = d % 100;
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
tm.tm_isdst = -1;

然后您可以将一些值 30 添加到 tm.tm_mday。如果您使用mktime(),您将收到time_t 作为seconds since the epoch 并且tm 中的字段将被规范化

time_t t = mktime(&tm);

【讨论】:

  • 感谢 Olaf 的快速反馈。
【解决方案2】:

您可以提取年、月和日,然后根据每个月的天数和闰年添加您的天数。

#include <stdio.h>

unsigned long AddDays(unsigned long StartDay, unsigned long Days)
{
  unsigned long year = StartDay / 10000, month = StartDay / 100 % 100 - 1, day = StartDay % 100 - 1;

  while (Days)
  {
    unsigned daysInMonth[2][12] =
    {
      { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, // 365 days, non-leap
      { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }  // 366 days, leap
    };

    int leap = !(year % 4) && (year % 100 || !(year % 400));

    unsigned daysLeftInMonth = daysInMonth[leap][month] - day;

    if (Days >= daysLeftInMonth)
    {
      day = 0;
      Days -= daysLeftInMonth;
      if (++month >= 12)
      {
        month = 0;
        year++;
      }
    }
    else
    {
      day += Days;
      Days = 0;
    }
  }

  return year * 10000 + (month + 1) * 100 + day + 1;
}

int main(void)
{
  unsigned long testData[][2] =
  {
    { 20130228, 0 },
    { 20130228, 1 },
    { 20130228, 30 },
    { 20130228, 31 },
    { 20130228, 32 },
    { 20130228, 365 },
    { 20130228, 366 },
    { 20130228, 367 },
    { 20130228, 365*3 },
    { 20130228, 365*3+1 },
    { 20130228, 365*3+2 },
  };

  unsigned i;

  for (i = 0; i < sizeof(testData) / sizeof(testData[0]); i++)
    printf("%lu + %lu = %lu\n", testData[i][0], testData[i][1], AddDays(testData[i][0], testData[i][1]));

  return 0;
}

输出(ideone):

20130228 + 0 = 20130228
20130228 + 1 = 20130301
20130228 + 30 = 20130330
20130228 + 31 = 20130331
20130228 + 32 = 20130401
20130228 + 365 = 20140228
20130228 + 366 = 20140301
20130228 + 367 = 20140302
20130228 + 1095 = 20160228
20130228 + 1096 = 20160229
20130228 + 1097 = 20160301

另一种选择是提取年、月和日,并使用 mktime() 或类似函数将它们转换为自 epoch 以来的秒数,将代表那些天的秒数添加到该秒数给定日期,然后使用gmtime()localtime() 或类似函数将生成的秒数转换回日期,然后构造长整数值。我选择不使用这些功能来避免时区和夏令时之类的事情。我想要一个简单且包含的解决方案。

【讨论】:

  • 很高兴阅读您优雅而有效的代码,并且本身具有价值。谢谢你的时间。但我认为问题可能在于您没有提到标准库来操作日期。如果您认为并解释库在某种程度上是劣等的,或者您不只是为了展示替代方案而使用它,那将会非常有趣。
  • @qPCR4vir 我不希望有机会涉及时区和夏令时。我想要一个简单而包含的解决方案。就是这样。
  • 好的,这是一个很好的理由(有助于学习保持简单)。为什么不把它放在答案中?
  • @qPCR4vir 我已将其添加到答案中。
【解决方案3】:

通过将日期转换为“从 X 开始的时间单位”来对日期进行“数学运算”往往要容易得多 - 标准库中的 time_t 是“距 1970 年 1 月 1 日午夜的秒数”。因此,使用struct tm 中的mktime 将是一种解决方案。

如果由于某种原因您不想这样做,那么将您的日期转换为“自(例如)2000 年 1 月 1 日以来的天数”会起作用。在处理整年时,您必须考虑闰年(year % 4 == 0 &amp;&amp; (year % 100 != 0 || year %400 == 0) 应该涵盖这一点),当然在一年内您必须注意每月的天数。到日期的转换类似但相反。

【讨论】:

    猜你喜欢
    • 2015-11-03
    • 2013-09-19
    • 1970-01-01
    • 2013-02-27
    • 1970-01-01
    • 2014-03-28
    • 1970-01-01
    • 1970-01-01
    • 2014-12-31
    相关资源
    最近更新 更多