/**
There is no weekday calculatation.
If it hits the month it automaticly go to dst or std time
This example use los angeles time
**/
#include <Wire.h>
//BEGIN RTC CODE
//rtc variables
static int second, minute, hour;
static int dayOfWeek, dayOfMonth, month, year;
//end rtc variables
#define DS3231_I2C_ADDRESS 0x68
byte decToBcd(byte val) {
return ( (val / 10 * 16) + (val % 10) );
}
// Convert binary coded decimal to decimal numbers
byte bcdToDec(byte val) {
return ( (val / 16 * 10) + (val % 16) );
}
// Set the time
void rtc_setTime(byte second, byte minute, byte hour, byte wday, byte mday, byte mon, byte year) {
// sets time and date data to DS3231
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set next input to start at the seconds register
Wire.write(decToBcd(second)); // set seconds
Wire.write(decToBcd(minute)); // set minutes
Wire.write(decToBcd(hour)); // set hours
Wire.write(decToBcd(wday)); // set day of week (1=Monday, 7=Sunday)
Wire.write(decToBcd(mday)); // set date (1 to 31)
Wire.write(decToBcd(mon)); // set month
Wire.write(decToBcd(year)); // set year (0 to 99)
Wire.endTransmission();
}
//Refresh/Read the time
void rtc_readTime() {
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // set DS3231 register pointer to 00h
Wire.endTransmission();
// request seven bytes of data from DS3231 starting from register 00h
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
second = bcdToDec(Wire.read() & 0x7f);
minute = bcdToDec(Wire.read());
hour = bcdToDec(Wire.read() & 0x3f);
dayOfWeek = bcdToDec(Wire.read());
dayOfMonth = bcdToDec(Wire.read());
month = bcdToDec(Wire.read());
year = bcdToDec(Wire.read());
//leap year correction (if year is > 2100)
#define LEAP_YEAR(Y) ( !(((Y))%4) && ( (((Y))%100) || !(((Y))%400) ) )
if(LEAP_YEAR(year) == 0 && dayOfMonth == 29 && month == 2){
rtc_setTime(second, minute, hour, dayOfWeek, 1, 3, year);
}
}
void rtc_init(){
Wire.begin();
}
//END RTC CODE
//BEGIN DST CODE
static int32_t __offset = 0L; //rtc offst
static int32_t __local = 0l; //local offset
static int32_t __dst;
static bool _dst;
//get the offset from rtc (set this to 0 if the rtc is utc/gmt time)
void rtc_offset(int32_t seconds){
__offset = seconds;
}
//set the user local offset (set this to 0 if you is utc/gmt time)
void set_local_offset(int32_t seconds){
__local = seconds;
}
//just gets the month days
int16_t getYeardayMonth(int16_t month, long currentYear){
int monthlist[12] = {1, 32, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335};
int monthlistleap[12] = {1, 32, 61, 92, 122, 153, 183, 214, 245, 275, 306, 336};
int16_t days = 0;
if( !(((currentYear))%4) && ( (((currentYear))%100) || !(((currentYear))%400) ) ){
days = monthlistleap[month -1];
} else {
days = monthlist[month -1];
}
return days;
}
int8_t getWeekYday(int yday, long year){
int total = 0;
for(int i = 0; i < year; i++){
total = i * 365;
if(LEAP_YEAR(i)){
total++;
}
}
total+=yday;
return (total+6)%7;
}
//sets the dst (you need to add current rtc month and weekday) sunday is 0
void set_dst(long currentYear, int currentMonth, int currentDay, int sweekday, int smonth, int eday, int emonth, int offset){
__dst = offset;
const uint8_t daysInMonth[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
uint16_t days = currentDay, endMonth, startMonth;
for (uint8_t i = 1; i < currentMonth; i++)
{
days += daysInMonth[i - 1];
}
if (currentMonth > 2 && !(((currentYear))%4) && ( (((currentYear))%100) || !(((currentYear))%400) ) )
{
days++;
}
startMonth = getYeardayMonth(smonth, currentYear);
endMonth = getYeardayMonth(emonth, currentYear);
if(days > startMonth && days < endMonth){
_dst = 1;
} else {
_dst = 0;
}
if(days > endMonth){
_dst = 0;
}
if(days < startMonth){
_dst = 0;
}
}
//gets the local offset with dst
int32_t get_local_offset(){
if(_dst){
return __local + __dst;
} else {
return __local;
}
}
//END DST CODE
void setup() {
rtc_init();
//set your offset here in seconds
rtc_offset(-28800);
set_local_offset(-28800);
Serial.begin(115200);
}
void loop() {
rtc_readTime();
static char buf[50];
sprintf(buf, "%u-%02d-%02dT%02d:%02d:%02dZ", year, month, dayOfMonth, hour, minute, second);
set_dst(year, month, dayOfMonth, 0, 3, 0, 11, 3600);
Serial.println(buf);
Serial.println(get_local_offset()); //in seconds
delay(500);
}