-
Notifications
You must be signed in to change notification settings - Fork 5
/
adst.c
118 lines (110 loc) · 3.97 KB
/
adst.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/*
* Auto DST support for VFD Modular Clock
* (C) 2012 William B Phelps
*
* 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 2 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.
*
*/
#include <avr/io.h>
#include <string.h>
#include "Time.h"
#include "adst.h"
// globals from main.c
extern uint8_t g_DST_mode; // DST off, on, auto?
extern uint8_t g_DST_offset; // DST offset in hours
extern uint8_t g_DST_update; // DST update flag
uint8_t mDays[]={31,28,31,30,31,30,31,31,30,31,30,31};
uint16_t tmDays[]={0,31,59,90,120,151,181,212,243,273,304,334}; // Number days at beginning of month if not leap year
// Calculate day of the week - Sunday=1, Saturday=7 (non ISO)
uint8_t dotw(uint16_t year, uint8_t month, uint8_t day)
{
uint16_t m, y;
m = month;
y = year;
if (m < 3) {
m += 12;
y -= 1;
}
return (day + (2 * m) + (6 * (m+1)/10) + y + (y/4) - (y/100) + (y/400) + 1) % 7 + 1;
}
long yearSeconds(uint16_t yr, uint8_t mo, uint8_t da, uint8_t h, uint8_t m, uint8_t s)
{
unsigned long dn = tmDays[(mo-1)]+da; // # days so far if not leap year or (mo<3)
if (mo>2) {
if ((yr%4 == 0 && yr%100 != 0) || yr%400 == 0) // if leap year
dn ++; // add 1 day
}
dn = dn*86400 + (long)h*3600 + (long)m*60 + s;
return dn;
}
long DSTseconds(uint16_t year, uint8_t month, uint8_t doftw, uint8_t week, uint8_t hour)
{
uint8_t dom = mDays[month-1];
if ( (month == 2) && (year%4 == 0) )
dom ++; // february has 29 days this year
uint8_t dow = dotw(year, month, 1); // DOW for 1st day of month for DST event
int8_t day = doftw - dow; // number of days until 1st dotw in given month
if (day<1) day += 7; // make sure it's positive
if (doftw >= dow)
day = doftw - dow;
else
day = doftw + 7 - dow;
day = 1 + day + (week-1)*7; // date of dotw for this year
while (day > dom) // handles "last DOW" case
day -= 7;
return yearSeconds(year,month,day,hour,0,0); // seconds til DST event this year
}
// DST Rules: Start(month, dotw, n, hour), End(month, dotw, n, hour), Offset
// DOTW is Day of the Week. 1=Sunday, 7=Saturday
// N is which occurrence of DOTW
// Current US Rules: March, Sunday, 2nd, 2am, November, Sunday, 1st, 2 am, 1 hour
// 3,1,2,2, 11,1,1,2, 1
uint8_t getDSToffset(tmElements_t* te, DST_Rules* rules)
{
// uint16_t yr = 2000 + tmYearToY2k(te->Year); // convert tmElements_t Year to 20yy
uint16_t yr = 2000 + te->Year; // Year as 20yy; te.Year is not 1970 based
// if current time & date is at or past the first DST rule and before the second, return 1
// otherwise return 0
// seconds til start of DST this year
long seconds1 = DSTseconds(yr, rules->Start.Month, rules->Start.DOTW, rules->Start.Week, rules->Start.Hour);
// seconds til end of DST this year
long seconds2 = DSTseconds(yr, rules->End.Month, rules->End.DOTW, rules->End.Week, rules->End.Hour);
long seconds_now = yearSeconds(yr, te->Month, te->Day, te->Hour, te->Minute, te->Second);
if (seconds2>seconds1) { // northern hemisphere
if ((seconds_now >= seconds1) && (seconds_now < seconds2)) // spring ahead
return(rules->Offset); // return Offset
else // fall back
return(0); // return 0
}
else { // southern hemisphere
if ((seconds_now >= seconds2) && (seconds_now < seconds1)) // fall ahead
return(rules->Offset); // return Offset
else // spring back
return(0); // return 0
}
}
char dst_setting_[5];
char* dst_setting(uint8_t dst)
{
switch (dst) {
case(0):
strcpy(dst_setting_,"off");
break;
case(1):
strcpy(dst_setting_,"on ");
break;
case(2):
strcpy(dst_setting_,"auto");
break;
default:
strcpy(dst_setting_,"???");
}
return dst_setting_;
}