cplusplus / nbballot

Handling of NB comments in response to ballots
14 stars 4 forks source link

GB336 27.07.4 Remove gps_clock #332

Closed wg21bot closed 4 years ago

wg21bot commented 4 years ago

Use of specific clocks may create expectations that are not delivered (GPS) The "gps" clock has nothing to do with the GNSS service known as GPS except for sharing a common anchor point (epoch) there is no calibration, no feed, no expectation that the "clock" correlates to GPS data streams. It seems a very niche use and given some of the other issues around its interpretation I would suggest it is removed.

Proposed change: delete gps_clock

HowardHinnant commented 4 years ago

I strongly object.

Implementations are allowed but not required to get gps_clock::now() from a GPS receiver.

gps_clock provides a unique mapping to the civil calendar in its formatting that other clocks to not share. gps_clock currently reports a civil time that is 18s ahead of system_clock and utc_clock. And it correctly reports a physical time difference between two time_points straddling a leap second insertion (unlike system_clock but like utc_clock).

The main observable difference between gps_clock and utc_clock is its mapping to the civil calendar. This mapping never has 61 seconds in a minute.

Example code:

    #include <chrono>
    #include <iostream>

    int
    main()
    {
        using namespace std;
        using namespace std::chrono;
        auto now_sys = floor<seconds>(system_clock::now());
        auto now_utc = clock_cast<utc_clock>(now_sys);
        auto now_gps = clock_cast<gps_clock>(now_sys);
        cout << "now_sys = " << now_sys << '\n';
        cout << "now_utc = " << now_utc << '\n';
        cout << "now_gps = " << now_gps << '\n';
    }

Example output:

    now_sys = 2019-10-25 16:54:30
    now_utc = 2019-10-25 16:54:30
    now_gps = 2019-10-25 16:54:48

Implementations are allowed but not required to get gps_clock::now() from a GPS receiver. Whether they do or not, the example output above will have similar behavior. And this functionality can reduce the possibility of confusing errors when a programmer has to deal with mapping GPS time points to and from civil time.

nhorlock commented 4 years ago

I'm still unclear as to the actual real-world use, i.e. where would a user expect to get a GPS timepoint from? In this use case are we assuming a normalised GPS timepoint that is independent of the rollover behaviour? GPS rollover is "relatively" frequent so the epoch has short cycles and this is not really supported. I guess my question is, what does a gps_clock timepoint assume and how does that correlate to actual gps feeds (note that normalising may be the only correct behaviour here as different generations of GPS satellites have larger counters and thus different rollover behaviour.)

HowardHinnant commented 4 years ago

Let's just assume that a client has a GPS feed, not necessarily live, possibly on file, and knows that the rollover is 1024 weeks. Somehow he has to know or be fed the rollover data (rollover size and count). Here is how he could take the raw data, map it to a civil time not adjusted by leap seconds (the GPS mapping), then convert it to UTC, then convert it back to gps_time, then recover the initial GPS feed data:

#include <chrono>
#include <iostream>

int
main()
{
    using namespace std;
    using namespace std::chrono;

    // Helpful duration types
    using Tow = duration<int, ratio<3, 2>>;
    using Frame = duration<int, ratio_multiply<weeks::period, ratio<1'024>>>;

    // GPS feed data in integral form
    int week_count = 30;
    int tow_count = 147'105;
    int frame_count = 2;

    // Form a gps_time and print out its mapping to the civil calendar
    auto tp_gps = gps_seconds{weeks{week_count}} + Tow{tow_count} + Frame{frame_count};
    cout << tp_gps << " GPS\n";

    // Convert to UTC and print that out
    auto tp_utc = clock_cast<utc_clock>(tp_gps);
    cout << tp_utc << " UTC\n";

    // Convert back to gps_time and recover the feed data
    tp_gps = clock_cast<gps_clock>(tp_utc);
    auto d_gps = tp_gps.time_since_epoch();
    auto frame = duration_cast<Frame>(d_gps);
    d_gps -= frame;
    auto week = duration_cast<weeks>(d_gps);
    d_gps -= week;
    auto tow = duration_cast<Tow>(d_gps);
    cout << "frame = " << frame.count() << " week = " << week.count()
         << " tow = " << tow.count() << '\n';
}

The output of the program above is:

2019-11-05 13:17:37.5 GPS
2019-11-05 13:17:19.5 UTC
frame = 2 week = 30 tow = 147105

I assert that this is useful functionality. Note that the feed could be live, or be historical data. One might start with the feed and need the UTC time point. Or one might start with the UTC time point and need the feed data.

One might only want the elapsed time since the GPS epoch, which in this example is an intermediate result.

One might want the elapsed time between two GPS feeds.

One might have a large program with both UTC time points and GPS time points and desire the compile-time type-safety that chrono affords to keep from accidentally mixing these two families of time points in an expression (e.g. subtracting a GPS time point from a UTC time point).

peter-b commented 4 years ago

I agree that there is a compelling use-case for gps_time. The concerns expressed in the national body comment (I am not the author) seem to revolve around the time returned by gps_clock::now().

Rather than rejecting this national body comment, perhaps it would increase consensus to either:

tituswinters commented 4 years ago

LEWG in Belfast: Rejected. No consensus for change.