Skip to content

Commit 3e8c222

Browse files
Adapt Datetime parser to DST timezones (#1524)
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]>
1 parent e223f22 commit 3e8c222

File tree

2 files changed

+19
-14
lines changed

2 files changed

+19
-14
lines changed

olp-cpp-sdk-authentication/src/AuthenticationClientUtils.cpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ constexpr auto kDate = "date";
9898

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

108108
#else
109109

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

120124
#endif
121125

122-
std::time_t GmtEpochOffset() {
123-
const auto epoch_as_date_time = "Thu, 1 Jan 1970 0:00:00 GMT";
124-
return DoParseTime(epoch_as_date_time);
125-
}
126-
127-
std::time_t ParseTime(const std::string& value) {
128-
const auto time = DoParseTime(value);
129-
const auto offset = GmtEpochOffset();
130-
return time - offset;
131-
}
132-
133126
boost::optional<std::time_t> GetTimestampFromHeaders(
134127
const olp::http::Headers& headers) {
135128
auto it =

olp-cpp-sdk-authentication/tests/AuthenticationClientTest.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@
2929

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

3436
namespace auth = olp::authentication;
@@ -237,6 +239,16 @@ TEST(AuthenticationClientTest, TimeParsing) {
237239
SCOPED_TRACE("Parse time");
238240
EXPECT_EQ(auth::ParseTime(kTime), 1590750465);
239241
}
242+
243+
{
244+
SCOPED_TRACE("Parse epoch time");
245+
EXPECT_EQ(auth::ParseTime(kEpochTime), 0);
246+
}
247+
248+
{
249+
SCOPED_TRACE("Parse summer time");
250+
EXPECT_EQ(auth::ParseTime(kSummerTime), 1718713535);
251+
}
240252
}
241253

242254
TEST(AuthenticationClientTest, GenerateAuthorizationHeader) {

0 commit comments

Comments
 (0)