how can i use the c++ library such as mktime() to convert day to dates instead of making my own algorithm
How can I convert the day of the year (365 days) equivalent date December 31
393 Views Asked by rob AtThere are 3 best solutions below
On
One example of how to use std::mktime to handle the proposed problem is written below.
The key to this algorithm is to use std::mktime to convert from the year input to a base year epoch, ie the number of seconds from 1970-01-01 until year-01-01.
Then you add manually the number of seconds until the date you want. Remember leap seconds do not count so just adding 86400, the number of seconds in a day, is correct.
The last step is to convert back from epoch time into a full date.
#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};
}
One example of usage would be:
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 );
}
}
Produces when run:
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
On
For starters, December 31 2022 was a Saturday, not a Sunday as your title suggests.
While you could probably find a std:: library way to get what you want, I ask smaller versions of the "compute the day of the year" type problems in interview loops. So it was rather easy for me to drop this code for you. Here's a function that will take a year and a "day of the year" (a value between 1-365 or 1-366 for leap years) and generate a string for the month, day, and day of week. Enjoy.
The downside of this code is that the strings are hardcoded to English. But it works. If you need to make it work for dates before 301 AD, it will need a minor adjustment.
#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;
}
Mktime is not C++, but a C library function. And honestly, it's pretty terrible. The fact that you're even mentioning it might point to you reading outdated material. Also, it's serving a different purpose than what to seem to think it does, but that is of no consequence here:
So, a modern C++ solution (all credits to chris, who put this code on godbolt compiler explorer, which I reworked a bit for you to experiment with:
C++ has
std::chrono. And that allows you to do something like create a date-representing object that describes the beginning of a year, and then add a time delta, i.e., astd::duration(e.g. 365 days or 10⁶ seconds) to it, then convert it to whatever readable representation you need.You should have actually stumbled across it! Documentation is ample and readily available.