Skip to content

A suggestion... for getDate, getMonth, getYear, isLeapYear #113

Open
@marmat123

Description

@marmat123

I don't want to fork, so here:


Since the NTP servers should not provide data before 2020:

Add in NTPClient.h:

#define DAYSOF4YEARS 1461UL		// 4*year plus leap day
#define DAYSOFAYEAR  365UL
#define SEC20200101  1577750400UL	// 2020/01/01 - 1 day (86400s) because the result of the integer division is rounded off

class NTPClient {
  private:
       ...
       uint16_t    _date	= 0;
       uint16_t    _month	= 0;
       uint16_t    _year	= 0;
       bool        _isLeapYear	= false;
       ...
  public:
       ...
       bool isLeapYear() const;
       int getYear() const;
       int getMonth() const;
       int getDate() const; 
      ...

Add in NTPClient.cpp:

bool NTPClient::forceUpdate() {

[...]

// at the end add: 

	uint32_t    _days2k = (_currentEpoc - SEC20200101)/86400;	// distance to today in days
	
	if (_days2k > DAYSOF4YEARS) {					// how many four-year packages + remaining days, from 2050 faster than subtraction on an esp8266 ;)
		_year	= _days2k / DAYSOF4YEARS;
		_days2k	= _days2k - _year * DAYSOF4YEARS;
		_year	*= 4;
	}
	
	if (_days2k > DAYSOFAYEAR + 1) {				//2020 was a leap year, how many years + remaining days
		_days2k--;
		while (_days2k > DAYSOFAYEAR) {				//three times at most
			_days2k -= DAYSOFAYEAR;
			_year++;
		}
	} else _isLeapYear = true;
	
	_year += 20;							// + 2020
	
	if (_isLeapYear && _days2k > 60) _days2k--;			// subtract the possible leap day when February passed
	
	if	(_days2k > 334)	{ _month = 12;	_date = _days2k - 334;	}    //boring but quick
	else if	(_days2k > 304)	{ _month = 11;	_date = _days2k - 304;	}
	else if	(_days2k > 273)	{ _month = 10;	_date = _days2k - 273;	}
	else if	(_days2k > 243)	{ _month = 9;	_date = _days2k - 243;	}
	else if	(_days2k > 212)	{ _month = 8;	_date = _days2k - 212;	}
	else if	(_days2k > 181)	{ _month = 7;	_date = _days2k - 181;	}
	else if	(_days2k > 151)	{ _month = 6;	_date = _days2k - 151;	}
	else if	(_days2k > 120)	{ _month = 5;	_date = _days2k - 120;	}
	else if	(_days2k > 90)	{ _month = 4;	_date = _days2k - 90;	}
	else if	(_days2k > 59)	{ _month = 3;	_date = _days2k - 59;	}
	else if	(_days2k > 31)	{ _month = 2;	_date = _days2k - 31;	}
	else			{ _month = 1;	_date = _days2k;	}

	return true;
}


// and then you can add:

bool NTPClient::isLeapYear() const {
	return this->_isLeapYear;
}
int NTPClient::getYear() const {
	return this->_year;
}
int NTPClient::getMonth() const { 
	return this->_month; 
}
int NTPClient::getDate() const {
	return this->_date;
} 

it works to 2099/12/31 ;-)

You can now use the methods

  • isLeapYear()
  • getYear()
  • getMonth()
  • getDay()

which makes it easier to set an RTC like the DS3231 without time.h - because for some stupid reason it (DS3231) does not understand a timestamp, but has actually stored the "normal" western date format in its registers.

Remark
There is still potential for optimization, because some divisions are redundant now, if you could evaluate temporary variables for getDay, getHours, getMinutes and getSeconds.

Metadata

Metadata

Assignees

No one assigned

    Labels

    topic: codeRelated to content of the project itselftype: enhancementProposed improvement

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions