[RTC] datetimeToEpoch and epochToDatetime are no members of Rtc class

datetimeToEpoach and epochToDatetime are not dependent with any H/W. But those methods can not be used in UNO Q:

/home/arduino/works/blink/sketch/sketch.ino:184:25: error: 'class Rtc' has no member named 'datetimeToEpoch'
  184 |         timestamp = rtc.datetimeToEpoch(year, month, day, hour, minute, second) - 32400;
      |                         ^~~~~~~~~~~~~~~
/home/arduino/works/blink/sketch/sketch.ino:185:13: error: 'class Rtc' has no member named 'epochToDatetime'
  185 |         rtc.epochToDatetime(timestamp, year, month, day, hour, minute, second);
      |             ^~~~~~~~~~~~~~~

Used library         Version Path
RTC                          /home/arduino/.arduino15/packages/arduino/hardware/zephyr/0.56.0/libraries/RTC
Arduino_RouterBridge 0.4.3   /home/arduino/Arduino/libraries/Arduino_RouterBridge
Arduino_RPClite      0.3.0   /home/arduino/.arduino15/internal/Arduino_RPClite_0.3.0_66fefd6c76c3d010/Arduino_RPClite
MsgPack              0.4.2   /home/arduino/.arduino15/internal/MsgPack_0.4.2_a0d4adc5044d022c/MsgPack
DebugLog             0.8.4   /home/arduino/.arduino15/internal/DebugLog_0.8.4_c199e2cf6415ecc8/DebugLog
ArxTypeTraits        0.3.2   /home/arduino/.arduino15/internal/ArxTypeTraits_0.3.2_d65e2aabfeed7838/ArxTypeTraits
ArxContainer         0.7.0   /home/arduino/.arduino15/internal/ArxContainer_0.7.0_007f0bb2a1cdefe3/ArxContainer
SketchInfo           0.0.1   /home/arduino/Arduino/libraries/SketchInfo
ArduinoJson          7.4.3   /home/arduino/Arduino/libraries/ArduinoJson

Used platform  Version Path
arduino:zephyr 0.56.0  /home/arduino/.arduino15/packages/arduino/hardware/zephyr/0.56.0
Error during build: exit status 1

I think the more correct problem is the library I am using does not have some functions I want. As many of these functions can be accomplished several ways, either do that or use a different library.

Does this help explain what is happening?


```cpp
#if !defined(CONFIG_COUNTER_NRF_RTC) // For boards with a dedicated RTC peripheral/driver, we use
									 // the Zephyr RTC API directly
	/** @brief Pointer to the Zephyr RTC device. */
	const struct device *rtc_dev;

	/** @brief Internal static wrapper for alarm callbacks. */
	static void alarmCallbackWrapper([[maybe_unused]] const struct device *dev,
									 [[maybe_unused]] uint16_t id, void *user_data);

	/** @brief Internal static wrapper for update callbacks. */
	static void updateCallbackWrapper([[maybe_unused]] const struct device *dev, void *user_data);

	uint16_t alarmId = 0; /**< Default alarm identifier. */

#else // For boards without an RTC driver (i.e. Nordic), we must use the counter API to implement
	  // RTC functionality
	/** @brief Pointer to the Zephyr counter device used as RTC backend. */
	const struct device *counter_dev;

	/** @brief Time offset between the system counter and epoch time. */
	time_t timeOffset;

	/** @brief Counter driver alarm configuration. */
	struct counter_alarm_cfg alarm_cfg;

	/** @brief Indicates whether a counter-backed alarm is currently active. */
	bool alarmPending = false;

	/** @brief Cached alarm time for counter-backed implementations. */
	time_t alarmEpoch = 0;

	/** @brief Tracks whether setTime() has been called for CONFIG_COUNTER. */
	bool isInitialized = false;

	/** @brief Static handler for counter alarm interrupts. */
	static void alarmHandler(const struct device *dev, uint8_t chan_id, uint32_t ticks,
							 void *user_data);

	/** @brief Converts a date and time to a Unix epoch timestamp. */
	time_t datetimeToEpoch(int year, int month, int day, int hour, int minute, int second);

	/** @brief Converts a Unix epoch timestamp to a date and time. */
	void epochToDatetime(time_t t, int &year, int &month, int &day, int &hour, int &minute,
						 int &second);
#endif
```

Those functions are private to the class, so not accessible to your code. Easy enough to copy out the code and make your own functions, or use the standard time.h library to do conversions.

Ah, of course. The reason they are private is that we are not that far from the rollover date (12ish yrs), and making them private allows the epoch to be changed transparently. Anyone alive who has not planned for it will experience Y2K again, but waaaaaay worse.

The problem isn't that they're private, but that they're not defined for the Zephyr board at all. Look at the conditional compilation options as shown in post #3 by @sonofcy
If the problem was privacy, the compiler would give a different error message.

RTC.cpp and RTC.h files are modified to use datetimeToEpoch and epochToDatetime functions:

RTC.cpp

...
#include <stdio.h>

// Utility functions - local scope only
namespace {
static const int days_in_month[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

static bool is_leap(int year) {
	return (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0));
}
} // namespace

Rtc::~Rtc() {
}
...
int Rtc::getSeconds() {
	int year, month, day, hour, minute, second;
	int retVal = getTime(year, month, day, hour, minute, second);
	if (retVal == 0) {
		return second;
	}
	return -1;
}


/**
 * @brief Converts a date and time to Unix epoch seconds.
 *
 * This utility function calculates the number of seconds since
 * January 1, 1970 (the Unix epoch) for the provided date and time.
 *
 * @param year   Year value (e.g., 2025).
 * @param month  Month value (1–12).
 * @param day    Day value (1–31).
 * @param hour   Hour value (0–23).
 * @param minute Minute value (0–59).
 * @param second Second value (0–59).
 * @return Corresponding epoch time in seconds.
 */
time_t Rtc::datetimeToEpoch(int year, int month, int day, int hour, int minute, int second) {
	int y = year;
	int m = month;
	time_t days = 0;

	for (int i = 1970; i < y; i++) {
		days += is_leap(i) ? 366 : 365;
	}

	for (int i = 1; i < m; i++) {
		days += days_in_month[i - 1];
		if (i == 2 && is_leap(y)) {
			days += 1;
		}
	}

	days += (day - 1);

	return (((days * 24 + hour) * 60 + minute) * 60 + second);
}

/**
 * @brief Converts Unix epoch seconds to a date and time.
 *
 * This utility function breaks down a given epoch timestamp into a
 * human-readable calendar date and time.
 *
 * @param t       Epoch time in seconds.
 * @param year    Reference to store the year.
 * @param month   Reference to store the month.
 * @param day     Reference to store the day.
 * @param hour    Reference to store the hour.
 * @param minute  Reference to store the minute.
 * @param second  Reference to store the second.
 */
void Rtc::epochToDatetime(time_t t, int &year, int &month, int &day, int &hour, int &minute,
						  int &second) {
	time_t seconds_in_day = t % 86400;
	time_t days = t / 86400;

	hour = seconds_in_day / 3600;
	minute = (seconds_in_day % 3600) / 60;
	second = seconds_in_day % 60;

	year = 1970;
	while (true) {
		int days_in_year = is_leap(year) ? 366 : 365;
		if (days >= days_in_year) {
			days -= days_in_year;
			year++;
		} else {
			break;
		}
	}

	int m = 0;
	while (true) {
		int dim = days_in_month[m];
		if (m == 1 && is_leap(year)) {
			dim++;
		}

		if (days >= dim) {
			days -= dim;
			m++;
		} else {
			break;
		}
	}

	month = m + 1;
	day = days + 1;
}

#if !defined(CONFIG_COUNTER_NRF_RTC) // For boards with a dedicated RTC peripheral/driver, we use
									 // the Zephyr RTC
...

RTC.h

...
	int getCalibration(int32_t &calibration);

	/** @brief Converts a date and time to a Unix epoch timestamp. */
	time_t datetimeToEpoch(int year, int month, int day, int hour, int minute, int second);

	/** @brief Converts a Unix epoch timestamp to a date and time. */
	void epochToDatetime(time_t t, int &year, int &month, int &day, int &hour, int &minute,
						 int &second);

private:
	RtcAlarmCallback userAlarmCallback = nullptr; /**< User-registered alarm callback. */
	void *userAlarmCallbackData = nullptr;        /**< User data for alarm callback. */
...

sketch.ino

...
#include <vector>
#include "Arduino_RouterBridge.h"
#include "ArduinoJson.h"
#include "MsgPack.h"
#include "RTC.h"
...
typedef struct PythonDict {
    MsgPack::str_t key_time;
    int time;
    MsgPack::str_t key_datetime;
    std::vector<int> datetime;

    MSGPACK_DEFINE_MAP(key_time, time, key_datetime, datetime);
} python_dict_t;
...
const char* BUILD_TIMESTAMP = __DATE__ " " __TIME__;
Rtc rtc;
bool rtc_ready = false;
...
python_dict_t get_time_dict() {
    int year{}, month{}, day{}, hour{}, minute{}, second{};
    time_t time{};
    python_dict_t dict = {};

    if (rtc_ready) {
        rtc.getTime(year, month, day, hour, minute, second);
        time = rtc.datetimeToEpoch(year, month, day, hour, minute, second) - 32400;
    }
    dict.key_time = "time";
    dict.time = time;
    dict.key_datetime = "datetime";
    std::vector<int> datetime = {year, month, day, hour, minute, second};
    dict.datetime = datetime;

    return dict;
}

void set_time(time_t t) {
    int year{}, month{}, day{}, hour{}, minute{}, second{};
    if(rtc_ready) {
        rtc.epochToDatetime(t, year, month, day, hour, minute, second);
        rtc.setTime(year, month, day, hour, minute, second);
    }
}

void setup() {
    pinMode(LED_BUILTIN, OUTPUT);

    Serial.begin();
    Bridge.begin();

    if (!rtc.begin()) {
        Serial.println("RTC not ready!\n");
        rtc_ready = false;
    } else {
        rtc_ready = true;
    }

    Bridge.provide("get_time_dict",         get_time_dict);
    ...
    Bridge.provide("set_time",              set_time);
    ...
}

RTC.zip (8.3 KB) * without examples only RTC.cpp and RTC.h