C ++从tm_yday和tm_year值计算日期

时间:2015-02-02 21:05:03

标签: c++

我们要求从tm_yday派生日期;一年中的一天(从1月1日起)和tm_year;自1900年以来的几年。

任何人都可以提供帮助。

我已经尝试但没有运气感谢你的帮助任何方向也会有所帮助。

例如输入300 1900的值应该是10/27/1900,其中300是一年中的一天和1900年。

提前致谢!

2 个答案:

答案 0 :(得分:0)

你需要实际执行此操作,不要涉及ctimemktime的变幻莫测,这在这种情况下是不合适的,因为tm_yday的值是< em> not 用于构建时间(根据其他字段的值设置tm_wdaytm_yday,并根据需要调整它们。

为此,我们可以简单地使用以下代码作为起点。它实际上使用的数组包含每个月的天数,当然是将2月调整为闰年。

然后通过从一年中提供的日期连续减去每个月的天数,直到它比当月的天数少,就可以计算出您所在的月份。

在该过程结束时,月份和日期已知,我们只需输出值:

#include <iostream>
#include <cstdlib>

// Function to detect leap year.

bool isLeapYear(int year) {
    if (year % 400 == 0) return true;
    if (year % 100 == 0) return false;
    if (year % 4 == 0) return true;
    return false;
}

// Helper function for parameter checks.

int usageExit(const char *errMsg) {
    std::cerr << "*** " << errMsg << std::endl;
    std::cerr << "Usage: getdate <year> <day-of-year>" << std::endl;
    return 1;
}

int main(int argc, char *argv[]) {
    // Must provide two parameters.

    if (argc != 3) return usageExit("Incorrect parameter count");

    // Get (and check) year and day of year.

    char *firstBad;

    long year = std::strtol(argv[1], &firstBad, 10);
    if ((firstBad == argv[1]) || (*firstBad != '\0')) return usageExit("Year is not numeric");
    if (year < 0) return usageExit("Year is negative");
    bool leapYear = isLeapYear(year);

    long dayOfYear = std::strtol(argv[2], &firstBad, 10);
    if ((firstBad == argv[2]) || (*firstBad != '\0')) return usageExit("Day of year is not numeric");
    if ((dayOfYear < 1) || (dayOfYear > (leapYear ? 366 : 365))) return usageExit("Day of year is out of range");

    // Figure out month and day of month, from day of year.

    int daysInMonth[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    if (leapYear) daysInMonth[1]++;

    int month = 0;
    int daysLeft = dayOfYear;
    while (daysLeft > daysInMonth[month])
        daysLeft -= daysInMonth[month++];
    ++month;

    // Output results.

    std::cout << month << "/" << daysLeft << "/" << year << std::endl;
}

答案 1 :(得分:0)

这可以在没有迭代/分支算法的情况下完成,这将使其更有效。 algorithms are given hereHoward Hinnant's free, open-source C++11/14/17 date/time library。我们的想法是,您可以将三元组:{year, jan, 1}转换为连续天数,将该天数添加到该计数天数,然后将该总和转换回{year, month, day}

days_from_civil algorithm基于这些无迭代算法,并提供简洁可读的语法来调用它们。该语法如下所示。但首先要谈谈tm_yday

tm_yday由C标准定义为:

  自1月1日起的天数 - [0,365]

也就是说,1月1日是第0天。但是这句话:

  

例如输入300 1900的值应为10/27/1900

将1月1日定义为第1天。因此,在下面的代码中,1tm_yday中减去,将1月1解释为第1天,将{300, 1900}解释为1900-10-27。如果不希望对tm_yday进行此解释,请删除- 1

#include "date/date.h"

date::year_month_day
f(const std::tm& x)
{
    using namespace date;
    return sys_days{year{x.tm_year + 1900}/jan/1} + days{x.tm_yday-1};
}

date::year_month_day是一个{year, month, day}结构,每个字段都有getter。此函数从tm_year检索tm_ydaystd::tm字段,并使用以下步骤将它们转换为year_month_day

  1. year{x.tm_year + 1900}tm_year字段转换为名为date::year的字段。这只不过是一个short的包装器,意味着一年。它可以保存[-32767,32767]范围内的值。

  2. 表达式year{x.tm_year + 1900}/jan/1为所示年份的1月1日构建date::year_month_day。它只存储年,月和日的三个值,不进行其他计算。

  3. date::sys_days是天数。它实际上是基于std::chrono::time_point的{​​{1}},精度为system_clock(相对于微秒或纳秒)。 days使用civil_from_days algorithmsys_days{...}转换为此year_month_day(天数)。

  4. time_pointdate::days,期限为24小时。表达式std::chrono::duration将指示的整数表达式转换为名为days{x.tm_yday-1}的{​​{1}}类型。

  5. duration的{​​{1}}被添加到代表一年中第一天的日精度days

  6. 总和的结果是新的duration持有另一天的天数。使用Firestore documentation on working with arrays, lists and setsdays隐式转换回函数time_point的返回类型。

  7. 这个功能可以像这样运用:

    time_point

    输出:

    time_point

    如果您在year_month_day的任何优化高于std::tm tm{}; tm.tm_yday = 300; std::cout << f(tm) << '\n'; 时使用1900-10-27 编译f,它将编译为无分支对象代码没有桌子。这样的代码非常缓存友好且管道友好。对于奖励积分,clang的定义在人眼中也很容易。