date.c
changeset 4326 c2ae4dbc1074
parent 4295 66d2c96579a6
child 4344 5d0e40cd67b9
equal deleted inserted replaced
4325:6564f3c88b84 4326:c2ae4dbc1074
    68 	ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
    68 	ACCUM_JAN, ACCUM_FEB, ACCUM_MAR, ACCUM_APR,
    69 	ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
    69 	ACCUM_MAY, ACCUM_JUN, ACCUM_JUL, ACCUM_AUG,
    70 	ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
    70 	ACCUM_SEP, ACCUM_OCT, ACCUM_NOV, ACCUM_DEC,
    71 };
    71 };
    72 
    72 
    73 
    73 static inline bool IsLeapYear(Year yr)
       
    74 {
       
    75 	return yr % 4 == 0 && (yr % 100 != 0 || yr % 400 == 0);
       
    76 }
       
    77 
       
    78 /**
       
    79  * Converts a Date to a Year, Month & Day.
       
    80  * @param date the date to convert from
       
    81  * @param ymd  the year, month and day to write to
       
    82  */
    74 void ConvertDateToYMD(Date date, YearMonthDay *ymd)
    83 void ConvertDateToYMD(Date date, YearMonthDay *ymd)
    75 {
    84 {
    76 	uint yr  = date / (365 + 365 + 365 + 366);
    85 	/*
    77 	uint rem = date % (365 + 365 + 365 + 366);
    86 	 * Year determination in multiple steps to account for leap
    78 	uint x;
    87 	 * years. First do the large steps, then the smaller ones.
    79 
    88 	 */
    80 	yr *= 4;
    89 
    81 
    90 	/* There are 97 leap years in 400 years */
    82 	if (rem >= 366) {
    91 	Year yr = 400 * (date / (365 * 400 + 97));
    83 		rem--;
    92 	int rem = date % (365 * 400 + 97);
    84 		do {
    93 	uint16 x;
    85 			rem -= 365;
    94 
    86 			yr++;
    95 	/* There are 24 leap years in 100 years */
    87 		} while (rem >= 365);
    96 	yr += 100 * (rem / (365 * 100 + 24));
    88 		if (rem >= 31 + 28) rem++;
    97 	rem = rem % (365 * 100 + 24);
    89 	}
    98 
    90 
    99 	/* There is 1 leap year every 4 years */
    91 	ymd->year = BASE_YEAR + yr;
   100 	yr += 4 * (rem / (365 * 4 + 1));
       
   101 	rem = rem % (365 * 4 + 1);
       
   102 
       
   103 	/* The last (max 3) years to account for; the first one
       
   104 	 * can be, but is not necessarily a leap year */
       
   105 	while (rem >= (IsLeapYear(yr) ? 366 : 365)) {
       
   106 		rem -= IsLeapYear(yr) ? 366 : 365;
       
   107 		yr++;
       
   108 	}
       
   109 
       
   110 	/* Skip the 29th of February in non-leap years */
       
   111 	if (!IsLeapYear(yr) && rem >= ACCUM_MAR - 1) rem++;
       
   112 
       
   113 	ymd->year = yr;
    92 
   114 
    93 	x = _month_date_from_year_day[rem];
   115 	x = _month_date_from_year_day[rem];
    94 	ymd->month = x >> 5;
   116 	ymd->month = x >> 5;
    95 	ymd->day = x & 0x1F;
   117 	ymd->day = x & 0x1F;
    96 }
   118 }
    97 
   119 
    98 /**
   120 /**
    99  * Converts a tupe of Year, Month and Day to a Date.
   121  * Converts a tupe of Year, Month and Day to a Date.
   100  * @param year  is a number between 0..?
   122  * @param year  is a number between 0..MAX_YEAR
   101  * @param month is a number between 0..11
   123  * @param month is a number between 0..11
   102  * @param day   is a number between 1..31
   124  * @param day   is a number between 1..31
   103  */
   125  */
   104 Date ConvertYMDToDate(Year year, Month month, Day day)
   126 Date ConvertYMDToDate(Year year, Month month, Day day)
   105 {
   127 {
   106 	uint rem;
   128 	/*
   107 	uint yr = year - BASE_YEAR;
   129 	 * Each passed leap year adds one day to the 'day count'.
   108 
   130 	 *
   109 	/* day in the year */
   131 	 * A special case for the year 0 as no year has been passed,
   110 	rem = _accum_days_for_month[month] + day - 1;
   132 	 * but '(year - 1) / 4' does not yield '-1' to counteract the
   111 
   133 	 * '+1' at the end of the formula as divisions round to zero.
   112 	/* remove feb 29 from year 1,2,3 */
   134 	 */
   113 	if (yr & 3) rem += (yr & 3) * 365 + (rem < 31 + 29);
   135 	int nr_of_leap_years = (year == 0) ? 0 : ((year - 1) / 4 - (year - 1) / 100 + (year - 1) / 400 + 1);
   114 
   136 
   115 	/* base date. */
   137 	/* Day-offset in a leap year */
   116 	return (yr >> 2) * (365 + 365 + 365 + 366) + rem;
   138 	int days = _accum_days_for_month[month] + day - 1;
       
   139 
       
   140 	/* Account for the missing of the 29th of February in non-leap years */
       
   141 	if (!IsLeapYear(year) && days >= ACCUM_MAR) days--;
       
   142 
       
   143 	return year * 365 + nr_of_leap_years + days;
   117 }
   144 }
   118 
   145 
   119 /** Functions used by the IncreaseDate function */
   146 /** Functions used by the IncreaseDate function */
   120 
   147 
   121 extern void OnNewDay_Train(Vehicle *v);
   148 extern void OnNewDay_Train(Vehicle *v);
   250 	if (_cur_year == _patches.ending_year) {
   277 	if (_cur_year == _patches.ending_year) {
   251 			ShowEndGameChart();
   278 			ShowEndGameChart();
   252 	/* check if we reached the maximum year, decrement dates by a year */
   279 	/* check if we reached the maximum year, decrement dates by a year */
   253 	} else if (_cur_year == MAX_YEAR + 1) {
   280 	} else if (_cur_year == MAX_YEAR + 1) {
   254 		Vehicle *v;
   281 		Vehicle *v;
       
   282 		uint days_this_year;
   255 
   283 
   256 		_cur_year--;
   284 		_cur_year--;
   257 		_date -= 365;
   285 		days_this_year = IsLeapYear(_cur_year) ? 366 : 365;
   258 		FOR_ALL_VEHICLES(v) {
   286 		_date -= days_this_year;
   259 			v->date_of_last_service -= 365;
   287 		FOR_ALL_VEHICLES(v) v->date_of_last_service -= days_this_year;
   260 		}
       
   261 
   288 
   262 		/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
   289 		/* Because the _date wraps here, and text-messages expire by game-days, we have to clean out
   263 		 *  all of them if the date is set back, else those messages will hang for ever */
   290 		 *  all of them if the date is set back, else those messages will hang for ever */
   264 		InitTextMessage();
   291 		InitTextMessage();
   265 	}
   292 	}