Skip to content

Commit

Permalink
Reimplement DateToString() and DateFromString() (googleapis/googl…
Browse files Browse the repository at this point in the history
…e-cloud-cpp-spanner#299)

* Reimplement `DateToString()` and `DateFromString()`

The new implementation avoids internal/time_format.h, which is slated
for removal, the end goal being to produce `TimestampToString()` and
`TimestampFromString()` functions that can be shared between bigtable,
storage, and spanner libraries.
  • Loading branch information
devbww authored Aug 3, 2019
1 parent cb70bd4 commit cfbe1fd
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 23 deletions.
46 changes: 24 additions & 22 deletions google/cloud/spanner/internal/date.cc
Original file line number Diff line number Diff line change
Expand Up @@ -13,42 +13,44 @@
// limitations under the License.

#include "google/cloud/spanner/internal/date.h"
#include "google/cloud/spanner/internal/time_format.h"
#include <ctime>
#include <array>
#include <cinttypes>
#include <cstdio>

namespace google {
namespace cloud {
namespace spanner {
inline namespace SPANNER_CLIENT_NS {
namespace internal {

namespace {

// RFC3339 "full-date".
constexpr auto kDateFormat = "%Y-%m-%d";

} // namespace

std::string DateToString(Date d) {
std::tm tm;
tm.tm_year = static_cast<int>(d.year() - 1900);
tm.tm_mon = d.month() - 1;
tm.tm_mday = d.day();
return FormatTime(kDateFormat, tm);
std::array<char, sizeof "-9223372036854775808-01-01"> buf;
std::snprintf(buf.data(), buf.size(), "%" PRId64 "-%02d-%02d", d.year(),
d.month(), d.day());
return std::string(buf.data());
}

StatusOr<Date> DateFromString(std::string const& s) {
std::tm tm;
auto pos = ParseTime(kDateFormat, s, &tm);
if (pos == std::string::npos) {
return Status(StatusCode::kInvalidArgument,
s + ": Failed to match RFC3339 full-date");
std::int64_t year;
int month;
int day;
char c;
switch (sscanf(s.c_str(), "%" SCNd64 "-%d-%d%c", &year, &month, &day, &c)) {
case 3:
break;
case 4:
return Status(StatusCode::kInvalidArgument,
s + ": Extra data after RFC3339 full-date");
default:
return Status(StatusCode::kInvalidArgument,
s + ": Failed to match RFC3339 full-date");
}
if (pos != s.size()) {
Date date(year, month, day);
if (date.month() != month || date.day() != day) {
return Status(StatusCode::kInvalidArgument,
s + ": Extra data after RFC3339 full-date");
s + ": RFC3339 full-date field out of range");
}
return Date(tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
return date;
}

} // namespace internal
Expand Down
2 changes: 1 addition & 1 deletion google/cloud/spanner/internal/date_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ TEST(Date, DateFromStringFailure) {
EXPECT_FALSE(DateFromString(""));
EXPECT_FALSE(DateFromString("garbage in"));
EXPECT_FALSE(DateFromString("2018-13-02"));
EXPECT_FALSE(DateFromString("2019-06-32"));
EXPECT_FALSE(DateFromString("2019-06-31"));
EXPECT_FALSE(DateFromString("2019-06-21x"));
}

Expand Down

0 comments on commit cfbe1fd

Please sign in to comment.