Skip to content

Commit 08fc6f0

Browse files
authored
impl(spanner): remove Interval arithmetic functions (#15117)
1 parent 2ba5c05 commit 08fc6f0

File tree

4 files changed

+114
-262
lines changed

4 files changed

+114
-262
lines changed
-132 KB
Binary file not shown.

google/cloud/spanner/interval.cc

Lines changed: 56 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,6 @@ using std::chrono::minutes;
5050
using std::chrono::nanoseconds;
5151
using std::chrono::seconds;
5252

53-
StatusOr<absl::TimeZone> LoadTimeZone(absl::string_view name) {
54-
absl::TimeZone tz;
55-
if (!absl::LoadTimeZone(name, &tz)) {
56-
return internal::InvalidArgumentError(
57-
absl::StrFormat("%s: Invalid time zone", name), GCP_ERROR_INFO());
58-
}
59-
return tz;
60-
}
61-
6253
// Round d to a microsecond boundary (to even in halfway cases).
6354
microseconds Round(nanoseconds d) {
6455
auto trunc = duration_cast<microseconds>(d);
@@ -252,56 +243,6 @@ auto NameIs(char name) {
252243
return [name](ISO8601UnitFactory const& u) { return u.name == name; };
253244
}
254245

255-
StatusOr<Interval> ParseISO8601Interval(absl::string_view str) {
256-
Interval intvl;
257-
absl::string_view s = str;
258-
259-
auto const* units = std::begin(kISO8601DateUnitFactories);
260-
auto const* units_end = std::end(kISO8601DateUnitFactories);
261-
enum { kValue, kUnit, kNothing } expecting = kValue;
262-
bool negated = false;
263-
264-
for (;;) {
265-
if (units == std::begin(kISO8601DateUnitFactories)) {
266-
negated = !absl::ConsumePrefix(&s, "+") && absl::ConsumePrefix(&s, "-");
267-
if (!absl::ConsumePrefix(&s, "P")) break;
268-
}
269-
if (units_end == std::end(kISO8601DateUnitFactories)) {
270-
if (absl::ConsumePrefix(&s, "T")) {
271-
units = std::begin(kISO8601TimeUnitFactories);
272-
units_end = std::end(kISO8601TimeUnitFactories);
273-
expecting = kValue;
274-
}
275-
}
276-
if (units == units_end) break;
277-
double vf;
278-
if (ParseDouble(s, vf, true, true)) {
279-
expecting = kUnit;
280-
if (s.empty()) break;
281-
units = std::find_if(units, units_end, NameIs(s.front()));
282-
if (units == units_end) break;
283-
intvl += units++->factory(1) * vf;
284-
expecting = kNothing;
285-
s.remove_prefix(1);
286-
break; // must be last unit
287-
}
288-
std::int32_t vn;
289-
if (!ParseInteger(s, vn, true)) break;
290-
expecting = kUnit;
291-
if (s.empty()) break;
292-
units = std::find_if(units, units_end, NameIs(s.front()));
293-
if (units == units_end) break;
294-
intvl += units++->factory(vn);
295-
expecting = kNothing;
296-
s.remove_prefix(1);
297-
}
298-
299-
if (!s.empty() || expecting != kNothing) {
300-
return SyntaxError(str, s, GCP_ERROR_INFO());
301-
}
302-
return negated ? -intvl : intvl;
303-
}
304-
305246
/**
306247
* https://www.postgresql.org/docs/current/datatype-datetime.html
307248
*
@@ -398,7 +339,59 @@ Interval PostgreSqlUnit(absl::string_view& s, std::int32_t n) {
398339
return Interval(0, 0, n); // default to days without removing unit
399340
}
400341

401-
StatusOr<Interval> ParsePostgreSqlInterval(absl::string_view str) {
342+
} // namespace
343+
344+
StatusOr<Interval> Interval::ParseISO8601Interval(absl::string_view str) {
345+
Interval intvl;
346+
absl::string_view s = str;
347+
348+
auto const* units = std::begin(kISO8601DateUnitFactories);
349+
auto const* units_end = std::end(kISO8601DateUnitFactories);
350+
enum { kValue, kUnit, kNothing } expecting = kValue;
351+
bool negated = false;
352+
353+
for (;;) {
354+
if (units == std::begin(kISO8601DateUnitFactories)) {
355+
negated = !absl::ConsumePrefix(&s, "+") && absl::ConsumePrefix(&s, "-");
356+
if (!absl::ConsumePrefix(&s, "P")) break;
357+
}
358+
if (units_end == std::end(kISO8601DateUnitFactories)) {
359+
if (absl::ConsumePrefix(&s, "T")) {
360+
units = std::begin(kISO8601TimeUnitFactories);
361+
units_end = std::end(kISO8601TimeUnitFactories);
362+
expecting = kValue;
363+
}
364+
}
365+
if (units == units_end) break;
366+
double vf;
367+
if (ParseDouble(s, vf, true, true)) {
368+
expecting = kUnit;
369+
if (s.empty()) break;
370+
units = std::find_if(units, units_end, NameIs(s.front()));
371+
if (units == units_end) break;
372+
intvl += units++->factory(1) * vf;
373+
expecting = kNothing;
374+
s.remove_prefix(1);
375+
break; // must be last unit
376+
}
377+
std::int32_t vn;
378+
if (!ParseInteger(s, vn, true)) break;
379+
expecting = kUnit;
380+
if (s.empty()) break;
381+
units = std::find_if(units, units_end, NameIs(s.front()));
382+
if (units == units_end) break;
383+
intvl += units++->factory(vn);
384+
expecting = kNothing;
385+
s.remove_prefix(1);
386+
}
387+
388+
if (!s.empty() || expecting != kNothing) {
389+
return SyntaxError(str, s, GCP_ERROR_INFO());
390+
}
391+
return negated ? -intvl : intvl;
392+
}
393+
394+
StatusOr<Interval> Interval::ParsePostgreSqlInterval(absl::string_view str) {
402395
Interval intvl;
403396
absl::string_view s = str;
404397

@@ -441,8 +434,6 @@ StatusOr<Interval> ParsePostgreSqlInterval(absl::string_view str) {
441434
return intvl;
442435
}
443436

444-
} // namespace
445-
446437
bool operator==(Interval const& a, Interval const& b) {
447438
return Cmp<std::equal_to>(a.months_, a.days_, a.offset_, //
448439
b.months_, b.days_, b.offset_);
@@ -491,10 +482,11 @@ Interval::operator std::string() const {
491482
}
492483

493484
StatusOr<Interval> MakeInterval(absl::string_view s) {
494-
auto interval = ParseISO8601Interval(s);
485+
auto interval = Interval::ParseISO8601Interval(s);
495486
if (interval.ok()) return interval;
496487

497-
auto pg_interval = ParsePostgreSqlInterval(absl::AsciiStrToLower(s));
488+
auto pg_interval =
489+
Interval::ParsePostgreSqlInterval(absl::AsciiStrToLower(s));
498490
if (pg_interval.ok()) return pg_interval;
499491

500492
// We failed to parse the argument using either syntax. The most
@@ -532,34 +524,6 @@ Interval JustifyInterval(Interval intvl) {
532524
return JustifyDays(JustifyHours(intvl));
533525
}
534526

535-
StatusOr<Timestamp> Add(Timestamp const& ts, Interval const& intvl,
536-
absl::string_view time_zone) {
537-
auto tz = LoadTimeZone(time_zone);
538-
if (!tz) return tz.status();
539-
auto ci = tz->At(*ts.get<absl::Time>());
540-
auto cs = absl::CivilSecond( // add the civil-time parts
541-
ci.cs.year(), ci.cs.month() + intvl.months_, ci.cs.day() + intvl.days_,
542-
ci.cs.hour(), ci.cs.minute(), ci.cs.second());
543-
return *MakeTimestamp(internal::ToProtoTimestamp( // overflow saturates
544-
absl::FromCivil(cs, *tz) + ci.subsecond +
545-
absl::FromChrono(intvl.offset_)));
546-
}
547-
548-
StatusOr<Interval> Diff(Timestamp const& ts1, Timestamp const& ts2,
549-
absl::string_view time_zone) {
550-
auto tz = LoadTimeZone(time_zone);
551-
if (!tz) return tz.status();
552-
auto ci1 = tz->At(*ts1.get<absl::Time>());
553-
auto ci2 = tz->At(*ts2.get<absl::Time>());
554-
auto days = absl::CivilDay(ci1.cs) - absl::CivilDay(ci2.cs);
555-
auto offset = absl::Hours(ci1.cs.hour() - ci2.cs.hour()) +
556-
absl::Minutes(ci1.cs.minute() - ci2.cs.minute()) +
557-
absl::Seconds(ci1.cs.second() - ci2.cs.second()) +
558-
(ci1.subsecond - ci2.subsecond);
559-
return JustifyHours(Interval(0, 0, static_cast<std::int32_t>(days),
560-
absl::ToChronoNanoseconds(offset)));
561-
}
562-
563527
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
564528
} // namespace spanner
565529
} // namespace cloud

google/cloud/spanner/interval.h

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_BEGIN
3636
* @see https://cloud.google.com/spanner/docs/data-types#interval_type
3737
*/
3838
class Interval {
39+
friend class IntervalTest;
40+
3941
public:
4042
/// Default construction yields a zero-length interval.
4143
Interval() : Interval(0, 0, 0) {}
@@ -79,24 +81,6 @@ class Interval {
7981
}
8082
///@}
8183

82-
/// @name Arithmetic operators
83-
///
84-
/// Beware: Fractional multiplication similarly assumes 30-days months
85-
/// and 24-hour days, and may lead to counterintuitive results.
86-
///@{
87-
Interval operator-() const;
88-
Interval& operator+=(Interval const&);
89-
Interval& operator-=(Interval const& intvl) {
90-
*this += -intvl;
91-
return *this;
92-
}
93-
Interval& operator*=(double);
94-
Interval& operator/=(double d) {
95-
*this *= 1.0 / d;
96-
return *this;
97-
}
98-
///@}
99-
10084
/// @name Conversion to a string using ISO8601 duration format.
10185
explicit operator std::string() const;
10286

@@ -105,30 +89,39 @@ class Interval {
10589
return os << std::string(intvl);
10690
}
10791

92+
/// @name Negation
93+
Interval operator-() const;
94+
10895
private:
10996
Interval(std::int32_t months, std::int32_t days,
11097
std::chrono::nanoseconds offset)
11198
: months_(months), days_(days), offset_(offset) {}
11299

100+
static StatusOr<Interval> ParseISO8601Interval(absl::string_view str);
101+
static StatusOr<Interval> ParsePostgreSqlInterval(absl::string_view str);
102+
113103
friend Interval JustifyDays(Interval);
114104
friend Interval JustifyHours(Interval);
115-
friend StatusOr<Timestamp> Add(Timestamp const&, Interval const&,
116-
absl::string_view);
105+
friend StatusOr<Interval> MakeInterval(absl::string_view);
106+
friend class IntervalTest;
107+
108+
// Beware: Fractional multiplication similarly assumes 30-days months
109+
// and 24-hour days, and may lead to counterintuitive results.
110+
Interval& operator+=(Interval const&);
111+
Interval& operator-=(Interval const& intvl) {
112+
*this += -intvl;
113+
return *this;
114+
}
115+
Interval& operator*=(double);
116+
Interval operator+(Interval rhs) const { return Interval(*this) += rhs; }
117+
Interval operator-(Interval rhs) const { return Interval(*this) -= rhs; }
118+
Interval operator*(double rhs) const { return Interval(*this) *= rhs; }
117119

118120
std::int32_t months_;
119121
std::int32_t days_;
120122
std::chrono::nanoseconds offset_;
121123
};
122124

123-
/// @name Binary operators
124-
///@{
125-
inline Interval operator+(Interval lhs, Interval rhs) { return lhs += rhs; }
126-
inline Interval operator-(Interval lhs, Interval rhs) { return lhs -= rhs; }
127-
inline Interval operator*(Interval lhs, double rhs) { return lhs *= rhs; }
128-
inline Interval operator*(double lhs, Interval rhs) { return rhs *= lhs; }
129-
inline Interval operator/(Interval lhs, double rhs) { return lhs /= rhs; }
130-
///@}
131-
132125
/**
133126
* Construct an `Interval` from a string. At least handles the format
134127
* produced by `Interval::operator std::string()`.
@@ -153,23 +146,6 @@ Interval JustifyHours(Interval);
153146
*/
154147
Interval JustifyInterval(Interval);
155148

156-
/**
157-
* Add the Interval to the Timestamp in the civil-time space defined by
158-
* the time zone. Saturates the Timestamp result upon overflow. Returns
159-
* an error status if the time zone cannot be loaded.
160-
*/
161-
StatusOr<Timestamp> Add(Timestamp const&, Interval const&,
162-
absl::string_view time_zone);
163-
164-
/**
165-
* Intervals constructed by subtracting two timestamps are partially
166-
* justified, returning a whole number of days plus any remainder. A
167-
* year/month value will never be present. Undefined on days overflow.
168-
* Returns an error status if the time zone cannot be loaded.
169-
*/
170-
StatusOr<Interval> Diff(Timestamp const&, Timestamp const&,
171-
absl::string_view time_zone);
172-
173149
GOOGLE_CLOUD_CPP_INLINE_NAMESPACE_END
174150
} // namespace spanner
175151
} // namespace cloud

0 commit comments

Comments
 (0)