NorthernWidget / DS3231

Communicates between Arduino-programmed AVR and Maxim DS3231 RTC: splice of Ayars' (http://hacks.ayars.org/2011/04/ds3231-real-time-clock.html) and Jeelabs/Ladyada's (https://github.com/adafruit/RTClib) libraries
The Unlicense
187 stars 81 forks source link

[Question]: Why do we use yOff instead use the Year In DateTime? #93

Closed hasenradball closed 1 year ago

hasenradball commented 1 year ago

@awickert @IowaDave

Why do we use the yOff instead using the hole year number (e.g. 2023) in the DateTime Class? Is ist possible to switch to use the year?

I would sugest to switch to

uint16_t year

as Data member for DateTime so no year information is lost.

Or maybee better to add the full year as Data member. To be able to recalculate timesstanps in a way.

I could provide a solution.

awickert commented 1 year ago

We do this because the DS3231 holds the year in a two-byte register. (One byte per 8-bit int, so it holds two decimal integers.)

We could of course change how we instantiate it to keep year and yOff a bit more separate. Here's a bit of the constructor for reference.

DateTime::DateTime (uint16_t year, uint8_t month, uint8_t day, uint8_t hour, uint8_t min, uint8_t sec) {
    if (year >= 2000)
        year -= 2000;
    yOff = year;
hasenradball commented 1 year ago

Hi Andy thank you for the feedback.

I found that some things in the constructor could be simplyfied a bit. By using the standardized time functions.

Also I thought about the point save all members in a struct tm instead of using uint_8 variables. If using a struct you could easily use the function strftime() to print time in different formats.

How do you think about this?

https://en.cppreference.com/w/cpp/chrono/c/strftime

hasenradball commented 1 year ago

@awickert I would like to make a proposal for a refractured DateTime class which holds all values in a struct tm and the values are compatible with the standardized time functions in time.h

see an over view here. overview time functions

struct tm

So the constructors will get more cleaner than now. and from my point of view the code is easier to understand and easier to maintain.

hasenradball commented 1 year ago

@awickert just for a small example:

The one constructor which looks like this:

DateTime::DateTime (uint32_t t) {
  t -= SECONDS_FROM_1970_TO_2000;    // bring to 2000 timestamp from 1970

    ss = t % 60;
    t /= 60;
    mm = t % 60;
    t /= 60;
    hh = t % 24;
    uint16_t days = t / 24;
    uint8_t leap;
    for (yOff = 0; ; ++yOff) {
        leap = isleapYear((uint16_t) yOff);
        if (days < (uint16_t)(365 + leap))
            break;
        days -= (365 + leap);
    }
    for (m = 1; ; ++m) {
        uint8_t daysPerMonth = pgm_read_byte(daysInMonth + m - 1);
        if (leap && m == 2)
            ++daysPerMonth;
        if (days < daysPerMonth)
            break;
        days -= daysPerMonth;
    }
    d = days + 1;
}

will result in this:

DateTime::DateTime (time_t timestamp)
: _timestamp{timestamp}
{
    gmtime_r(&_timestamp, &_tm);
}

With the class declaration like:

// DateTime class restructured by using standardized time functions
class DateTime {
    public:
        DateTime (time_t timestamp = 0);

        DateTime (  uint16_t year, uint8_t month, uint8_t mday,
                    uint8_t hour = 0, uint8_t min = 0, uint8_t sec = 0
                    uint8_t wday = 0);

        DateTime (const char* date, const char* time);

        int getYear() const     { return _tm.tm_year; }
        int getMonth() const    { return _tm.tm_mon; }
        int getDay() const      { return _tm.tm_mday; }
        int getHour() const     { return _tm.tm_hour; }
        int getMinute() const   { return _tm.tm_min; }
        int getSecond() const   { return _tm.tm_sec; }
        int getWeekDay() const  { return _tm.tm_wday; }
        int getDST() const      { return _tm.tm_isdst; }

        // 32-bit times as seconds since 1/1/2000
        time_t secondstime() const;
        // 32-bit times as seconds since 1/1/1970
        // THE ABOVE COMMENT IS CORRECT FOR LOCAL TIME; TO USE THIS COMMAND TO
        // OBTAIN TRUE UNIX TIME SINCE EPOCH, YOU MUST CALL THIS COMMAND AFTER
        // SETTING YOUR CLOCK TO UTC
        time_t unixtime(void) const;
    protected:
        time_t _timestamp;
        struct tm _tm;
};
hasenradball commented 1 year ago

@awickert see PR #95