// Copyright 2016 Google Inc. All Rights Reserved. // // 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. #if !defined(HAS_STRPTIME) #if !defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__VXWORKS__) #define HAS_STRPTIME … #endif #endif #if defined(HAS_STRPTIME) && HAS_STRPTIME #if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__OpenBSD__) #define _XOPEN_SOURCE … #endif #endif #include "absl/base/config.h" #include "absl/time/internal/cctz/include/cctz/time_zone.h" // Include time.h directly since, by C++ standards, ctime doesn't have to // declare strptime. #include <time.h> #include <cctype> #include <chrono> #include <cstddef> #include <cstdint> #include <cstring> #include <ctime> #include <limits> #include <string> #include <vector> #if !HAS_STRPTIME #include <iomanip> #include <sstream> #endif #include "absl/time/internal/cctz/include/cctz/civil_time.h" #include "time_zone_if.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace time_internal { namespace cctz { namespace detail { namespace { #if !HAS_STRPTIME // Build a strptime() using C++11's std::get_time(). char* strptime(const char* s, const char* fmt, std::tm* tm) { std::istringstream input(s); input >> std::get_time(tm, fmt); if (input.fail()) return nullptr; return const_cast<char*>(s) + (input.eof() ? strlen(s) : static_cast<std::size_t>(input.tellg())); } #endif // Convert a cctz::weekday to a tm_wday value (0-6, Sunday = 0). int ToTmWday(weekday wd) { … } // Convert a tm_wday value (0-6, Sunday = 0) to a cctz::weekday. weekday FromTmWday(int tm_wday) { … } std::tm ToTM(const time_zone::absolute_lookup& al) { … } // Returns the week of the year [0:53] given a civil day and the day on // which weeks are defined to start. int ToWeek(const civil_day& cd, weekday week_start) { … } const char kDigits[] = …; // Formats a 64-bit integer in the given field width. Note that it is up // to the caller of Format64() [and Format02d()/FormatOffset()] to ensure // that there is sufficient space before ep to hold the conversion. char* Format64(char* ep, int width, std::int_fast64_t v) { … } // Formats [0 .. 99] as %02d. char* Format02d(char* ep, int v) { … } // Formats a UTC offset, like +00:00. char* FormatOffset(char* ep, int offset, const char* mode) { … } // Formats a std::tm using strftime(3). void FormatTM(std::string* out, const std::string& fmt, const std::tm& tm) { … } // Used for %E#S/%E#f specifiers and for data values in parse(). template <typename T> const char* ParseInt(const char* dp, int width, T min, T max, T* vp) { … } // The number of base-10 digits that can be represented by a signed 64-bit // integer. That is, 10^kDigits10_64 <= 2^63 - 1 < 10^(kDigits10_64 + 1). const int kDigits10_64 = …; // 10^n for everything that can be represented by a signed 64-bit integer. const std::int_fast64_t kExp10[kDigits10_64 + 1] = …; } // namespace // Uses strftime(3) to format the given Time. The following extended format // specifiers are also supported: // // - %Ez - RFC3339-compatible numeric UTC offset (+hh:mm or -hh:mm) // - %E*z - Full-resolution numeric UTC offset (+hh:mm:ss or -hh:mm:ss) // - %E#S - Seconds with # digits of fractional precision // - %E*S - Seconds with full fractional precision (a literal '*') // - %E4Y - Four-character years (-999 ... -001, 0000, 0001 ... 9999) // - %ET - The RFC3339 "date-time" separator "T" // // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are // handled internally for performance reasons. strftime(3) is slow due to // a POSIX requirement to respect changes to ${TZ}. // // The TZ/GNU %s extension is handled internally because strftime() has // to use mktime() to generate it, and that assumes the local time zone. // // We also handle the %z and %Z specifiers to accommodate platforms that do // not support the tm_gmtoff and tm_zone extensions to std::tm. // // Requires that zero() <= fs < seconds(1). std::string format(const std::string& format, const time_point<seconds>& tp, const detail::femtoseconds& fs, const time_zone& tz) { … } namespace { const char* ParseOffset(const char* dp, const char* mode, int* offset) { … } const char* ParseZone(const char* dp, std::string* zone) { … } const char* ParseSubSeconds(const char* dp, detail::femtoseconds* subseconds) { … } // Parses a string into a std::tm using strptime(3). const char* ParseTM(const char* dp, const char* fmt, std::tm* tm) { … } // Sets year, tm_mon and tm_mday given the year, week_num, and tm_wday, // and the day on which weeks are defined to start. Returns false if year // would need to move outside its bounds. bool FromWeek(int week_num, weekday week_start, year_t* year, std::tm* tm) { … } } // namespace // Uses strptime(3) to parse the given input. Supports the same extended // format specifiers as format(), although %E#S and %E*S are treated // identically (and similarly for %E#f and %E*f). %Ez and %E*z also accept // the same inputs. %ET accepts either 'T' or 't'. // // The standard specifiers from RFC3339_* (%Y, %m, %d, %H, %M, and %S) are // handled internally so that we can normally avoid strptime() altogether // (which is particularly helpful when the native implementation is broken). // // The TZ/GNU %s extension is handled internally because strptime() has to // use localtime_r() to generate it, and that assumes the local time zone. // // We also handle the %z specifier to accommodate platforms that do not // support the tm_gmtoff extension to std::tm. %Z is parsed but ignored. bool parse(const std::string& format, const std::string& input, const time_zone& tz, time_point<seconds>* sec, detail::femtoseconds* fs, std::string* err) { … } } // namespace detail } // namespace cctz } // namespace time_internal ABSL_NAMESPACE_END } // namespace absl