提问人:rob 提问时间:1/24/2023 最后编辑:rob 更新时间:1/25/2023 访问量:319
如何转换一年中的某一天(365 天)等效日期 12 月 31 日
How can I convert the day of the year (365 days) equivalent date December 31
答:
Mktime 不是 C++,而是一个 C 库函数。老实说,这非常可怕。你甚至提到它的事实可能表明你正在阅读过时的材料。此外,它的目的与人们认为它的作用不同,但这在这里无关紧要:
所以,一个现代的 C++ 解决方案(所有功劳都归功于 chris,他把这段代码放在 godbolt 编译器资源管理器上,我重新设计了一下供你试验:
#include <array>
#include <chrono>
#include <iostream>
using namespace std::literals;
namespace chr = std::chrono;
int main() {
constexpr auto day_of_year = 365;
// y suffix, to turn 2022 into a year specification in std::literals
// the overloaded / operator makes specifying Gregorian calendar dates easy
const auto date = chr::sys_days{2022y / 1 / 0} + chr::days{day_of_year};
// Year-month-day representation of the resulting date
const chr::year_month_day ymd(date);
// Weekday
const chr::weekday day_of_week(date);
constexpr std::array<const char*, 7> weekdays{"Weekend, the 2nd",
"Extended Weekend",
"Tuesday",
"Funday",
"Ultimate Funday",
"Pre-Weekend",
"Weekend (first day)"};
// explicitly cast to int (for years, which exist BC) or unsigned
// (month of year and day of month are always non-negative)
std::cout << static_cast<int>(ymd.year()) << "-"
<< static_cast<unsigned>(ymd.month()) << "-"
<< static_cast<unsigned>(ymd.day()) << ",\n"
<< "Which is a " << weekdays[day_of_week.c_encoding()] << "\n";
// note that the above date calculation is all based on constants, so the
// compiler does it for you at compile time – it doesn't get more efficient
}
C++ 有 .这允许你做一些事情,比如创建一个描述一年开始的日期表示对象,然后添加一个时间增量,即一个(例如 365 天或 10⁶ 秒),然后将其转换为你需要的任何可读表示。std::chrono
std::duration
你真的应该偶然发现它!文档充足且随时可用。
评论
sys_days{year/1/0}
下面写了一个如何使用来处理所提出的问题的示例。std::mktime
该算法的关键是用于将年份输入转换为基准年纪元,即从 1970-01-01 到 year-01-01 的秒数。std::mktime
然后,手动添加距离所需日期的秒数。请记住,闰秒不计算在内,因此只需将一天中的秒数 86400 相加即可。
最后一步是从纪元时间转换回完整日期。
#include <ctime>
#include <cstring>
#include <cstdio>
struct YearDay {
int year;
int month;
int day;
};
YearDay convert( int year, int yday ) {
// Convert year to epoch
struct tm tms;
std::memset(&tms,0,sizeof(tms));
tms.tm_year = year - 1900;
std::time_t date = std::mktime(&tms);
// add days manually
date += yday * 86400;
// Synthesize into a full date
struct tm* newtm = std::gmtime( &date );
return YearDay{newtm->tm_year+1900,
newtm->tm_mon+1,
newtm->tm_mday};
}
一个用法示例是:
int main() {
int year = 2022;
for ( int yday = 1; yday<=365; ++yday ) {
YearDay yd = convert( year, yday );
printf( "%4d %-3d ==> %4d-%02d-%02d\n",
year, yday, yd.year, yd.month, yd.day );
}
}
运行时产生:
Program stdout
2022 1 ==> 2022-01-01
2022 2 ==> 2022-01-02
2022 3 ==> 2022-01-03
...
2022 363 ==> 2022-12-29
2022 364 ==> 2022-12-30
2022 365 ==> 2022-12-31
Godbolt:https://godbolt.org/z/YvGsoenbK
评论
std::
首先,2022 年 12 月 31 日是星期六,而不是标题所暗示的星期日。
虽然你可能会找到一个 std:: 库方法来获得你想要的东西,但我在面试循环中问的是“计算一年中的某一天”类型问题的较小版本。因此,我很容易为您删除此代码。下面是一个函数,它将花费一年和一个“一年中的某一天”(闰年的值介于 1-365 或 1-366 之间)并为月、日和星期几生成一个字符串。享受。
此代码的缺点是字符串被硬编码为英语。但它有效。如果您需要使其适用于公元 301 年之前的日期,则需要稍作调整。
#include <iostream>
#include <string>
using namespace std;
string MakeDate(const int year, const int dayOfYear) {
auto isLeapYear = [](int y) {
return (y % 400 == 0) || ((y % 4 == 0) && (y % 100 != 0));
};
static const int days_in_month[13] = { 0, 31,28,31,30,31,30,31,31,30,31,30,31 };
static const int days_in_month_ly[13] = { 0, 31,29,31,30,31,30,31,31,30,31,30,31 };
static const string month_names[13] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
static const string day_names[7] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursay", "Friday", "Saturday" };
// January 1, 301 was a Tuesday if the Gregorian calendar went back that far
// Every 400 years since then, it's been a Tuesday on January 1
// 0=Sunday, 1=Monday, 2=Tuesday.... 6=Saturday
int firstDayOfYear = 2;
int computeYear = 301;
int diff = (year > computeYear) ? (year - computeYear) : 0;
computeYear += 400 * (diff / 400);
while (year > computeYear) {
int addOn = isLeapYear(computeYear) ? 2 : 1;
firstDayOfYear = (firstDayOfYear + addOn) % 7;
computeYear++;
}
// assume "jan 1" is "dayOfYear==1". Normalize it to be a zero based offset
int days = dayOfYear - 1;
int d = 1;
int m = 1;
int y = year;
int dayOfWeek = (firstDayOfYear + days) % 7;
const int* dim = isLeapYear(y) ? days_in_month_ly : days_in_month;
while (days >= dim[m]) {
days -= dim[m];
m++;
if (m > 12) {
m = 1;
y++;
dim = isLeapYear(y) ? days_in_month_ly : days_in_month;
}
}
d = 1 + days;
string result = month_names[m] + " " + to_string(d) + " " + to_string(y) + ", " + day_names[dayOfWeek];
return result;
}
int main()
{
// print out all 365 days of 2022
for (int i = 1; i <= 365; i++)
{
std::cout << MakeDate(2022, i) << "\n";
}
return 0;
}
评论
.h
<iostream>
<iostream.h>