Every four-hundredth year is a leap year. So, take the number of days since the beginning of 2001 and do a modulo (365 * 400 + 97) to find the number of days since the last such four-hundredth year. Do integer division by the former figure to find out how many 400-year blocks have passed since 1/1/2001.
Every hundredth year is not a leap year. So, take the modulo result above and do a modulo (365 * 100 + 24) to find the number of days since the last such hundredth year. Do integer division by (365 * 100 + 24) to find out how many years have passed since the last hundredth year.
Every fourth year within such a hundred-year block is a leap year. So take the modulo result above and do a modulo (365 * 4 + 1) on it to get the number of days since the last leap year. Do integer division by the modulo result from the previous step to get the number of four-year blocks since the last hundredth year.
Every 365 days within such a four-year block constitute a year. So take the modulo result from the previous step and do a modulo 365 to get the number of days since the beginning of the year. Do integer division by the modulo result from the previous step to get the number of years since the last leap year.
Compute number of years since the origin as 400 * (first integer division result) + 100 * (second integer division result) + 4 * (third integer division result) + (fourth integer division result).
Within nine computations you have the result the stupid loop was trying to arrive at. (Edit: See next post, it has a similar bug to the stupid loop as well!) If you really need 1980 as the origin, you can add the number of days for 1/1/1601 through 31/12/1979 (corresponding to 379 years) according to the above pattern to the input and use 1/1/1601 as the "origin". Then subtract 379 years from the year-count afterward. (This won't work for years before the 1800s since the Gregorian calendar has changed since the year 1601, but it should work without issue for 1980 onward, at least.)
Example code:
Code:
const int daysInYear = 365; /* regular year */
const int daysInFourYears = daysInYear * 4 + 1; /* leap day */
const int daysIn100Years = daysInYear * 100 + 24; /* no leap day */
const int daysIn400Years = daysInYear * 400 + 97; /* leap day */
const int daysUntil1980 = 3 * daysIn100Years + 19 * daysInFourYears
+ 3 * daysInYear; /* 379 "years" */
/* [...] */
days += daysUntil1980;
year = 1601; /* year after last 400th year before 1980 */
year += days / daysIn400Years * 400; /* 400-year blocks */
days %= daysIn400Years; /* days since the last 400-year block */
year += days / daysIn100Years * 100; /* centuries */
days %= daysIn100Years; /* days since beginning of century */
year += days / daysInFourYears * 4; /* four-year blocks */
days %= daysInFourYears; /* days since the last leap year */
year += days / daysInYear; /* ordinary years */
days %= daysInYear; /* days since beginning of year */
/*
* At this point, year has the current year, while days has the number of days
* since January 1.
*/
Adapted to the C library's time() function, the following test program uses 1970 as the "ORIGINYEAR" instead of 1980.
Code:
#include <stdio.h>
#include <time.h>
int main ()
{
time_t days = time (NULL) / 86400; /* days since 1/1/1970 */
int year;
const int daysInYear = 365; /* regular year */
const int daysInFourYears = daysInYear * 4 + 1; /* leap day */
const int daysIn100Years = daysInYear * 100 + 24;/* no leap day */
const int daysIn400Years = daysInYear * 400 + 97;/* leap day */
const int daysUntil1970 = 3 * daysIn100Years + 17 * daysInFourYears
+ 1 * daysInYear; /* 369 "years" */
/* [...] */
days += daysUntil1970;
year = 1601; /* year after last 400th year before 1970 */
year += days / daysIn400Years * 400; /* 400-year blocks */
days %= daysIn400Years; /* days since the last 400-year block */
year += days / daysIn100Years * 100; /* centuries */
days %= daysIn100Years; /* days since beginning of century */
year += days / daysInFourYears * 4; /* four-year blocks */
days %= daysInFourYears; /* days since the last leap year */
year += days / daysInYear; /* ordinary years */
days %= daysInYear; /* days since beginning of year */
/*
* At this point, year has the current year, while days has the number
* of days since January 1.
*/
printf ("This year is %d. %d days have elapsed since it began.\n",
year, days);
return 0;
}
Running it, I get
Code:
This year is 2009. 1 days have elapsed since it began.
(which is true, it was January 2 at UTC as of that run).
You know what's got me worried? That according to the linked code in the OP things will go bad again in 2081. I mean, how am I supposed to spend the next 72 years knowing that my Zune will die at that time?
Sure, I'll be close to 100 years old then, but with advances in medical technology I could still be quite alive and kicking then. What I can be sure of is that my Zune will definitely die again on that date. It's just so unfair...
wow...just wow..all i can say is that im super pissed and so are my parents because they got that for me when it just came out. i was doing some research online and people kept on blaming skynet and aliens. i responded to say that bill gates was an alien and was trying to take over skynet and take all our bases and music sharing funness... microsoft really needs to fix this somehow, or there is going to be a lot of 30gb hard drives on ebay in the next week. if they dont fix this soon there is going to be a very big recall on over 1000 zunes over the word. fix it, or give me my 200 bucks back gates, come on you can spend that much. you usually donate like 5mill to a random charity each year no? ima go punt my zune around to see if it will work.. then maybe a blend tech blender.....
"All apple people used to get shunned around zune users because they thought zune was better than them, now that we took an epic fail, they all turned around and started laughing down all over us right in our faces and kept telling us "ooo u thought you were better! well now look at it! its just a little P.O.S. now!!""
yea kill yor self.. look at the 360. that always breaks and gets red ringed. people should have seen this coming...
My thought was similar but I think easier to read and removes the duplicate calls to IsLeapYear():
Code:
year = ORIGINYEAR; /* = 1980 */
const int cDaysInYear = IsLeapYear() ? 366 : 365;
while (days > cDaysInYear)
{
days -= cDaysInYear;
year++;
}
Edit: Just saw your later post and obviously if you're going to rewrite this function instead of just fix it, the non-loop option is the way to go =)
Your solution would not work properly. IsLeapYear() would need to be called for each year, otherwise every year would have 365 days or every year would have 366 days.
__________________
"Against logic there is no armor like ignorance." - Laurence J. Peter
Zune: The Culprit of the Zune Massacre
Gizmodo is saying the the Gigabeat S also failed (...?)
"The fiend is Freescale's MC13783 PMIC, the power management integrated circuit—chips used to regulate and control power—which is used in the the Gigabeat S Series. This is the model that Microsoft used as the basis for their Zune."
This doesn't correlate with this explanation or the Microsoft one...
My last post carrying the loopless code still doesn't work. See for instance the offending date, December 31, 2008. It'll consider that to be the year 2009, because the last step (%= daysInYear) doesn't account for the fourth (leap) year at all. And in fact, this would require something like IsLeapYear() since the fourth year isn't always a leap year.
Isn't calendaring fun?
Code:
#include <stdio.h>
#include <time.h>
int IsLeapYear (int year)
{
return (year % 400 == 0
|| year % 100 != 0)
&& year % 4 == 0;
}
int main ()
{
int year;
time_t days = time (NULL) / 86400 - 3; /* days since 1/1/1970 */
const int daysInYear = 365; /* regular year */
const int daysInFourYears = daysInYear * 4 + 1; /* leap day */
const int daysIn100Years = daysInFourYears * 25 - 1;/* no leap day */
const int daysIn400Years = daysIn100Years * 4 + 1;/* leap day */
const int daysUntil1970 = 3 * daysIn100Years + 17 * daysInFourYears
+ 1 * daysInYear; /* 369 "years" */
/* [...] */
days += daysUntil1970;
year = 1601; /* year after last 400th year before 1970 */
year += days / daysIn400Years * 400; /* 400-year blocks */
days %= daysIn400Years; /* days since the last 400-year block */
/* Avoid "demoting" the first day of a four-century block. */
if (days != 0)
{
year += days / daysIn100Years * 100; /* centuries */
days %= daysIn100Years; /* days since beginning of century */
/* Avoid "promoting" the last day of a four-century block. */
if (days == 0 && IsLeapYear (year - 1))
{
-- year;
days += daysInYear;
}
else
{
year += days / daysInFourYears * 4;/* 4-year blocks */
days %= daysInFourYears;/* days since last leap year */
/* Avoid "demoting" the first day of a 4-year block. */
if (days != 0)
{
year += days / daysInYear;/* ordinary years */
days %= daysInYear;/* days since Jan 1 */
/* Avoid promoting last day of a 4-year block */
if (days == 0 && IsLeapYear (year - 1))
{
-- year;
days = daysInYear;
}
}
}
}
/*
* At this point, year has the current year, while days has the number
* of days since January 1.
*/
printf ("This year is %d. %ld days have elapsed since it began.\n",
year, days);
return 0;
}
It takes some special-casing to get it working. (Still no loops though.) Essentially, if the number of days left in the earlier steps (four-year blocks, century blocks and four-century blocks) is zero, we're at the beginning of a new such period and no more yearwise computation needs to be done. Otherwise, we need to specialcase the situation where, after the computation, the previous year was a leap year and we're at the beginning of a 100-year or 365-day period; if so, it's actually the last day of the previous (leap) year.
Yes, I hate the special cases too. Suddenly the loop code looks more elegant. :p
Zune: The Culprit of the Zune Massacre
Gizmodo is saying the the Gigabeat S also failed (...?)
"The fiend is Freescale's MC13783 PMIC, the power management integrated circuit—chips used to regulate and control power—which is used in the the Gigabeat S Series. This is the model that Microsoft used as the basis for their Zune."
This doesn't correlate with this explanation or the Microsoft one...
here is what I came up with before I read your most recent post. How did I do?
Code:
#include <stdio.h>
#include <time.h>
int main ()
{
time_t days = time (NULL) / 86400; /* days since 1/1/1970 */
//****************************************************************************************************
// Test Variables
// days +=365; /* days since 1/1/1970 one year from today */
// days += (365 * 2); /* days since 1/1/1970 two years from today */
// days += (365 * 3); /* days since 1/1/1970 three years from today */
// days += (365 * 4) + 1; /* days since 1/1/1970 four years from today */
days += (365 * 4) + 1 - 3; /* days since 1/1/1970 until 12/31/2012 when run on 01/03/2009 */
//****************************************************************************************************
int year;
const int daysInYear = 365; /* regular year */
const int daysInFourYears = daysInYear * 4 + 1; /* leap day */
const int daysIn100Years = daysInYear * 100 + 24;/* no leap day */
const int daysIn400Years = daysInYear * 400 + 97;/* leap day */
const int daysUntil1970 = 3 * daysIn100Years + 17 * daysInFourYears
+ 1 * daysInYear; /* 369 "years" */
/* [...] */
days += daysUntil1970;
year = 1601; /* year after last 400th year before 1980 */
year += days / daysIn400Years * 400; /* 400-year blocks */
days %= daysIn400Years; /* days since the last 400-year block */
year += days / daysIn100Years * 100; /* centuries */
days %= daysIn100Years; /* days since beginning of century */
year += days / daysInFourYears * 4; /* four-year blocks */
days %= daysInFourYears; /* days since the last leap year */
//****************************************************************************************************
// Calculates number of years and days since last leap year
int years_since_last_leapyear;
years_since_last_leapyear = days / daysInYear;
if (years_since_last_leapyear == 4)
{
year += years_since_last_leapyear - 1;
days = daysInYear;
}
else
{
year += years_since_last_leapyear;
days %= daysInYear;
}
//****************************************************************************************************
printf ("This year is %d. %d days have elapsed since it began.n",
year, days);
return 0;
}
Last edited by programphases; 01-03-2009 at 12:43 AM.
here is what I came up with before I read your most recent post. How did I do?
Code:
#include <stdio.h>
#include <time.h>
int main ()
{
time_t days = time (NULL) / 86400; /* days since 1/1/1970 */
//****************************************************************************************************
// Test Variables
// days +=365; /* days since 1/1/1970 one year from today */
// days += (365 * 2); /* days since 1/1/1970 two years from today */
// days += (365 * 3); /* days since 1/1/1970 three years from today */
// days += (365 * 4) + 1; /* days since 1/1/1970 four years from today */
days += (365 * 4) + 1 - 3; /* days since 1/1/1970 until 12/31/2012 when run on 01/03/2009 */
//****************************************************************************************************
int year;
const int daysInYear = 365; /* regular year */
const int daysInFourYears = daysInYear * 4 + 1; /* leap day */
const int daysIn100Years = daysInYear * 100 + 24;/* no leap day */
const int daysIn400Years = daysInYear * 400 + 97;/* leap day */
const int daysUntil1970 = 3 * daysIn100Years + 17 * daysInFourYears
+ 1 * daysInYear; /* 369 "years" */
/* [...] */
days += daysUntil1970;
year = 1601; /* year after last 400th year before 1980 */
year += days / daysIn400Years * 400; /* 400-year blocks */
days %= daysIn400Years; /* days since the last 400-year block */
year += days / daysIn100Years * 100; /* centuries */
days %= daysIn100Years; /* days since beginning of century */
year += days / daysInFourYears * 4; /* four-year blocks */
days %= daysInFourYears; /* days since the last leap year */
//****************************************************************************************************
// Calculates number of years and days since last leap year
int years_since_last_leapyear;
years_since_last_leapyear = days / daysInYear;
if (years_since_last_leapyear == 4)
{
year += years_since_last_leapyear - 1;
days = daysInYear;
}
else
{
year += years_since_last_leapyear;
days %= daysInYear;
}
//****************************************************************************************************
printf ("This year is %d. %d days have elapsed since it began.n",
year, days);
return 0;
}
The problem (that I also encountered with my last solution) remains that in some cases the modulo operation messes up the previous computation. Specifically:
Performing a modulo century-worth-of-days on a day corresponding to the last day of a four-century block will get you number-of-days zero and the year computation will result in the next year (so, say, 12/31/2000 will be computed to be 1/1/2001), since a four-century block has one day more than a century block. This error occurs before your fixup code and results in a situation that the fixup code won't handle, so you still end up with the wrong answer.
A similar issue occurs with the last day of an "ordinary" leap year at the end of a four-year block -- in this case your code corrects the four-year modulo result to three and sets the number of days left to 365, which fixes this issue.
The reason a fixup isn't required between the century computation and the four-year computation is that a century has one day less than 25 four-year blocks, so there's no chance of an extra day being considered the beginning of a four-year block.
This was more tricky than I thought! I've checked my code against 12/31/2000, 1/1/2001, 12/31/2008, 1/1/2009, 12/31/2100 and 1/1/2101, and
I'm still concerned there's a corner case I haven't handled. :p
The following program works for the last two days in 2000 and the first two days in 2001, the last two days in 2008 and the first two days in 2009, the last two days in 2099 and the first two days in 2100, the last two days in 2100 and the first two days in 2101. I am not sure if it works for all other possible days/years. It is nearly identical to your latest posted version...
Code:
#include <stdio.h>
#include <time.h>
int IsLeapYear (int year)
{
return (year % 400 == 0
|| year % 100 != 0)
&& year % 4 == 0;
}
int main ()
{
time_t days = time (NULL) / 86400; /* days since 1/1/1970 */
//****************************************************************************************************
// Test Variables
// days +=365; /* days since 1/1/1970 one year from today */
// days += (365 * 2); /* days since 1/1/1970 two years from today */
// days += (365 * 3); /* days since 1/1/1970 three years from today */
// days += (365 * 4) + 1; /* days since 1/1/1970 four years from today */
// days += (365 * 4) + 1 - 3; /* days since 1/1/1970 until 12/31/2012 when run on 01/03/2009 */
// Year 2000-2001 Test Variables
// days = days - 3 - 366 - 365 - 365 - 365 - 366 - 365 - 365 - 365 - 1 ; /* days since 1/1/1970 until 12/30/2000 when run on 01/03/2009 */ // Is a Leap Year (364 days elapsed)
// days = days - 3 - 366 - 365 - 365 - 365 - 366 - 365 - 365 - 365 ; /* days since 1/1/1970 until 12/31/2000 when run on 01/03/2009 */ // Is a Leap Year (365 days elapsed)
// days = days - 3 - 366 - 365 - 365 - 365 - 366 - 365 - 365 - 365 + 1; /* days since 1/1/1970 until 1/1/2001 when run on 01/03/2009 */ // (0 days elapsed)
// days = days - 3 - 366 - 365 - 365 - 365 - 366 - 365 - 365 - 365 + 1 + 1; /* days since 1/1/1970 until 1/2/2001 when run on 01/03/2009 */ // (1 days elapsed)
// Year 2008-2009 Test Variables
//days = days - 3 - 1; /* days since 1/1/1970 until 12/30/2008 when run on 01/03/2009 */ // Is a Leap Year (364 days elapsed)
//days = days - 3; /* days since 1/1/1970 until 12/31/2008 when run on 01/03/2009 */ // Is a Leap Year (365 days elapsed)
//days = days - 3 + 1; /* days since 1/1/1970 until 1/1/2008 when run on 01/03/2009 */ // (0 days elapsed)
//days = days - 3 + 1 + 1; /* days since 1/1/1970 until 1/2/2008 when run on 01/03/2009 */ // (1 days elapsed)
// Year 2099-2100 Test Variables
//days = days - 3 - 1 + (91 * 365) + 22 ; /* days since 1/1/1970 until 12/30/2099 when run on 01/03/2009 */ // Is not a Leap Year (363 days elapsed)
//days = days - 3 + (91 * 365) + 22 ; /* days since 1/1/1970 until 12/31/2099 when run on 01/03/2009 */ // Is not a Leap Year (364 days elapsed)
//days = days - 3 + 1 + (91 * 365) + 22 ; /* days since 1/1/1970 until 1/1/2100 when run on 01/03/2009 */ // (0 days elapsed)
//days = days - 3 + 1 + 1 + (91 * 365) + 22 ; /* days since 1/1/1970 until 1/2/2100 when run on 01/03/2009 */ // (1 days elapsed)
// Year 2100-2101 Test Variables
//days = days - 3 - 1 + (92 * 365) + 22 ; /* days since 1/1/1970 until 12/30/2100 when run on 01/03/2009 */ // Is not a Leap Year (363 days elapsed)
//days = days - 3 + (92 * 365) + 22 ; /* days since 1/1/1970 until 12/31/2100 when run on 01/03/2009 */ // Is not a Leap Year (364 days elapsed)
//days = days - 3 + 1 + (92 * 365) + 22 ; /* days since 1/1/1970 until 1/1/2101 when run on 01/03/2009 */ // (0 days elapsed)
//days = days - 3 + 1 + 1 + (92 * 365) + 22 ; /* days since 1/1/1970 until 1/2/2101 when run on 01/03/2009 */ // (1 days elapsed)
//****************************************************************************************************
int year;
const int daysInYear = 365; /* regular year */
const int daysInFourYears = daysInYear * 4 + 1; /* leap day */
const int daysIn100Years = daysInYear * 100 + 24;/* no leap day */
const int daysIn400Years = daysInYear * 400 + 97;/* leap day */
const int daysUntil1970 = 3 * daysIn100Years + 17 * daysInFourYears
+ 1 * daysInYear; /* 369 "years" */
/* [...] */
days += daysUntil1970;
year = 1601; /* year after last 400th year before 1980 */
year += days / daysIn400Years * 400; /* 400-year blocks */
days %= daysIn400Years; /* days since the last 400-year block */
// Fixup 1 (If days == 0, we are at the last day of a 400 year block.)
// Continue processing only if there are any days remaining after the 400 year block.
if (days)
{
year += days / daysIn100Years * 100; /* centuries */
days %= daysIn100Years; /* days since beginning of century */
// Fixup 2 (If days == 0 and is leapyear(year -1), then we are at the last day of a 100 year block
// that has a leaplear and need fixup2, else continue processing.)
if (!days && IsLeapYear(year - 1))
{
year -= 1;
days = daysInYear;
}
else
{
year += days / daysInFourYears * 4; /* four-year blocks */
days %= daysInFourYears; /* days since the last leap year */
//****************************************************************************************************
// Calculates number of years and days since last leap year
int years_since_last_leapyear;
years_since_last_leapyear = days / daysInYear;
// Fixup 3 (If years_since_last_leapyear == 4, then we are at the last day of a 4 year block
// and the 4th year in the 4 year block is a leap year
// and thus need fixup3, else continue processing.)
if (years_since_last_leapyear == 4)
{
year += years_since_last_leapyear - 1;
days = daysInYear;
}
else
{
year += years_since_last_leapyear;
days %= daysInYear;
}
//****************************************************************************************************
}
}
printf ("This year is %d. %d days have elapsed since it began.n",
year, days);
return 0;
}
__________________
Learn new programming languages quickly with Program Phases.
A Step Beyond Hello World! ProgramPhases.com
Your solution would not work properly. IsLeapYear() would need to be called for each year, otherwise every year would have 365 days or every year would have 366 days.
You are correct, I misunderstood the context of the code snippet. For some reason assumed this piece of code was being called for each year. But it turns out that is not the case.
I purchesed a limited edition 30GB breast cancer survivor pink from the ford web site for survivors last december, my wife is a 6 year survivor & has loved her special Zune, on 12/28/08 she tried to upload her new software due to microsoft updates for zune & her zune froze up. I tried every thing the web site has asked to do, I even went as far & puchased a new usb cord 14.95 for it & its still froze up. I called customer service & they said it was due to the soft ware issue but since it is out of warrenty I would have to send 129.00 dollars inorder for them to fix the issue the software caused. Send more money to fix a issue that should be covered due to thier mystake, makes no since, thats like buying an ice cream cone from dairy queen & receiveing a bowl of milk due to the fridge going out, their fault but to bad huh. Microsoft should replace or fix for free, i have purchased over 100.00 of zune passes that are now usless unless I speend more money for an issue they caused.Bad customer servise. If a class action law siut comes up you can bet I will be a part of it