PersonalVotingMachine/basic-setup/components/u8g2/sys/sdl/menu/datecalc.c

331 lines
6.8 KiB
C
Raw Normal View History

2020-12-22 14:30:09 +02:00
/*
datecalc.c
Written 1996/96 by Oliver Kraus
Published by Heinz Heise Verlag 1997 (c't 15/97)
Completly rewritten and put under GPL 2011 by Oliver Kraus
(c) 2011 by Oliver Kraus (olikraus@gmail.com)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Development goals:
- English version
- Optimized for 8 bit microcontroller
Definitions:
Short Name: y
Long Name: year
Range: 2000...
Short Name: ydn
Long Name: year day number
Range: 1..366
Short Name: cdn
Long Name: century day number
Range: 1...65535
Short Name: ymd
Long Name: Year, Month, Day
Range: 2000...65535, 1..12, 1..31
Conversions
ymd --> y, ydn
get_year_day_number()
y, ydn --> ymd
get_month_by_year_day_number()
get_day_by_year_day_number()
y, ydn --> cdn
to_century_day_number();
cdn --> y, ydn
from_century_day_number();
*/
#include <stdint.h>
/*
Prototype:
uint8_t is_leap_year(uint16_t y)
Description:
Calculate leap year
Arguments:
y year, e.g. 2011 for year 2011
Result:
0 not a leap year
1 leap year
*/
static uint8_t is_leap_year(uint16_t y)
{
if (
((y % 4 == 0) && (y % 100 != 0)) ||
(y % 400 == 0)
)
return 1;
return 0;
}
/*
Prototype:
uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d)
Description:
Calculate the day number within a year. 1st of Jan has the number 1.
"Robertson" Algorithm
Arguments:
y year, e.g. 2011 for year 2011
m month with 1 = january to 12 = december
d day starting with 1
Result:
The "day number" within the year: 1 for the 1st of Jan.
See also:
get_month_by_day_number()
*/
uint16_t get_year_day_number(uint16_t y, uint8_t m, uint8_t d)
{
uint8_t tmp1;
uint16_t tmp2;
tmp1 = 0;
if ( m >= 3 )
tmp1++;
tmp2 = m;
tmp2 +=2;
tmp2 *=611;
tmp2 /= 20;
tmp2 += d;
tmp2 -= 91;
tmp1 <<=1;
tmp2 -= tmp1;
if ( tmp1 != 0 )
tmp2 += is_leap_year(y);
return tmp2;
}
/*
Prototype:
uint8_t get_month_by_year_day_number(uint16_t y, uint16_t ydn)
Description:
Get the month from year and day number within a year.
"R. A. Stone" Algorithm
Arguments:
y year, e.g. 2011 for year 2011
ydn year day number (1st of Jan has the number 1)
Result:
The month within the year: 1 for January.
See also:
get_year_day_number()
*/
static uint16_t corrected_year_day_number(uint16_t y, uint16_t ydn)
{
uint8_t a;
a = is_leap_year(y);
if ( ydn > 59+a )
{
ydn += 2;
ydn -= a;
}
ydn += 91;
return ydn;
}
uint8_t get_month_by_year_day_number(uint16_t y, uint16_t ydn)
{
uint8_t a;
ydn = corrected_year_day_number(y, ydn);
ydn *= 20;
ydn /= 611;
a = ydn;
a -= 2;
return a;
}
/*
Prototype:
uint8_t get_day_by_year_day_number(uint16_t y, uint16_t ydn)
Description:
Get the day within month from year and day number within a year.
"R. A. Stone" Algorithm
Arguments:
y year, e.g. 2011 for year 2011
ydn year day number (1st of Jan has the number 1)
Result:
The day within a month: 1 for the first day of a month.
See also:
get_year_day_number()
*/
uint8_t get_day_by_year_day_number(uint16_t y, uint16_t ydn)
{
uint8_t m;
uint16_t tmp;
m = get_month_by_year_day_number(y, ydn);
m += 2;
ydn = corrected_year_day_number(y, ydn);
tmp = 611;
tmp *= m;
tmp /= 20;
ydn -= tmp;
return ydn;
}
/*
Prototype:
uint8_t get_weekday_by_year_day_number(uint16_t y, uint16_t ydn)
Description:
Get the day within week from year and day number within a year.
"Zeller" Algorithm
Arguments:
y year, e.g. 2011 for year 2011
ydn year day number (1st of Jan has the number 1)
Result:
The day within a week: 0..6 with 0 = Sunday, 1 = Monday, ...
See also:
get_year_day_number()
*/
uint8_t get_weekday_by_year_day_number(uint16_t y, uint16_t ydn)
{
uint8_t j, c, tmp8;
uint16_t tmp16;
y--;
j = y % 100;
c = y / 100;
tmp16 = c;
tmp16 *= 5;
tmp16 += ydn;
tmp8 = j;
j >>= 2;
c >>= 2;
tmp8 += j;
tmp8 += c;
tmp8 += 28;
tmp16 += tmp8;
tmp16 %= 7;
return tmp16;
}
/*
Prototype:
uint16_t to_century_day_number(uint16_t y, uint16_t ydn)
Description:
Calculate days since January, 1st, 2000
Arguments:
y year, e.g. 2011 for year 2011
ydn year day number (1st of Jan has the number 1)
*/
uint16_t to_century_day_number(uint16_t y, uint16_t ydn)
{
uint16_t cdn;
cdn = ydn;
cdn--;
while( y > 2000 )
{
y--;
cdn += 365;
cdn += is_leap_year(y);
}
return cdn;
}
void from_century_day_number(uint16_t cdn, uint16_t *year, uint16_t *ydn)
{
uint16_t y, days_per_year;
y = 2000;
for(;;)
{
days_per_year = 365;
days_per_year += is_leap_year(y);
if ( cdn >= days_per_year )
{
cdn -= days_per_year;
y++;
}
else
break;
}
cdn++;
*year = y;
*ydn = cdn;
}
/*
Calculate the seconds after 2000-01-01 00:00. The largest possible
time is 2136-02-07 06:28:15
*/
uint32_t to_time(uint16_t cdn, uint8_t h, uint8_t m, uint8_t s)
{
uint32_t t;
t = cdn;
t *= 24;
t += h;
t *= 60;
t += m;
t *= 60;
t += s;
return t;
}
void from_time(uint32_t t, uint16_t *cdn, uint8_t *h, uint8_t *m, uint8_t *s)
{
*s = t % 60;
t /= 60;
*m = t % 60;
t /= 60;
*h = t % 24;
t /= 24;
*cdn = t;
}
uint32_t to_sec_since_2000(uint16_t y, uint8_t mo, uint8_t d, uint8_t h, uint8_t mi, uint8_t s)
{
uint16_t ydn = get_year_day_number(y, mo, d);
uint16_t cdn = to_century_day_number(y, ydn);
return to_time(cdn, h, mi, s);
}
/*
Calculate the minutes after 2000-01-01 00:00.
*/
uint32_t to_minutes(uint16_t cdn, uint8_t h, uint8_t m)
{
uint32_t t;
t = cdn;
t *= 24;
t += h;
t *= 60;
t += m;
return t;
}
void from_minutes(uint32_t t, uint16_t *cdn, uint8_t *h, uint8_t *m)
{
*m = t % 60;
t /= 60;
*h = t % 24;
t /= 24;
*cdn = t;
}
uint32_t to_minutes_since_2000(uint16_t y, uint8_t mo, uint8_t d, uint8_t h, uint8_t mi)
{
uint16_t ydn = get_year_day_number(y, mo, d);
uint16_t cdn = to_century_day_number(y, ydn);
return to_minutes(cdn, h, mi);
}