summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMake/AbseilDll.cmake2
-rw-r--r--absl/base/internal/unscaledcycleclock.cc5
-rw-r--r--absl/flags/internal/usage.cc11
-rw-r--r--absl/flags/internal/usage_test.cc63
-rw-r--r--absl/numeric/int128_have_intrinsic.inc3
-rw-r--r--absl/status/CMakeLists.txt2
-rw-r--r--absl/strings/BUILD.bazel12
-rw-r--r--absl/strings/CMakeLists.txt14
-rw-r--r--absl/strings/char_formatting_test.cc189
-rw-r--r--absl/time/internal/cctz/src/time_zone_if.cc2
-rw-r--r--absl/time/internal/cctz/src/time_zone_libc.cc61
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup.cc11
-rw-r--r--absl/time/internal/cctz/src/time_zone_lookup_test.cc21
13 files changed, 332 insertions, 64 deletions
diff --git a/CMake/AbseilDll.cmake b/CMake/AbseilDll.cmake
index 624a9c99..b64f133c 100644
--- a/CMake/AbseilDll.cmake
+++ b/CMake/AbseilDll.cmake
@@ -815,6 +815,6 @@ Cflags: -I\${includedir}${PC_CFLAGS}\n")
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
-
+
add_library(absl::${_dll} ALIAS ${_dll})
endfunction()
diff --git a/absl/base/internal/unscaledcycleclock.cc b/absl/base/internal/unscaledcycleclock.cc
index b1c396c6..05e0e7ba 100644
--- a/absl/base/internal/unscaledcycleclock.cc
+++ b/absl/base/internal/unscaledcycleclock.cc
@@ -71,13 +71,12 @@ int64_t UnscaledCycleClock::Now() {
#else
int32_t tbu, tbl, tmp;
asm volatile(
- "0:\n"
"mftbu %[hi32]\n"
"mftb %[lo32]\n"
"mftbu %[tmp]\n"
"cmpw %[tmp],%[hi32]\n"
- "bne 0b\n"
- : [ hi32 ] "=r"(tbu), [ lo32 ] "=r"(tbl), [ tmp ] "=r"(tmp));
+ "bne $-16\n" // Retry on failure.
+ : [hi32] "=r"(tbu), [lo32] "=r"(tbl), [tmp] "=r"(tmp));
return (static_cast<int64_t>(tbu) << 32) | tbl;
#endif
#endif
diff --git a/absl/flags/internal/usage.cc b/absl/flags/internal/usage.cc
index 6a56fce9..13852e14 100644
--- a/absl/flags/internal/usage.cc
+++ b/absl/flags/internal/usage.cc
@@ -92,8 +92,16 @@ class XMLElement {
case '>':
out << "&gt;";
break;
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\t':
+ out << " ";
+ break;
default:
- out << c;
+ if (IsValidXmlCharacter(static_cast<unsigned char>(c))) {
+ out << c;
+ }
break;
}
}
@@ -102,6 +110,7 @@ class XMLElement {
}
private:
+ static bool IsValidXmlCharacter(unsigned char c) { return c >= 0x20; }
absl::string_view tag_;
absl::string_view txt_;
};
diff --git a/absl/flags/internal/usage_test.cc b/absl/flags/internal/usage_test.cc
index c3ab4a42..6847386f 100644
--- a/absl/flags/internal/usage_test.cc
+++ b/absl/flags/internal/usage_test.cc
@@ -39,6 +39,8 @@ ABSL_FLAG(double, usage_reporting_test_flag_03, 1.03,
"usage_reporting_test_flag_03 help message");
ABSL_FLAG(int64_t, usage_reporting_test_flag_04, 1000000000000004L,
"usage_reporting_test_flag_04 help message");
+ABSL_FLAG(std::string, usage_reporting_test_flag_07, "\r\n\f\v\a\b\t ",
+ "usage_reporting_test_flag_07 help \r\n\f\v\a\b\t ");
static const char kTestUsageMessage[] = "Custom usage message";
@@ -203,8 +205,12 @@ TEST_F(UsageReportingTest, TestFlagsHelpHRF) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -267,8 +273,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kShort);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -285,8 +292,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helpshort) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -301,8 +312,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kImportant);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -319,8 +331,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_simple) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -361,8 +377,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kMatch);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -379,8 +396,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_help_multiple_flag) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -395,8 +416,9 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
std::stringstream test_buf;
EXPECT_EQ(flags::HandleUsageFlags(test_buf, kTestUsageMessage),
flags::HelpMode::kPackage);
- EXPECT_EQ(test_buf.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -413,8 +435,12 @@ TEST_F(UsageReportingTest, TestUsageFlag_helppackage) {
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
@@ -471,8 +497,9 @@ path.
std::stringstream test_buf_02;
EXPECT_EQ(flags::HandleUsageFlags(test_buf_02, kTestUsageMessage),
flags::HelpMode::kMatch);
- EXPECT_EQ(test_buf_02.str(),
- R"(usage_test: Custom usage message
+ EXPECT_EQ(
+ test_buf_02.str(),
+ R"(usage_test: Custom usage message
Flags from absl/flags/internal/usage_test.cc:
--usage_reporting_test_flag_01 (usage_reporting_test_flag_01 help message);
@@ -489,8 +516,12 @@ path.
Some more help.
Even more long long long long long long long long long long long long help
- message.); default: "";
+ message.); default: "";)"
+
+ "\n --usage_reporting_test_flag_07 (usage_reporting_test_flag_07 "
+ "help\n\n \f\v\a\b ); default: \"\r\n\f\v\a\b\t \";\n"
+ R"(
Try --helpfull to get a list of all flags or --help=substring shows help for
flags which include specified substring in either in the name, or description or
path.
diff --git a/absl/numeric/int128_have_intrinsic.inc b/absl/numeric/int128_have_intrinsic.inc
index 3945fa29..6f1ac644 100644
--- a/absl/numeric/int128_have_intrinsic.inc
+++ b/absl/numeric/int128_have_intrinsic.inc
@@ -162,9 +162,6 @@ inline int128::operator long double() const {
}
#else // Clang on PowerPC
-// Forward declaration for conversion operators to floating point types.
-constexpr int128 operator-(int128 v);
-constexpr bool operator!=(int128 lhs, int128 rhs);
inline int128::operator float() const {
// We must convert the absolute value and then negate as needed, because
diff --git a/absl/status/CMakeLists.txt b/absl/status/CMakeLists.txt
index 15db36af..4a3c5d68 100644
--- a/absl/status/CMakeLists.txt
+++ b/absl/status/CMakeLists.txt
@@ -25,6 +25,8 @@ absl_cc_library(
"status_payload_printer.cc"
COPTS
${ABSL_DEFAULT_COPTS}
+ DEFINES
+ "$<$<PLATFORM_ID:AIX>:_LINUX_SOURCE_COMPAT>"
DEPS
absl::atomic_hook
absl::config
diff --git a/absl/strings/BUILD.bazel b/absl/strings/BUILD.bazel
index bd33c533..4a111b5a 100644
--- a/absl/strings/BUILD.bazel
+++ b/absl/strings/BUILD.bazel
@@ -1319,3 +1319,15 @@ cc_binary(
"//absl/types:optional",
],
)
+
+cc_test(
+ name = "char_formatting_test",
+ srcs = [
+ "char_formatting_test.cc",
+ ],
+ deps = [
+ ":str_format",
+ ":strings",
+ "@com_google_googletest//:gtest_main",
+ ],
+)
diff --git a/absl/strings/CMakeLists.txt b/absl/strings/CMakeLists.txt
index 9aaa7932..2ad052a3 100644
--- a/absl/strings/CMakeLists.txt
+++ b/absl/strings/CMakeLists.txt
@@ -548,6 +548,20 @@ absl_cc_test(
GTest::gmock_main
)
+absl_cc_test(
+ NAME
+ char_formatting_test
+ SRCS
+ "char_formatting_test.cc"
+ COPTS
+ ${ABSL_TEST_COPTS}
+ DEPS
+ absl::base
+ absl::str_format
+ absl::strings
+ GTest::gmock_main
+)
+
# Internal-only target, do not depend on directly.
absl_cc_library(
NAME
diff --git a/absl/strings/char_formatting_test.cc b/absl/strings/char_formatting_test.cc
new file mode 100644
index 00000000..60416af3
--- /dev/null
+++ b/absl/strings/char_formatting_test.cc
@@ -0,0 +1,189 @@
+// Copyright 2023 The Abseil Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <cstddef>
+
+#include "gtest/gtest.h"
+#include "absl/strings/str_cat.h"
+#include "absl/strings/str_format.h"
+#include "absl/strings/substitute.h"
+
+namespace {
+
+TEST(CharFormatting, Char) {
+ const char v = 'A';
+
+ // Desired behavior: does not compile:
+ // EXPECT_EQ(absl::StrCat(v, "B"), "AB");
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "AB");
+
+ // Legacy behavior: format as char:
+ EXPECT_EQ(absl::Substitute("$0B", v), "AB");
+}
+
+enum CharEnum : char {};
+TEST(CharFormatting, CharEnum) {
+ auto v = static_cast<CharEnum>('A');
+
+ // Desired behavior: format as decimal
+ // (No APIs do this today.)
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrCat(ch, "B"), "AB");
+
+ // Legacy behavior: format as character:
+
+ // Some older versions of gcc behave differently in this one case.
+#if !defined(__GNUC__) || defined(__clang__)
+ EXPECT_EQ(absl::Substitute("$0B", v), "AB");
+#endif
+}
+
+enum class CharEnumClass: char {};
+TEST(CharFormatting, CharEnumClass) {
+ auto v = static_cast<CharEnumClass>('A');
+
+ // Desired behavior: format as decimal
+ // (No APIs do this today.)
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrCat(ch, "B"), "AB");
+
+ // Legacy behavior: format as character:
+ EXPECT_EQ(absl::Substitute("$0B", v), "AB");
+}
+
+TEST(CharFormatting, UnsignedChar) {
+ const unsigned char v = 'A';
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "65B");
+
+ // Signedness check
+ const unsigned char w = 255;
+ EXPECT_EQ(absl::StrCat(w, "B"), "255B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "255B");
+}
+
+TEST(CharFormatting, SignedChar) {
+ const signed char v = 'A';
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // Legacy behavior: does not compile:
+ // EXPECT_EQ(absl::StrFormat("%vB", v), "AB");
+
+ // Signedness check
+ const signed char w = -128;
+ EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+}
+
+enum UnsignedCharEnum : unsigned char {};
+TEST(CharFormatting, UnsignedCharEnum) {
+ auto v = static_cast<UnsignedCharEnum>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<UnsignedCharEnum>(255);
+ EXPECT_EQ(absl::StrCat(w, "B"), "255B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+}
+
+enum SignedCharEnum : signed char {};
+TEST(CharFormatting, SignedCharEnum) {
+ auto v = static_cast<SignedCharEnum>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<SignedCharEnum>(-128);
+ EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+}
+
+enum class UnsignedCharEnumClass : unsigned char {};
+TEST(CharFormatting, UnsignedCharEnumClass) {
+ auto v = static_cast<UnsignedCharEnumClass>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<UnsignedCharEnumClass>(255);
+ EXPECT_EQ(absl::StrCat(w, "B"), "255B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "255B");
+}
+
+enum SignedCharEnumClass : signed char {};
+TEST(CharFormatting, SignedCharEnumClass) {
+ auto v = static_cast<SignedCharEnumClass>('A');
+
+ // Desired behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Signedness check
+ auto w = static_cast<SignedCharEnumClass>(-128);
+ EXPECT_EQ(absl::StrCat(w, "B"), "-128B");
+ EXPECT_EQ(absl::Substitute("$0B", w), "-128B");
+}
+
+#ifdef __cpp_lib_byte
+TEST(CharFormatting, StdByte) {
+ auto v = static_cast<std::byte>('A');
+ // Desired behavior: format as 0xff
+ // (No APIs do this today.)
+
+ // BUG: internally fails
+ EXPECT_EQ(absl::StrFormat("%vB", v), "");
+
+ // Legacy behavior: format as decimal:
+ EXPECT_EQ(absl::StrCat(v, "B"), "65B");
+ EXPECT_EQ(absl::Substitute("$0B", v), "65B");
+}
+#endif // _cpp_lib_byte
+
+} // namespace
diff --git a/absl/time/internal/cctz/src/time_zone_if.cc b/absl/time/internal/cctz/src/time_zone_if.cc
index 0319b2f9..1d44dde7 100644
--- a/absl/time/internal/cctz/src/time_zone_if.cc
+++ b/absl/time/internal/cctz/src/time_zone_if.cc
@@ -26,6 +26,8 @@ namespace cctz {
std::unique_ptr<TimeZoneIf> TimeZoneIf::Load(const std::string& name) {
// Support "libc:localtime" and "libc:*" to access the legacy
// localtime and UTC support respectively from the C library.
+ // NOTE: The "libc:*" zones are internal, test-only interfaces, and
+ // are subject to change/removal without notice. Do not use them.
if (name.compare(0, 5, "libc:") == 0) {
return std::unique_ptr<TimeZoneIf>(new TimeZoneLibC(name.substr(5)));
}
diff --git a/absl/time/internal/cctz/src/time_zone_libc.cc b/absl/time/internal/cctz/src/time_zone_libc.cc
index 887dd097..af9f063e 100644
--- a/absl/time/internal/cctz/src/time_zone_libc.cc
+++ b/absl/time/internal/cctz/src/time_zone_libc.cc
@@ -125,31 +125,30 @@ inline std::tm* local_time(const std::time_t* timep, std::tm* result) {
#endif
}
-// Converts a civil second and "dst" flag into a time_t and UTC offset.
+// Converts a civil second and "dst" flag into a time_t and a struct tm.
// Returns false if time_t cannot represent the requested civil second.
// Caller must have already checked that cs.year() will fit into a tm_year.
-bool make_time(const civil_second& cs, int is_dst, std::time_t* t, int* off) {
- std::tm tm;
- tm.tm_year = static_cast<int>(cs.year() - year_t{1900});
- tm.tm_mon = cs.month() - 1;
- tm.tm_mday = cs.day();
- tm.tm_hour = cs.hour();
- tm.tm_min = cs.minute();
- tm.tm_sec = cs.second();
- tm.tm_isdst = is_dst;
- *t = std::mktime(&tm);
+bool make_time(const civil_second& cs, int is_dst, std::time_t* t,
+ std::tm* tm) {
+ tm->tm_year = static_cast<int>(cs.year() - year_t{1900});
+ tm->tm_mon = cs.month() - 1;
+ tm->tm_mday = cs.day();
+ tm->tm_hour = cs.hour();
+ tm->tm_min = cs.minute();
+ tm->tm_sec = cs.second();
+ tm->tm_isdst = is_dst;
+ *t = std::mktime(tm);
if (*t == std::time_t{-1}) {
std::tm tm2;
const std::tm* tmp = local_time(t, &tm2);
- if (tmp == nullptr || tmp->tm_year != tm.tm_year ||
- tmp->tm_mon != tm.tm_mon || tmp->tm_mday != tm.tm_mday ||
- tmp->tm_hour != tm.tm_hour || tmp->tm_min != tm.tm_min ||
- tmp->tm_sec != tm.tm_sec) {
+ if (tmp == nullptr || tmp->tm_year != tm->tm_year ||
+ tmp->tm_mon != tm->tm_mon || tmp->tm_mday != tm->tm_mday ||
+ tmp->tm_hour != tm->tm_hour || tmp->tm_min != tm->tm_min ||
+ tmp->tm_sec != tm->tm_sec) {
// A true error (not just one second before the epoch).
return false;
}
}
- *off = static_cast<int>(tm_gmtoff(tm));
return true;
}
@@ -254,33 +253,37 @@ time_zone::civil_lookup TimeZoneLibC::MakeTime(const civil_second& cs) const {
// We probe with "is_dst" values of 0 and 1 to try to distinguish unique
// civil seconds from skipped or repeated ones. This is not always possible
// however, as the "dst" flag does not change over some offset transitions.
- // We are also subject to the vagaries of mktime() implementations.
+ // We are also subject to the vagaries of mktime() implementations. For
+ // example, some implementations treat "tm_isdst" as a demand (useless),
+ // and some as a disambiguator (useful).
std::time_t t0, t1;
- int offset0, offset1;
- if (make_time(cs, 0, &t0, &offset0) && make_time(cs, 1, &t1, &offset1)) {
- if (t0 == t1) {
+ std::tm tm0, tm1;
+ if (make_time(cs, 0, &t0, &tm0) && make_time(cs, 1, &t1, &tm1)) {
+ if (tm0.tm_isdst == tm1.tm_isdst) {
// The civil time was singular (pre == trans == post).
- const time_point<seconds> tp = FromUnixSeconds(t0);
+ const time_point<seconds> tp = FromUnixSeconds(tm0.tm_isdst ? t1 : t0);
return {time_zone::civil_lookup::UNIQUE, tp, tp, tp};
}
- if (t0 > t1) {
+ int offset = tm_gmtoff(tm0);
+ if (t0 < t1) { // negative DST
std::swap(t0, t1);
- std::swap(offset0, offset1);
+ offset = tm_gmtoff(tm1);
}
- const std::time_t tt = find_trans(t0, t1, offset1);
+
+ const std::time_t tt = find_trans(t1, t0, offset);
const time_point<seconds> trans = FromUnixSeconds(tt);
- if (offset0 < offset1) {
+ if (tm0.tm_isdst) {
// The civil time did not exist (pre >= trans > post).
- const time_point<seconds> pre = FromUnixSeconds(t1);
- const time_point<seconds> post = FromUnixSeconds(t0);
+ const time_point<seconds> pre = FromUnixSeconds(t0);
+ const time_point<seconds> post = FromUnixSeconds(t1);
return {time_zone::civil_lookup::SKIPPED, pre, trans, post};
}
// The civil time was ambiguous (pre < trans <= post).
- const time_point<seconds> pre = FromUnixSeconds(t0);
- const time_point<seconds> post = FromUnixSeconds(t1);
+ const time_point<seconds> pre = FromUnixSeconds(t1);
+ const time_point<seconds> post = FromUnixSeconds(t0);
return {time_zone::civil_lookup::REPEATED, pre, trans, post};
}
diff --git a/absl/time/internal/cctz/src/time_zone_lookup.cc b/absl/time/internal/cctz/src/time_zone_lookup.cc
index 68084ce2..9a30ba5e 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup.cc
@@ -148,11 +148,12 @@ std::string win32_local_time_zone(const HMODULE combase) {
UINT32 wlen;
const PCWSTR tz_wstr = windows_get_string_raw_buffer(tz_hstr, &wlen);
if (tz_wstr) {
- const int size = WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, nullptr,
- 0, nullptr, nullptr);
- result.resize(size);
- WideCharToMultiByte(CP_UTF8, 0, tz_wstr, wlen, &result[0], size, nullptr,
- nullptr);
+ const int size =
+ WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
+ nullptr, 0, nullptr, nullptr);
+ result.resize(static_cast<size_t>(size));
+ WideCharToMultiByte(CP_UTF8, 0, tz_wstr, static_cast<int>(wlen),
+ &result[0], size, nullptr, nullptr);
}
windows_delete_string(tz_hstr);
}
diff --git a/absl/time/internal/cctz/src/time_zone_lookup_test.cc b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
index 4b093b37..38f10f48 100644
--- a/absl/time/internal/cctz/src/time_zone_lookup_test.cc
+++ b/absl/time/internal/cctz/src/time_zone_lookup_test.cc
@@ -1034,16 +1034,16 @@ TEST(MakeTime, SysSecondsLimits) {
const time_zone cut = LoadZone("libc:UTC");
const year_t max_tm_year = year_t{std::numeric_limits<int>::max()} + 1900;
tp = convert(civil_second(max_tm_year, 12, 31, 23, 59, 59), cut);
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
- // The BSD gmtime_r() fails on extreme positive tm_year values.
+#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__EMSCRIPTEN__)
+ // Some gmtime_r() impls fail on extreme positive values.
#else
EXPECT_EQ("2147485547-12-31T23:59:59+00:00",
absl::time_internal::cctz::format(RFC3339, tp, cut));
#endif
const year_t min_tm_year = year_t{std::numeric_limits<int>::min()} + 1900;
tp = convert(civil_second(min_tm_year, 1, 1, 0, 0, 0), cut);
-#if defined(__Fuchsia__)
- // Fuchsia's gmtime_r() fails on extreme negative values (fxbug.dev/78527).
+#if defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+ // Some gmtime_r() impls fail on extreme negative values (fxbug.dev/78527).
#else
EXPECT_EQ("-2147481748-01-01T00:00:00+00:00",
absl::time_internal::cctz::format(RFC3339, tp, cut));
@@ -1072,7 +1072,7 @@ TEST(MakeTime, LocalTimeLibC) {
tp = zi.lookup(transition.to).trans) {
const auto fcl = zi.lookup(transition.from);
const auto tcl = zi.lookup(transition.to);
- civil_second cs; // compare cs in zi and lc
+ civil_second cs, us; // compare cs and us in zi and lc
if (fcl.kind == time_zone::civil_lookup::UNIQUE) {
if (tcl.kind == time_zone::civil_lookup::UNIQUE) {
// Both unique; must be an is_dst or abbr change.
@@ -1088,12 +1088,14 @@ TEST(MakeTime, LocalTimeLibC) {
}
ASSERT_EQ(time_zone::civil_lookup::REPEATED, tcl.kind);
cs = transition.to;
+ us = transition.from;
} else {
ASSERT_EQ(time_zone::civil_lookup::UNIQUE, tcl.kind);
ASSERT_EQ(time_zone::civil_lookup::SKIPPED, fcl.kind);
cs = transition.from;
+ us = transition.to;
}
- if (cs.year() > 2037) break; // limit test time (and to 32-bit time_t)
+ if (us.year() > 2037) break; // limit test time (and to 32-bit time_t)
const auto cl_zi = zi.lookup(cs);
if (zi.lookup(cl_zi.pre).is_dst == zi.lookup(cl_zi.post).is_dst) {
// The "libc" implementation cannot correctly classify transitions
@@ -1125,6 +1127,13 @@ TEST(MakeTime, LocalTimeLibC) {
EXPECT_EQ(cl_zi.pre, cl_lc.pre);
EXPECT_EQ(cl_zi.trans, cl_lc.trans);
EXPECT_EQ(cl_zi.post, cl_lc.post);
+ const auto ucl_zi = zi.lookup(us);
+ const auto ucl_lc = lc.lookup(us);
+ SCOPED_TRACE(testing::Message() << "For " << us << " in " << *np);
+ EXPECT_EQ(ucl_zi.kind, ucl_lc.kind);
+ EXPECT_EQ(ucl_zi.pre, ucl_lc.pre);
+ EXPECT_EQ(ucl_zi.trans, ucl_lc.trans);
+ EXPECT_EQ(ucl_zi.post, ucl_lc.post);
}
}
if (ep == nullptr) {