How can I convert the day of the year (1-365) to i

2019-06-12 21:06发布

问题:

I've tried searching for an algorithm that could achieve this but haven't come up with any results.

I have the constructor Date2013(int dd).

In this member function I created an array with the months in it (January, February, Etc)

Then I created an if statement that takes in dd, if dd falls in between day 1 -31, then output January, if it falls between 32 - 59, then output February.

What I'm having trouble doing is, then taking the number they input, dd, and converting that to the appropriate day in the month. ie(The 34th day of the year is February 2nd).

Does anyone know of any algorithms or know of a way I could achieve this?

(I'm just beginning to learn my C++ so an explanation or comments in any code would be really helpful so that I can understand your thought process and syntax)

回答1:

The most portable & reliable approach is to use the ANSI C mktime & localtime functions, which will work with either C or C++

Update:

To answer the question about how to implement your own algorithm rather than using standard C library mktime function, a good starting point would be to look at known-working code such as the glibc mktime source code. The relevant tidbits you would need include:

From glibc 2.17 (HEAD) mktime.c around line 141:

#define TM_YEAR_BASE 1900

/* Return 1 if YEAR + TM_YEAR_BASE is a leap year.  */
static inline int
leapyear (int year)
{
  /* Don't add YEAR to TM_YEAR_BASE, as that might overflow.
     Also, work even if YEAR is negative.  */
  return
    ((year & 3) == 0
     && (year % 100 != 0
         || ((year / 100) & 3) == (- (TM_YEAR_BASE / 100) & 3)));
}

From glibc 2.17 (HEAD) mktime.c starting at line 160:

const unsigned short int __mon_yday[2][13] =
{
    /* Normal years.  */
    { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
    /* Leap years.  */
    { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
};

A sample C++ class implementing a constructor that converts year & dayOfYear to corresponding month & dayOfMonth might look something like:

#include <iostream>
using namespace std;

#define MONTHS_IN_YEAR 12

class MyDateClass {
public:
MyDateClass(int year, int dayOfYear) {
    int yearOffset = dayOfYear - TM_YEAR_BASE;
    int leapYearIndex = leapyear(year) ? 1 : 0;
    int daysInYear = leapYearIndex ? 366 : 365;

    this->year = year;
    this->dayOfYear = dayOfYear;

    if (dayOfYear >= 1 && dayOfYear <= daysInYear) {
        for (int mon = 0; mon < MONTHS_IN_YEAR; mon++) {
           if (dayOfYear <= __mon_yday[leapYearIndex][mon+1]) {
               month = mon + 1;
               dayOfMonth = dayOfYear - __mon_yday[leapYearIndex][mon];
               break;
           }
        }
    } else {
        cerr << "day of year must be between 1 and " << daysInYear << endl;
        month = 0;
        dayOfMonth = 0;
    }
}

// Get month 1=January, 12=December       
inline int getMonth() { return month; }

// Get day of month
inline int getDayOfMonth() { return dayOfMonth; }

// Get year
inline int getYear() { return year; }

// Get day of yar
inline int getDayOfYear() { return dayOfYear; }

private:
   int month;
   int dayOfMonth;
   int year;
   int dayOfYear;
};

Hopefully I won't get down-voted for showing sample code that might do the job. Feel free to implement it however you want of course. This is just one example approach.


If you would rather use the existing mktime functionality (recommended), which should most likely be present in the standard C library on any platform you are programming, my original answer content follows...

When using mktime you need to be sure to set tm_mon=0 and tm_mday to the day of the year (see mktime documentation for a better explanation), but in a nutshell mktime ignores tm_wday and tm_yday and only translates tm_mday, which it essentially interprets as the day of the year if you also set tm_mon = 0;

Here is some working sample code that illustrates the point, which will work in C or C++:

#include <stdio.h>      /* printf, scanf */
#include <time.h>       /* time_t, struct tm, time, mktime */
#include <strings.h>    /* bzero */

int main () {
   time_t loctime;
   struct tm timeinfo, *loctimeinfo;
   int year, day;

   /* prompt user for year and day-of-the-year */
   printf ("Enter year: "); scanf ("%d",&year);
   printf ("Enter day of the year: "); scanf ("%d",&day);

   /* initialize timeinfo and modify it to the user's choice */
   bzero(&timeinfo, sizeof(struct tm));
   timeinfo.tm_isdst = -1;  /* Allow mktime to determine DST setting. */
   timeinfo.tm_mon   = 0;
   timeinfo.tm_mday = day;
   timeinfo.tm_year = year - 1900;

   loctime = mktime (&timeinfo);
   loctimeinfo = localtime(&loctime);

   printf ("The date for that day of the year is %s.\n", asctime(loctimeinfo));

   return 0;
}

Compile & sample runs:

$ g++ -o t2 t2.c
$ ./t2
Enter year: 2013
Enter day of the year: 1
The date for that day of the year is Tue Jan  1 00:00:00 2013

$ ./t2
Enter year: 2013
Enter day of the year: 365
The date for that day of the year is Tue Dec 31 00:00:00 2013

Even works for leap years like 2012:

$ ./t2
Enter year: 2012
Enter day of the year: 366
The date for that day of the year is Mon Dec 31 00:00:00 2012


回答2:

So, the basic principle for CALCULATING this is to have a list of "number of days per month", and basically.

int days_in_month[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

If we then have a variable called days which is the number of days within the year and a month to indicate which month we end in:

Start with "month = 1;", simply check if the days is less than days_in_month[month], and if it isn't subtract days_in_month[month] from days, and keep going until you either reach month = 12 and still have more days and days is more than the days_in_month[month] [which means it's next year, start over with month=1, and move to next year - but I think your task is limited to 1-365 days, so just report an error is fine for now].

When the number of days isn't more than days_in_month[month], you have the number of days into that month.

Note that I have intentionally not written the code for how to do this, but described how to do it. Because I'm the one who has written this sort of code at least a few times, and you are the one trying to learn. You do not learn by copying and pasting from SO.

Edit: And yes, I've completely ignored leap-years. For 2013, it's not a leap-year, so we don't care... ;)



标签: c++ calendar