Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

number of seconds since start of week?

Tags:

c++

date

I've been trying out Howard's date library. There are many examples for getting the number of seconds since midnight of a certain day, but not since the start of week to which the day belongs. Following the examples I produced this code:

using timepoint_t = std::chrono::time_point<
  std::chrono::system_clock,
  std::chrono::nanoseconds
>;

timepoint_t tp; // input
auto dp = std::chrono::floor<date::weeks>(tp); // output, should point to start of week?

But the results are wrong. For example, tp:

2018-10-25T11:26:00.397836134Z

will produce dp:

2018-10-25T00:00:00.000000000Z 

which is midnight of the 25th, not midnight of the 21th. What is the most direct way to produce the correct output?

like image 719
user1095108 Avatar asked Oct 25 '18 11:10

user1095108


2 Answers

I've upvoted user1095108's self answer as it gets the correct answer. But I wanted to add more information that wouldn't all fit in a comment.

The "start of the week" is not universally agreed upon. Some countries obverse Monday as the start of the week, as does the ISO standard. And other countries observe Sunday as the start of the week. This library tries to stay as neutral as possible on this issue.

Even once you nail down which weekday you're aiming for, you also need to nail down where on the planet you want to consider when finding the second the week starts.

Judging from your code, I'm going to assume:

  1. The week starts on Sunday.
  2. We want to find the start of the week according to UTC.

For the following code, assume:

using namespace date;
using namespace std::chrono;

just to keep things from getting overly verbose.

The first thing I would do is transform the input into a time_point with a precision of seconds:

auto tp = floor<seconds>(system_clock::now());

Then, in order to do weekday computations, such as finding the weekday of the input tp, one is going to need another time_point with a precision of days:

auto dp = floor<days>(tp);

You can construct a weekday directly from a day-precision time_point (dp), instead of going through the more expensive computation of forming a year_month_weekday:

weekday{dp}

then (as you show) subtract off the number of days since the start of the week:

dp -= weekday{dp} - Sunday;

Now you have two time_points: Your input, and the start of the week. You can simply subtract them to get the number of seconds into the week:

std::cout << tp - dp << '\n';

Now the reason that floor<weeks>(tp) doesn't give you the desired result is that system_clock is Unix Time. This measure counts time since 1970-01-01 00:00:00 UTC (neglecting leap seconds). And 1970-01-01 was a Thursday. So truncating a system_clock::time_point to a precision of weeks defines the "start of the week" as Thursday.

For even more fun, compute the number of seconds since the start of the week in a local time, which may involve daylight savings adjustments. In this case the computation has more than one right answer: Do you count physical seconds, which makes some weeks not have exactly 604800s, or do you count "calendrical seconds"? For example is Nov/4/2018 1:00 EST (America/New_York) 1 or 2 hours into the week? Once you decide which is the right answer, this library can compute it.

like image 57
Howard Hinnant Avatar answered Nov 05 '22 06:11

Howard Hinnant


Most of Howard's calendar calculations seem to be based off of date:days. So you're out of luck with date::weeks, it seems. One possible answer is:

auto dp(std::chrono::floor<date::days>(tp));
dp -= date::year_month_weekday(dp).weekday() - date::Sunday;

The number of seconds is then obtained as the customary std::chrono::duration_cast<std::chrono::seconds>(tp - dp).count(). Could it be the lack of support for date::weeks in std::chrono, that the date::weeks cast does not work? Howard's date::floor() gives the same output as std::chrono::floor() though.

like image 23
user1095108 Avatar answered Nov 05 '22 07:11

user1095108