Darren Engleking
Darren Engleking

Reputation: 11

calculate a date given day of year and year

I am trying to write a program in C given these two data sets from a user. Year:[Range 1901-2099] and Day in year: [range 1-366] I need a formula to calculate the date in MM/DD/YYYY format. One more thing. No IF/ELSE statements. No AND/OR or GREATER THAN or LESS THAN are allowed.

Upvotes: 1

Views: 2359

Answers (4)

alk
alk

Reputation: 70971

In case library functions were allowed to be used (which I doubt) I'd do it this (lazy lego) way:

#define _XOPEN_SOURCE /* glibc2 needs this for strptime */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>    
#include <errno.h>

int to_date(
  char * date, 
  const size_t size, 
  const char * fmt, 
  const short unsigned int day_of_year, 
  const short unsigned int year)
{
  char buffer[16] = "";

  sprintf(buffer, "%hu %hu", day_of_year, year);

  {
    struct tm t = {0};
    char * presult = strptime(buffer, "%j %Y", &t);

    if ((NULL == presult) || ('\0' != *presult))
    {
      errno = EINVAL;
      return -1;
    }

    strftime(date, size, fmt, &t);
  }

  return 0;
}

int main(int argc, char ** argv)
{
  if (2 > argc)
  {
    fprintf(stderr, "Missing arguments. Usage: %s day-of-year year\n", argv[0]);
    return EXIT_FAILURE;
  }

  short unsigned int day_of_year = atoi(argv[1]);
  short unsigned int year = atoi(argv[2]);
  char date[16] = "";

  if (-1 == to_date(date, sizeof(date), "%m/%d/%Y", day_of_year, year))
  {
    perror("to_date() failed");
    return EXIT_FAILURE;
  }

  printf("Result: day %d of year %d is '%s'.\n", day_of_year, year, date);

  return EXIT_SUCCESS;
}

Call it like this

$ ./main 2 2000

to get

Result: day 2 of year 2000 is '01/02/2000'.    

Upvotes: 1

Jan Schejbal
Jan Schejbal

Reputation: 4033

You can do it without any kind of flow control statements (if, switch) and without doing leap year calculation yourself. Get the timestamp corresponding to January 1st of the desired year. Then, you can use a single addition on the timestamp to get to the correct day, and convert the timestamp to whatever format you want.

I would provide code, specific function names and explain what you need to add to the timestamp, but since this is obviously a homework question, I won't. If anyone reminds me in two weeks (i.e. when the deadline for the assignment is most likely over) I'll happily post example code.

Upvotes: 2

chux
chux

Reputation: 154127

For years 1901 to 2099, can easily be done using time functions.

void Makedate(int year, int day, struct tm *dest) {
  struct tm tm1 = { 0 };
  // Leap year every 4 years, lets do calc referencing 2000-2003
  tm1.tm_year = 2000 - 1900 + year % 4;
  tm1.tm_mday = day; // Make the Jan 1st to Jan 366th.  OK to be out of range.
  // Avoid day changes due to DST by using Noon. BTW I doubt this is needed (CYA)
  tm1.tm_hour = 12;  
  // mktime adjusts our fields for us, setting the month, mday, dow, etc.
  mktime(&tm1);
  tm1.tm_year = year - 1900;  // set to selected year
  *dest = tm1;
}

int main() {
  struct tm tm0;
  Makedate(2013,   1, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
  Makedate(2013, 365, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
  Makedate(2020,   1, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
  Makedate(2020, 366, & tm0); printf("y:%4d m:%2d d:%2d\n", tm0.tm_year + 1900, tm0.tm_mon + 1, tm0.tm_mday);
  return 0;
}

y:2013 m: 1 d: 1
y:2013 m:12 d:31
y:2020 m: 1 d: 1
y:2020 m:12 d:31

Upvotes: 0

ND_27
ND_27

Reputation: 774

You can use nested switch case to avoid using if-else.

  1. Find out whether it is a leap year or not.
  2. Create four buckets of months (1-99), (100-199).. etc. Bucket numbers will be used as case numbers.
  3. Now check the left most bit of the day, and write a switch case for assigning it into the right bucket.
  4. Each bucket could be divided into 4 more buckets too (the leap year information will be used).
  5. Repeat step 3 for the middle bit and based on the result (case) switch to appropriate bucket.

Briefly, logic could be as follows:

isLeapYear = year % 4

Switch(isLeapYear)
Case 0: {
  first_bucket = days/4
  Switch(first_bucket)
  {
   Case 0: {
            days_left = days % 100
            second_bucket = days / 50;
// ...
// ...
}
Case 1, 2, 3: {
// Similar logic for non-leap year
// ...
}

Upvotes: 2

Related Questions