Skip to content

Commit

Permalink
Adapt Datetime parser to DST timezones (#1524)
Browse files Browse the repository at this point in the history
When iOS device locale is set to location
which uses different timezeons depending on
daylight saving time (eg PST and PDT for
Los Angeles), then different `gmtoff` applied
by `strptime` for 'summer' and 'winter'
timestamps.

This results in the wrong translation of
datetime string into epoch.

Adapt code to iOS/MacOS behaviour, where
`timegm` updates an input parameter and
erases `gmtoff` value:
- remove logic to infer the offset using epoch
  datetime;
- store `gmtoff` value before calling `timegm`;
- offset result returned from `timegm` by
  saved `gmtoff`.

Relates-To: HERESDK-2568

Signed-off-by: Mykhailo Diachenko <[email protected]>
  • Loading branch information
diachenko-mischa committed Jun 20, 2024
1 parent e223f22 commit 3e8c222
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 14 deletions.
21 changes: 7 additions & 14 deletions olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ constexpr auto kDate = "date";

#ifdef _WIN32
// Windows does not have ::strptime and ::timegm
std::time_t DoParseTime(const std::string& value) {
std::time_t ParseTime(const std::string& value) {
std::tm tm = {};
std::istringstream ss(value);
ss >> std::get_time(&tm, "%a, %d %b %Y %H:%M:%S %z");
Expand All @@ -107,29 +107,22 @@ std::time_t DoParseTime(const std::string& value) {

#else

std::time_t DoParseTime(const std::string& value) {
std::time_t ParseTime(const std::string& value) {
std::tm tm = {};
const auto format = "%a, %d %b %Y %H:%M:%S %Z";
const auto parsed_until = ::strptime(value.c_str(), format, &tm);
if (parsed_until != value.c_str() + value.size()) {
OLP_SDK_LOG_WARNING(kLogTag, "Timestamp is not fully parsed" << value);
}
return timegm(&tm);
// MacOS updates `tm_isdst`, `tm_zone` and `tm_gmtoff` fields in `timegm`
// call.
const auto gmtoff = tm.tm_gmtoff;
const auto local_time = timegm(&tm);
return local_time - gmtoff;
}

#endif

std::time_t GmtEpochOffset() {
const auto epoch_as_date_time = "Thu, 1 Jan 1970 0:00:00 GMT";
return DoParseTime(epoch_as_date_time);
}

std::time_t ParseTime(const std::string& value) {
const auto time = DoParseTime(value);
const auto offset = GmtEpochOffset();
return time - offset;
}

boost::optional<std::time_t> GetTimestampFromHeaders(
const olp::http::Headers& headers) {
auto it =
Expand Down
12 changes: 12 additions & 0 deletions olp-cpp-sdk-authentication/tests/AuthenticationClientTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@

namespace {
constexpr auto kTime = "Fri, 29 May 2020 11:07:45 GMT";
constexpr auto kEpochTime = "Thu, 1 Jan 1970 00:00:00 GMT";
constexpr auto kSummerTime = "Tue, 18 Jun 2024 12:25:35 GMT";
} // namespace

namespace auth = olp::authentication;
Expand Down Expand Up @@ -237,6 +239,16 @@ TEST(AuthenticationClientTest, TimeParsing) {
SCOPED_TRACE("Parse time");
EXPECT_EQ(auth::ParseTime(kTime), 1590750465);
}

{
SCOPED_TRACE("Parse epoch time");
EXPECT_EQ(auth::ParseTime(kEpochTime), 0);
}

{
SCOPED_TRACE("Parse summer time");
EXPECT_EQ(auth::ParseTime(kSummerTime), 1718713535);
}
}

TEST(AuthenticationClientTest, GenerateAuthorizationHeader) {
Expand Down

0 comments on commit 3e8c222

Please sign in to comment.