Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

implement iso8601 TimeSpan formatting #190

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

maxbla
Copy link

@maxbla maxbla commented Aug 3, 2020

fixes #181

I ran this test. It basically tests that serializing and constructing returns the same TimeSpan that was serialized.

int main() {
    std::default_random_engine generator;
    std::uniform_int_distribution<int32_t> distribution(-2147483648, 2147483647);
    char buf[19];
    for (int i=0; i<10000000; i++) {
        int32_t seconds = distribution(generator); 
        TimeSpan t(seconds);
        t.toCharArray(buf, 19);
        TimeSpan t1(buf);
        assert(t1._seconds == t._seconds);
    }
}

I was looking for somewhere to put tests like this, but it seems like this repository doesn't really have tests.

Copy link
Contributor

@edgar-bonet edgar-bonet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few comments:

RTClib.cpp Outdated Show resolved Hide resolved
RTClib.cpp Outdated Show resolved Hide resolved
RTClib.cpp Outdated Show resolved Hide resolved
RTClib.cpp Outdated Show resolved Hide resolved
RTClib.cpp Outdated Show resolved Hide resolved
RTClib.cpp Show resolved Hide resolved
@@ -231,6 +234,9 @@ class TimeSpan {

protected:
int32_t _seconds; ///< Actual TimeSpan value is stored as seconds
static constexpr int32_t SECS_PER_MIN = 60; ///< Number of seconds in a minute
static constexpr int32_t MINS_PER_HOUR = 60; ///< Number of minutes in an hour
static constexpr int32_t HOURS_PER_DAY = 24; ///< Number of hours in a day
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would you feel about making these either global or public?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have no strong feelings either way: they certainly look like generally useful, but they are kind of trivial, and they would risk collisions in the global namespace. Maybe public would be OK. I guess you should get the opinion of a maintainer: I am just a random contributor.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a static (constexpr) global then? That way they won't cause global namespace collisions. This library as-is has the magic number antipattern. Fixing it is out of scope for this PR though.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On second thought, static constexprs won't work in this case because they are in the header. Statics in a header are textually #included, and static means limited to a "translation uint", so the constants would still be exposed in the public interface.

@maxbla maxbla mentioned this pull request Aug 4, 2020
Copy link
Contributor

@edgar-bonet edgar-bonet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking good. Some more comments:

RTClib.cpp Outdated Show resolved Hide resolved
RTClib.cpp Show resolved Hide resolved
long num = strtol(cursor, &rest, 10);
cursor = rest;
if (*cursor == 'D') {
_seconds += sign * SECONDS_PER_DAY * num;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can overflow.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it can. What should I do about it? Detect overflow, return 0 on failure, and add this failure mode to the docs?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure. It seems to me that the overflow cannot be detected without significant extra complexity. :-(

Copy link
Author

@maxbla maxbla Mar 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would you feel about using __builtin_smull_overflow? It is supported in both gcc and clang, but it's non-standard.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

__builtin_smull_overflow() looks nice, but I do not know whether it is supported by all the environments where RTClib can potentially be used.

Maybe a simple fix would be to build the absolute value of the duration as a uint32_t. That won't prevent the overflow, but at least it would avoid undefined behavior. Then, at the end of the constructor,

_seconds = sign * abs_seconds;

is guaranteed to wrap correctly to the correct signed value, as long as the result is in the range of an int32_t.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all the environments where RTClib can potentially be used

Is RTClib used outside the Arduino ecosystem? And if so, can it be used with any compiler other than Clang or GCC? (clang includes these intrinsics too)

RTClib.cpp Outdated Show resolved Hide resolved
RTClib.cpp Outdated Show resolved Hide resolved
@maxbla
Copy link
Author

maxbla commented Oct 31, 2020

What's the status of this PR? Should I do something to move it along?

@edgar-bonet
Copy link
Contributor

I guess you could solve the two issues raised by GitHub:

This pull request is still a work in progress
This branch has conflicts that must be resolved

The conflict is pretty easy to fix:

diff --cc RTClib.cpp
index e282548,2ecffb4..3a0ff37
--- a/RTClib.cpp
+++ b/RTClib.cpp
@@@ -694,8 -713,8 +713,8 @@@ bool DateTime::operator==(const DateTim
      @return Timestamp string, e.g. "2020-04-16T18:34:56".
  */
  /**************************************************************************/
 -String DateTime::timestamp(timestampOpt opt) {
 +String DateTime::timestamp(timestampOpt opt) const {
-   char buffer[20];
+   char buffer[25]; // large enough for any DateTime, including invalid ones
  
    // Generate timestamp according to opt
    switch (opt) {

I would consider rebasing on top of master, and maybe squashing the last 9 commits together.

As for the “work in progress” status, you should be able to change it to “Ready for review”, when you are ready.

@maxbla maxbla force-pushed the master branch 3 times, most recently from ac9e45a to a123854 Compare March 10, 2021 03:23
@maxbla maxbla marked this pull request as ready for review March 10, 2021 03:50
@maxbla
Copy link
Author

maxbla commented Mar 10, 2021

This PR is ready for (final) review and I have time to fix any problems identified in said review.

@maxbla maxbla force-pushed the master branch 5 times, most recently from 9f002c2 to 1dca08a Compare March 10, 2021 06:34
// At the time of writing, this is only used in logic in TimeSpan::toCharArray
// This function's inclusion is very unfortunate, and if it is used anywhere
// else, should probably use a template
static size_t sat_sub(size_t left, size_t right) {
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It feels dirty to add this function in here, but it is the cleanest way I could think to handle the repeated

if (written >= len) {
    buf[len - 1] = '\0';
    return 0;
}

Copy link
Contributor

@edgar-bonet edgar-bonet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM. I hope it gets merged, with or without my suggestions.

RTClib.cpp Outdated Show resolved Hide resolved
Uses iso 8601 period format. Includes a constructor from a string.
Makes all toString-like methods const
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support ISO 8601 Duration formatting for RTClib's TimeSpan
2 participants