format_test.cc (16758B)
1 // Copyright 2017 The Abseil Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // https://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include <cstdint> 16 #include <limits> 17 #include <string> 18 19 #include "gmock/gmock.h" 20 #include "gtest/gtest.h" 21 #include "absl/time/internal/test_util.h" 22 #include "absl/time/time.h" 23 24 using testing::HasSubstr; 25 26 namespace { 27 28 // A helper that tests the given format specifier by itself, and with leading 29 // and trailing characters. For example: TestFormatSpecifier(t, "%a", "Thu"). 30 void TestFormatSpecifier(absl::Time t, absl::TimeZone tz, 31 const std::string& fmt, const std::string& ans) { 32 EXPECT_EQ(ans, absl::FormatTime(fmt, t, tz)); 33 EXPECT_EQ("xxx " + ans, absl::FormatTime("xxx " + fmt, t, tz)); 34 EXPECT_EQ(ans + " yyy", absl::FormatTime(fmt + " yyy", t, tz)); 35 EXPECT_EQ("xxx " + ans + " yyy", 36 absl::FormatTime("xxx " + fmt + " yyy", t, tz)); 37 } 38 39 // 40 // Testing FormatTime() 41 // 42 43 TEST(FormatTime, Basics) { 44 absl::TimeZone tz = absl::UTCTimeZone(); 45 absl::Time t = absl::FromTimeT(0); 46 47 // Starts with a couple basic edge cases. 48 EXPECT_EQ("", absl::FormatTime("", t, tz)); 49 EXPECT_EQ(" ", absl::FormatTime(" ", t, tz)); 50 EXPECT_EQ(" ", absl::FormatTime(" ", t, tz)); 51 EXPECT_EQ("xxx", absl::FormatTime("xxx", t, tz)); 52 std::string big(128, 'x'); 53 EXPECT_EQ(big, absl::FormatTime(big, t, tz)); 54 // Cause the 1024-byte buffer to grow. 55 std::string bigger(100000, 'x'); 56 EXPECT_EQ(bigger, absl::FormatTime(bigger, t, tz)); 57 58 t += absl::Hours(13) + absl::Minutes(4) + absl::Seconds(5); 59 t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8); 60 EXPECT_EQ("1970-01-01", absl::FormatTime("%Y-%m-%d", t, tz)); 61 EXPECT_EQ("13:04:05", absl::FormatTime("%H:%M:%S", t, tz)); 62 EXPECT_EQ("13:04:05.006", absl::FormatTime("%H:%M:%E3S", t, tz)); 63 EXPECT_EQ("13:04:05.006007", absl::FormatTime("%H:%M:%E6S", t, tz)); 64 EXPECT_EQ("13:04:05.006007008", absl::FormatTime("%H:%M:%E9S", t, tz)); 65 } 66 67 TEST(FormatTime, LocaleSpecific) { 68 const absl::TimeZone tz = absl::UTCTimeZone(); 69 absl::Time t = absl::FromTimeT(0); 70 71 TestFormatSpecifier(t, tz, "%a", "Thu"); 72 TestFormatSpecifier(t, tz, "%A", "Thursday"); 73 TestFormatSpecifier(t, tz, "%b", "Jan"); 74 TestFormatSpecifier(t, tz, "%B", "January"); 75 76 // %c should at least produce the numeric year and time-of-day. 77 const std::string s = 78 absl::FormatTime("%c", absl::FromTimeT(0), absl::UTCTimeZone()); 79 EXPECT_THAT(s, HasSubstr("1970")); 80 EXPECT_THAT(s, HasSubstr("00:00:00")); 81 82 TestFormatSpecifier(t, tz, "%p", "AM"); 83 TestFormatSpecifier(t, tz, "%x", "01/01/70"); 84 TestFormatSpecifier(t, tz, "%X", "00:00:00"); 85 } 86 87 TEST(FormatTime, ExtendedSeconds) { 88 const absl::TimeZone tz = absl::UTCTimeZone(); 89 90 // No subseconds. 91 absl::Time t = absl::FromTimeT(0) + absl::Seconds(5); 92 EXPECT_EQ("05", absl::FormatTime("%E*S", t, tz)); 93 EXPECT_EQ("05.000000000000000", absl::FormatTime("%E15S", t, tz)); 94 95 // With subseconds. 96 t += absl::Milliseconds(6) + absl::Microseconds(7) + absl::Nanoseconds(8); 97 EXPECT_EQ("05.006007008", absl::FormatTime("%E*S", t, tz)); 98 EXPECT_EQ("05", absl::FormatTime("%E0S", t, tz)); 99 EXPECT_EQ("05.006007008000000", absl::FormatTime("%E15S", t, tz)); 100 101 // Times before the Unix epoch. 102 t = absl::FromUnixMicros(-1); 103 EXPECT_EQ("1969-12-31 23:59:59.999999", 104 absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); 105 106 // Here is a "%E*S" case we got wrong for a while. While the first 107 // instant below is correctly rendered as "...:07.333304", the second 108 // one used to appear as "...:07.33330499999999999". 109 t = absl::FromUnixMicros(1395024427333304); 110 EXPECT_EQ("2014-03-17 02:47:07.333304", 111 absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); 112 t += absl::Microseconds(1); 113 EXPECT_EQ("2014-03-17 02:47:07.333305", 114 absl::FormatTime("%Y-%m-%d %H:%M:%E*S", t, tz)); 115 } 116 117 TEST(FormatTime, RFC1123FormatPadsYear) { // locale specific 118 absl::TimeZone tz = absl::UTCTimeZone(); 119 120 // A year of 77 should be padded to 0077. 121 absl::Time t = absl::FromCivil(absl::CivilSecond(77, 6, 28, 9, 8, 7), tz); 122 EXPECT_EQ("Mon, 28 Jun 0077 09:08:07 +0000", 123 absl::FormatTime(absl::RFC1123_full, t, tz)); 124 EXPECT_EQ("28 Jun 0077 09:08:07 +0000", 125 absl::FormatTime(absl::RFC1123_no_wday, t, tz)); 126 } 127 128 TEST(FormatTime, InfiniteTime) { 129 absl::TimeZone tz = absl::time_internal::LoadTimeZone("America/Los_Angeles"); 130 131 // The format and timezone are ignored. 132 EXPECT_EQ("infinite-future", 133 absl::FormatTime("%H:%M blah", absl::InfiniteFuture(), tz)); 134 EXPECT_EQ("infinite-past", 135 absl::FormatTime("%H:%M blah", absl::InfinitePast(), tz)); 136 } 137 138 // 139 // Testing ParseTime() 140 // 141 142 TEST(ParseTime, Basics) { 143 absl::Time t = absl::FromTimeT(1234567890); 144 std::string err; 145 146 // Simple edge cases. 147 EXPECT_TRUE(absl::ParseTime("", "", &t, &err)) << err; 148 EXPECT_EQ(absl::UnixEpoch(), t); // everything defaulted 149 EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err; 150 EXPECT_TRUE(absl::ParseTime(" ", " ", &t, &err)) << err; 151 EXPECT_TRUE(absl::ParseTime("x", "x", &t, &err)) << err; 152 EXPECT_TRUE(absl::ParseTime("xxx", "xxx", &t, &err)) << err; 153 154 EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", 155 "2013-06-28 19:08:09 -0800", &t, &err)) 156 << err; 157 const auto ci = absl::FixedTimeZone(-8 * 60 * 60).At(t); 158 EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); 159 EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); 160 } 161 162 TEST(ParseTime, NullErrorString) { 163 absl::Time t; 164 EXPECT_FALSE(absl::ParseTime("%Q", "invalid format", &t, nullptr)); 165 EXPECT_FALSE(absl::ParseTime("%H", "12 trailing data", &t, nullptr)); 166 EXPECT_FALSE( 167 absl::ParseTime("%H out of range", "42 out of range", &t, nullptr)); 168 } 169 170 TEST(ParseTime, WithTimeZone) { 171 const absl::TimeZone tz = 172 absl::time_internal::LoadTimeZone("America/Los_Angeles"); 173 absl::Time t; 174 std::string e; 175 176 // We can parse a string without a UTC offset if we supply a timezone. 177 EXPECT_TRUE( 178 absl::ParseTime("%Y-%m-%d %H:%M:%S", "2013-06-28 19:08:09", tz, &t, &e)) 179 << e; 180 auto ci = tz.At(t); 181 EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); 182 EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); 183 184 // But the timezone is ignored when a UTC offset is present. 185 EXPECT_TRUE(absl::ParseTime("%Y-%m-%d %H:%M:%S %z", 186 "2013-06-28 19:08:09 +0800", tz, &t, &e)) 187 << e; 188 ci = absl::FixedTimeZone(8 * 60 * 60).At(t); 189 EXPECT_EQ(absl::CivilSecond(2013, 6, 28, 19, 8, 9), ci.cs); 190 EXPECT_EQ(absl::ZeroDuration(), ci.subsecond); 191 } 192 193 TEST(ParseTime, ErrorCases) { 194 absl::Time t = absl::FromTimeT(0); 195 std::string err; 196 197 EXPECT_FALSE(absl::ParseTime("%S", "123", &t, &err)) << err; 198 EXPECT_THAT(err, HasSubstr("Illegal trailing data")); 199 200 // Can't parse an illegal format specifier. 201 err.clear(); 202 EXPECT_FALSE(absl::ParseTime("%Q", "x", &t, &err)) << err; 203 // Exact contents of "err" are platform-dependent because of 204 // differences in the strptime implementation between macOS and Linux. 205 EXPECT_FALSE(err.empty()); 206 207 // Fails because of trailing, unparsed data "blah". 208 EXPECT_FALSE(absl::ParseTime("%m-%d", "2-3 blah", &t, &err)) << err; 209 EXPECT_THAT(err, HasSubstr("Illegal trailing data")); 210 211 // Feb 31 requires normalization. 212 EXPECT_FALSE(absl::ParseTime("%m-%d", "2-31", &t, &err)) << err; 213 EXPECT_THAT(err, HasSubstr("Out-of-range")); 214 215 // Check that we cannot have spaces in UTC offsets. 216 EXPECT_TRUE(absl::ParseTime("%z", "-0203", &t, &err)) << err; 217 EXPECT_FALSE(absl::ParseTime("%z", "- 2 3", &t, &err)) << err; 218 EXPECT_THAT(err, HasSubstr("Failed to parse")); 219 EXPECT_TRUE(absl::ParseTime("%Ez", "-02:03", &t, &err)) << err; 220 EXPECT_FALSE(absl::ParseTime("%Ez", "- 2: 3", &t, &err)) << err; 221 EXPECT_THAT(err, HasSubstr("Failed to parse")); 222 223 // Check that we reject other malformed UTC offsets. 224 EXPECT_FALSE(absl::ParseTime("%Ez", "+-08:00", &t, &err)) << err; 225 EXPECT_THAT(err, HasSubstr("Failed to parse")); 226 EXPECT_FALSE(absl::ParseTime("%Ez", "-+08:00", &t, &err)) << err; 227 EXPECT_THAT(err, HasSubstr("Failed to parse")); 228 229 // Check that we do not accept "-0" in fields that allow zero. 230 EXPECT_FALSE(absl::ParseTime("%Y", "-0", &t, &err)) << err; 231 EXPECT_THAT(err, HasSubstr("Failed to parse")); 232 EXPECT_FALSE(absl::ParseTime("%E4Y", "-0", &t, &err)) << err; 233 EXPECT_THAT(err, HasSubstr("Failed to parse")); 234 EXPECT_FALSE(absl::ParseTime("%H", "-0", &t, &err)) << err; 235 EXPECT_THAT(err, HasSubstr("Failed to parse")); 236 EXPECT_FALSE(absl::ParseTime("%M", "-0", &t, &err)) << err; 237 EXPECT_THAT(err, HasSubstr("Failed to parse")); 238 EXPECT_FALSE(absl::ParseTime("%S", "-0", &t, &err)) << err; 239 EXPECT_THAT(err, HasSubstr("Failed to parse")); 240 EXPECT_FALSE(absl::ParseTime("%z", "+-000", &t, &err)) << err; 241 EXPECT_THAT(err, HasSubstr("Failed to parse")); 242 EXPECT_FALSE(absl::ParseTime("%Ez", "+-0:00", &t, &err)) << err; 243 EXPECT_THAT(err, HasSubstr("Failed to parse")); 244 EXPECT_FALSE(absl::ParseTime("%z", "-00-0", &t, &err)) << err; 245 EXPECT_THAT(err, HasSubstr("Illegal trailing data")); 246 EXPECT_FALSE(absl::ParseTime("%Ez", "-00:-0", &t, &err)) << err; 247 EXPECT_THAT(err, HasSubstr("Illegal trailing data")); 248 } 249 250 TEST(ParseTime, ExtendedSeconds) { 251 std::string err; 252 absl::Time t; 253 254 // Here is a "%E*S" case we got wrong for a while. The fractional 255 // part of the first instant is less than 2^31 and was correctly 256 // parsed, while the second (and any subsecond field >=2^31) failed. 257 t = absl::UnixEpoch(); 258 EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483647", &t, &err)) << err; 259 EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + 260 absl::Nanoseconds(1) / 2, 261 t); 262 t = absl::UnixEpoch(); 263 EXPECT_TRUE(absl::ParseTime("%E*S", "0.2147483648", &t, &err)) << err; 264 EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + 265 absl::Nanoseconds(3) / 4, 266 t); 267 268 // We should also be able to specify long strings of digits far 269 // beyond the current resolution and have them convert the same way. 270 t = absl::UnixEpoch(); 271 EXPECT_TRUE(absl::ParseTime( 272 "%E*S", "0.214748364801234567890123456789012345678901234567890123456789", 273 &t, &err)) 274 << err; 275 EXPECT_EQ(absl::UnixEpoch() + absl::Nanoseconds(214748364) + 276 absl::Nanoseconds(3) / 4, 277 t); 278 } 279 280 TEST(ParseTime, ExtendedOffsetErrors) { 281 std::string err; 282 absl::Time t; 283 284 // %z against +-HHMM. 285 EXPECT_FALSE(absl::ParseTime("%z", "-123", &t, &err)) << err; 286 EXPECT_THAT(err, HasSubstr("Illegal trailing data")); 287 288 // %z against +-HH. 289 EXPECT_FALSE(absl::ParseTime("%z", "-1", &t, &err)) << err; 290 EXPECT_THAT(err, HasSubstr("Failed to parse")); 291 292 // %Ez against +-HH:MM. 293 EXPECT_FALSE(absl::ParseTime("%Ez", "-12:3", &t, &err)) << err; 294 EXPECT_THAT(err, HasSubstr("Illegal trailing data")); 295 296 // %Ez against +-HHMM. 297 EXPECT_FALSE(absl::ParseTime("%Ez", "-123", &t, &err)) << err; 298 EXPECT_THAT(err, HasSubstr("Illegal trailing data")); 299 300 // %Ez against +-HH. 301 EXPECT_FALSE(absl::ParseTime("%Ez", "-1", &t, &err)) << err; 302 EXPECT_THAT(err, HasSubstr("Failed to parse")); 303 } 304 305 TEST(ParseTime, InfiniteTime) { 306 absl::Time t; 307 std::string err; 308 EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future", &t, &err)); 309 EXPECT_EQ(absl::InfiniteFuture(), t); 310 311 // Surrounding whitespace. 312 EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future", &t, &err)); 313 EXPECT_EQ(absl::InfiniteFuture(), t); 314 EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-future ", &t, &err)); 315 EXPECT_EQ(absl::InfiniteFuture(), t); 316 EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-future ", &t, &err)); 317 EXPECT_EQ(absl::InfiniteFuture(), t); 318 319 EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past", &t, &err)); 320 EXPECT_EQ(absl::InfinitePast(), t); 321 322 // Surrounding whitespace. 323 EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past", &t, &err)); 324 EXPECT_EQ(absl::InfinitePast(), t); 325 EXPECT_TRUE(absl::ParseTime("%H:%M blah", "infinite-past ", &t, &err)); 326 EXPECT_EQ(absl::InfinitePast(), t); 327 EXPECT_TRUE(absl::ParseTime("%H:%M blah", " infinite-past ", &t, &err)); 328 EXPECT_EQ(absl::InfinitePast(), t); 329 330 // "infinite-future" as literal string 331 absl::TimeZone tz = absl::UTCTimeZone(); 332 EXPECT_TRUE(absl::ParseTime("infinite-future %H:%M", "infinite-future 03:04", 333 &t, &err)); 334 EXPECT_NE(absl::InfiniteFuture(), t); 335 EXPECT_EQ(3, tz.At(t).cs.hour()); 336 EXPECT_EQ(4, tz.At(t).cs.minute()); 337 338 // "infinite-past" as literal string 339 EXPECT_TRUE( 340 absl::ParseTime("infinite-past %H:%M", "infinite-past 03:04", &t, &err)); 341 EXPECT_NE(absl::InfinitePast(), t); 342 EXPECT_EQ(3, tz.At(t).cs.hour()); 343 EXPECT_EQ(4, tz.At(t).cs.minute()); 344 345 // The input doesn't match the format. 346 EXPECT_FALSE(absl::ParseTime("infinite-future %H:%M", "03:04", &t, &err)); 347 EXPECT_FALSE(absl::ParseTime("infinite-past %H:%M", "03:04", &t, &err)); 348 } 349 350 TEST(ParseTime, FailsOnUnrepresentableTime) { 351 const absl::TimeZone utc = absl::UTCTimeZone(); 352 absl::Time t; 353 EXPECT_FALSE( 354 absl::ParseTime("%Y-%m-%d", "-292277022657-01-27", utc, &t, nullptr)); 355 EXPECT_TRUE( 356 absl::ParseTime("%Y-%m-%d", "-292277022657-01-28", utc, &t, nullptr)); 357 EXPECT_TRUE( 358 absl::ParseTime("%Y-%m-%d", "292277026596-12-04", utc, &t, nullptr)); 359 EXPECT_FALSE( 360 absl::ParseTime("%Y-%m-%d", "292277026596-12-05", utc, &t, nullptr)); 361 } 362 363 // 364 // Roundtrip test for FormatTime()/ParseTime(). 365 // 366 367 TEST(FormatParse, RoundTrip) { 368 const absl::TimeZone lax = 369 absl::time_internal::LoadTimeZone("America/Los_Angeles"); 370 const absl::Time in = 371 absl::FromCivil(absl::CivilSecond(1977, 6, 28, 9, 8, 7), lax); 372 const absl::Duration subseconds = absl::Nanoseconds(654321); 373 std::string err; 374 375 // RFC3339, which renders subseconds. 376 { 377 absl::Time out; 378 const std::string s = 379 absl::FormatTime(absl::RFC3339_full, in + subseconds, lax); 380 EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) 381 << s << ": " << err; 382 EXPECT_EQ(in + subseconds, out); // RFC3339_full includes %Ez 383 } 384 385 // RFC1123, which only does whole seconds. 386 { 387 absl::Time out; 388 const std::string s = absl::FormatTime(absl::RFC1123_full, in, lax); 389 EXPECT_TRUE(absl::ParseTime(absl::RFC1123_full, s, &out, &err)) 390 << s << ": " << err; 391 EXPECT_EQ(in, out); // RFC1123_full includes %z 392 } 393 394 // `absl::FormatTime()` falls back to strftime() for "%c", which appears to 395 // work. On Windows, `absl::ParseTime()` falls back to std::get_time() which 396 // appears to fail on "%c" (or at least on the "%c" text produced by 397 // `strftime()`). This makes it fail the round-trip test. 398 // 399 // Under the emscripten compiler `absl::ParseTime() falls back to 400 // `strptime()`, but that ends up using a different definition for "%c" 401 // compared to `strftime()`, also causing the round-trip test to fail 402 // (see https://github.com/kripken/emscripten/pull/7491). 403 #if !defined(_MSC_VER) && !defined(__EMSCRIPTEN__) 404 // Even though we don't know what %c will produce, it should roundtrip, 405 // but only in the 0-offset timezone. 406 { 407 absl::Time out; 408 const std::string s = absl::FormatTime("%c", in, absl::UTCTimeZone()); 409 EXPECT_TRUE(absl::ParseTime("%c", s, &out, &err)) << s << ": " << err; 410 EXPECT_EQ(in, out); 411 } 412 #endif // !_MSC_VER && !__EMSCRIPTEN__ 413 } 414 415 TEST(FormatParse, RoundTripDistantFuture) { 416 const absl::TimeZone tz = absl::UTCTimeZone(); 417 const absl::Time in = 418 absl::FromUnixSeconds(std::numeric_limits<int64_t>::max()); 419 std::string err; 420 421 absl::Time out; 422 const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz); 423 EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) 424 << s << ": " << err; 425 EXPECT_EQ(in, out); 426 } 427 428 TEST(FormatParse, RoundTripDistantPast) { 429 const absl::TimeZone tz = absl::UTCTimeZone(); 430 const absl::Time in = 431 absl::FromUnixSeconds(std::numeric_limits<int64_t>::min()); 432 std::string err; 433 434 absl::Time out; 435 const std::string s = absl::FormatTime(absl::RFC3339_full, in, tz); 436 EXPECT_TRUE(absl::ParseTime(absl::RFC3339_full, s, &out, &err)) 437 << s << ": " << err; 438 EXPECT_EQ(in, out); 439 } 440 441 } // namespace