1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker *
4*993b0882SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker *
8*993b0882SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker *
10*993b0882SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker */
16*993b0882SAndroid Build Coastguard Worker
17*993b0882SAndroid Build Coastguard Worker #ifndef LIBTEXTCLASSIFIER_UTILS_CALENDAR_CALENDAR_COMMON_H_
18*993b0882SAndroid Build Coastguard Worker #define LIBTEXTCLASSIFIER_UTILS_CALENDAR_CALENDAR_COMMON_H_
19*993b0882SAndroid Build Coastguard Worker
20*993b0882SAndroid Build Coastguard Worker #include "annotator/types.h"
21*993b0882SAndroid Build Coastguard Worker #include "utils/base/integral_types.h"
22*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
23*993b0882SAndroid Build Coastguard Worker #include "utils/base/macros.h"
24*993b0882SAndroid Build Coastguard Worker
25*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
26*993b0882SAndroid Build Coastguard Worker namespace calendar {
27*993b0882SAndroid Build Coastguard Worker
28*993b0882SAndroid Build Coastguard Worker // Macro to reduce the amount of boilerplate needed for propagating errors.
29*993b0882SAndroid Build Coastguard Worker #define TC3_CALENDAR_CHECK(EXPR) \
30*993b0882SAndroid Build Coastguard Worker if (!(EXPR)) { \
31*993b0882SAndroid Build Coastguard Worker return false; \
32*993b0882SAndroid Build Coastguard Worker }
33*993b0882SAndroid Build Coastguard Worker
34*993b0882SAndroid Build Coastguard Worker // An implementation of CalendarLib that is independent of the particular
35*993b0882SAndroid Build Coastguard Worker // calendar implementation used (implementation type is passed as template
36*993b0882SAndroid Build Coastguard Worker // argument).
37*993b0882SAndroid Build Coastguard Worker template <class TCalendar>
38*993b0882SAndroid Build Coastguard Worker class CalendarLibTempl {
39*993b0882SAndroid Build Coastguard Worker public:
40*993b0882SAndroid Build Coastguard Worker bool InterpretParseData(const DatetimeParsedData& parse_data,
41*993b0882SAndroid Build Coastguard Worker int64 reference_time_ms_utc,
42*993b0882SAndroid Build Coastguard Worker const std::string& reference_timezone,
43*993b0882SAndroid Build Coastguard Worker const std::string& reference_locale,
44*993b0882SAndroid Build Coastguard Worker bool prefer_future_for_unspecified_date,
45*993b0882SAndroid Build Coastguard Worker TCalendar* calendar,
46*993b0882SAndroid Build Coastguard Worker DatetimeGranularity* granularity) const;
47*993b0882SAndroid Build Coastguard Worker
48*993b0882SAndroid Build Coastguard Worker DatetimeGranularity GetGranularity(const DatetimeParsedData& data) const;
49*993b0882SAndroid Build Coastguard Worker
50*993b0882SAndroid Build Coastguard Worker private:
51*993b0882SAndroid Build Coastguard Worker // Adjusts the calendar's time instant according to a relative date reference
52*993b0882SAndroid Build Coastguard Worker // in the parsed data.
53*993b0882SAndroid Build Coastguard Worker bool ApplyRelationField(const DatetimeComponent& relative_date_time_component,
54*993b0882SAndroid Build Coastguard Worker TCalendar* calendar) const;
55*993b0882SAndroid Build Coastguard Worker
56*993b0882SAndroid Build Coastguard Worker // Round the time instant's precision down to the given granularity.
57*993b0882SAndroid Build Coastguard Worker bool RoundToGranularity(DatetimeGranularity granularity,
58*993b0882SAndroid Build Coastguard Worker TCalendar* calendar) const;
59*993b0882SAndroid Build Coastguard Worker
60*993b0882SAndroid Build Coastguard Worker // Adjusts time in steps of relation_type, by distance steps.
61*993b0882SAndroid Build Coastguard Worker // For example:
62*993b0882SAndroid Build Coastguard Worker // - Adjusting by -2 MONTHS will return the beginning of the 1st
63*993b0882SAndroid Build Coastguard Worker // two weeks ago.
64*993b0882SAndroid Build Coastguard Worker // - Adjusting by +4 Wednesdays will return the beginning of the next
65*993b0882SAndroid Build Coastguard Worker // Wednesday at least 4 weeks from now.
66*993b0882SAndroid Build Coastguard Worker // If allow_today is true, the same day of the week may be kept
67*993b0882SAndroid Build Coastguard Worker // if it already matches the relation type.
68*993b0882SAndroid Build Coastguard Worker bool AdjustByRelation(DatetimeComponent date_time_component, int distance,
69*993b0882SAndroid Build Coastguard Worker bool allow_today, TCalendar* calendar) const;
70*993b0882SAndroid Build Coastguard Worker };
71*993b0882SAndroid Build Coastguard Worker
HasOnlyTimeComponents(const DatetimeParsedData & parse_data)72*993b0882SAndroid Build Coastguard Worker inline bool HasOnlyTimeComponents(const DatetimeParsedData& parse_data) {
73*993b0882SAndroid Build Coastguard Worker std::vector<DatetimeComponent> components;
74*993b0882SAndroid Build Coastguard Worker parse_data.GetDatetimeComponents(&components);
75*993b0882SAndroid Build Coastguard Worker
76*993b0882SAndroid Build Coastguard Worker for (const DatetimeComponent& component : components) {
77*993b0882SAndroid Build Coastguard Worker if (!(component.component_type == DatetimeComponent::ComponentType::HOUR ||
78*993b0882SAndroid Build Coastguard Worker component.component_type ==
79*993b0882SAndroid Build Coastguard Worker DatetimeComponent::ComponentType::MINUTE ||
80*993b0882SAndroid Build Coastguard Worker component.component_type ==
81*993b0882SAndroid Build Coastguard Worker DatetimeComponent::ComponentType::SECOND ||
82*993b0882SAndroid Build Coastguard Worker component.component_type ==
83*993b0882SAndroid Build Coastguard Worker DatetimeComponent::ComponentType::MERIDIEM)) {
84*993b0882SAndroid Build Coastguard Worker return false;
85*993b0882SAndroid Build Coastguard Worker }
86*993b0882SAndroid Build Coastguard Worker }
87*993b0882SAndroid Build Coastguard Worker return true;
88*993b0882SAndroid Build Coastguard Worker }
89*993b0882SAndroid Build Coastguard Worker
90*993b0882SAndroid Build Coastguard Worker template <class TCalendar>
InterpretParseData(const DatetimeParsedData & parse_data,int64 reference_time_ms_utc,const std::string & reference_timezone,const std::string & reference_locale,bool prefer_future_for_unspecified_date,TCalendar * calendar,DatetimeGranularity * granularity)91*993b0882SAndroid Build Coastguard Worker bool CalendarLibTempl<TCalendar>::InterpretParseData(
92*993b0882SAndroid Build Coastguard Worker const DatetimeParsedData& parse_data, int64 reference_time_ms_utc,
93*993b0882SAndroid Build Coastguard Worker const std::string& reference_timezone, const std::string& reference_locale,
94*993b0882SAndroid Build Coastguard Worker bool prefer_future_for_unspecified_date, TCalendar* calendar,
95*993b0882SAndroid Build Coastguard Worker DatetimeGranularity* granularity) const {
96*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->Initialize(reference_timezone, reference_locale,
97*993b0882SAndroid Build Coastguard Worker reference_time_ms_utc))
98*993b0882SAndroid Build Coastguard Worker
99*993b0882SAndroid Build Coastguard Worker bool should_round_to_granularity = true;
100*993b0882SAndroid Build Coastguard Worker *granularity = GetGranularity(parse_data);
101*993b0882SAndroid Build Coastguard Worker
102*993b0882SAndroid Build Coastguard Worker // Apply each of the parsed fields in order of increasing granularity.
103*993b0882SAndroid Build Coastguard Worker static const int64 kMillisInMinute = 1000 * 60;
104*993b0882SAndroid Build Coastguard Worker if (parse_data.HasFieldType(DatetimeComponent::ComponentType::ZONE_OFFSET)) {
105*993b0882SAndroid Build Coastguard Worker int zone_offset;
106*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::ZONE_OFFSET,
107*993b0882SAndroid Build Coastguard Worker &zone_offset);
108*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetZoneOffset(zone_offset * kMillisInMinute))
109*993b0882SAndroid Build Coastguard Worker }
110*993b0882SAndroid Build Coastguard Worker static const int64 kMillisInHour = 1000 * 60 * 60;
111*993b0882SAndroid Build Coastguard Worker if (parse_data.HasFieldType(DatetimeComponent::ComponentType::DST_OFFSET)) {
112*993b0882SAndroid Build Coastguard Worker int dst_offset;
113*993b0882SAndroid Build Coastguard Worker if (parse_data.GetFieldValue(DatetimeComponent::ComponentType::DST_OFFSET,
114*993b0882SAndroid Build Coastguard Worker &dst_offset)) {
115*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetDstOffset(dst_offset * kMillisInHour))
116*993b0882SAndroid Build Coastguard Worker }
117*993b0882SAndroid Build Coastguard Worker }
118*993b0882SAndroid Build Coastguard Worker std::vector<DatetimeComponent> relative_components;
119*993b0882SAndroid Build Coastguard Worker parse_data.GetRelativeDatetimeComponents(&relative_components);
120*993b0882SAndroid Build Coastguard Worker if (!relative_components.empty()) {
121*993b0882SAndroid Build Coastguard Worker // Currently only one relative date time component is possible.
122*993b0882SAndroid Build Coastguard Worker const DatetimeComponent& relative_component = relative_components.back();
123*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(ApplyRelationField(relative_component, calendar));
124*993b0882SAndroid Build Coastguard Worker should_round_to_granularity = relative_component.ShouldRoundToGranularity();
125*993b0882SAndroid Build Coastguard Worker } else {
126*993b0882SAndroid Build Coastguard Worker // By default, the parsed time is interpreted to be on the reference day.
127*993b0882SAndroid Build Coastguard Worker // But a parsed date should have time 0:00:00 unless specified.
128*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetHourOfDay(0))
129*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetMinute(0))
130*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetSecond(0))
131*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetMillisecond(0))
132*993b0882SAndroid Build Coastguard Worker }
133*993b0882SAndroid Build Coastguard Worker if (parse_data.HasAbsoluteValue(DatetimeComponent::ComponentType::YEAR)) {
134*993b0882SAndroid Build Coastguard Worker int year;
135*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::YEAR, &year);
136*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetYear(year))
137*993b0882SAndroid Build Coastguard Worker }
138*993b0882SAndroid Build Coastguard Worker if (parse_data.HasAbsoluteValue(DatetimeComponent::ComponentType::MONTH)) {
139*993b0882SAndroid Build Coastguard Worker int month;
140*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::MONTH, &month);
141*993b0882SAndroid Build Coastguard Worker // ICU has months starting at 0, Java and Datetime parser at 1, so we
142*993b0882SAndroid Build Coastguard Worker // need to subtract 1.
143*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetMonth(month - 1))
144*993b0882SAndroid Build Coastguard Worker }
145*993b0882SAndroid Build Coastguard Worker
146*993b0882SAndroid Build Coastguard Worker if (parse_data.HasAbsoluteValue(
147*993b0882SAndroid Build Coastguard Worker DatetimeComponent::ComponentType::DAY_OF_MONTH)) {
148*993b0882SAndroid Build Coastguard Worker int day_of_month;
149*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::DAY_OF_MONTH,
150*993b0882SAndroid Build Coastguard Worker &day_of_month);
151*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetDayOfMonth(day_of_month))
152*993b0882SAndroid Build Coastguard Worker }
153*993b0882SAndroid Build Coastguard Worker if (parse_data.HasAbsoluteValue(DatetimeComponent::ComponentType::HOUR)) {
154*993b0882SAndroid Build Coastguard Worker int hour;
155*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::HOUR, &hour);
156*993b0882SAndroid Build Coastguard Worker if (parse_data.HasFieldType(DatetimeComponent::ComponentType::MERIDIEM)) {
157*993b0882SAndroid Build Coastguard Worker int merdiem;
158*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::MERIDIEM,
159*993b0882SAndroid Build Coastguard Worker &merdiem);
160*993b0882SAndroid Build Coastguard Worker if (merdiem == 1 && hour < 12) {
161*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetHourOfDay(hour + 12))
162*993b0882SAndroid Build Coastguard Worker } else if (merdiem == 0 && hour == 12) {
163*993b0882SAndroid Build Coastguard Worker // Set hour of the day's value to zero (12am == 0:00 in 24 hour format).
164*993b0882SAndroid Build Coastguard Worker // Please see issue b/139923083.
165*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetHourOfDay(0));
166*993b0882SAndroid Build Coastguard Worker } else {
167*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetHourOfDay(hour))
168*993b0882SAndroid Build Coastguard Worker }
169*993b0882SAndroid Build Coastguard Worker } else {
170*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetHourOfDay(hour))
171*993b0882SAndroid Build Coastguard Worker }
172*993b0882SAndroid Build Coastguard Worker }
173*993b0882SAndroid Build Coastguard Worker if (parse_data.HasAbsoluteValue(DatetimeComponent::ComponentType::MINUTE)) {
174*993b0882SAndroid Build Coastguard Worker int minute;
175*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::MINUTE, &minute);
176*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetMinute(minute))
177*993b0882SAndroid Build Coastguard Worker }
178*993b0882SAndroid Build Coastguard Worker if (parse_data.HasAbsoluteValue(DatetimeComponent::ComponentType::SECOND)) {
179*993b0882SAndroid Build Coastguard Worker int second;
180*993b0882SAndroid Build Coastguard Worker parse_data.GetFieldValue(DatetimeComponent::ComponentType::SECOND, &second);
181*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetSecond(second))
182*993b0882SAndroid Build Coastguard Worker }
183*993b0882SAndroid Build Coastguard Worker if (should_round_to_granularity) {
184*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(RoundToGranularity(*granularity, calendar))
185*993b0882SAndroid Build Coastguard Worker }
186*993b0882SAndroid Build Coastguard Worker
187*993b0882SAndroid Build Coastguard Worker int64 calendar_millis;
188*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->GetTimeInMillis(&calendar_millis))
189*993b0882SAndroid Build Coastguard Worker if (prefer_future_for_unspecified_date &&
190*993b0882SAndroid Build Coastguard Worker calendar_millis < reference_time_ms_utc &&
191*993b0882SAndroid Build Coastguard Worker HasOnlyTimeComponents(parse_data)) {
192*993b0882SAndroid Build Coastguard Worker calendar->AddDayOfMonth(1);
193*993b0882SAndroid Build Coastguard Worker }
194*993b0882SAndroid Build Coastguard Worker
195*993b0882SAndroid Build Coastguard Worker return true;
196*993b0882SAndroid Build Coastguard Worker }
197*993b0882SAndroid Build Coastguard Worker
198*993b0882SAndroid Build Coastguard Worker template <class TCalendar>
ApplyRelationField(const DatetimeComponent & relative_date_time_component,TCalendar * calendar)199*993b0882SAndroid Build Coastguard Worker bool CalendarLibTempl<TCalendar>::ApplyRelationField(
200*993b0882SAndroid Build Coastguard Worker const DatetimeComponent& relative_date_time_component,
201*993b0882SAndroid Build Coastguard Worker TCalendar* calendar) const {
202*993b0882SAndroid Build Coastguard Worker switch (relative_date_time_component.relative_qualifier) {
203*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::UNSPECIFIED:
204*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "UNSPECIFIED RelationType.";
205*993b0882SAndroid Build Coastguard Worker return false;
206*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::NEXT:
207*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(AdjustByRelation(relative_date_time_component,
208*993b0882SAndroid Build Coastguard Worker /*distance=*/1,
209*993b0882SAndroid Build Coastguard Worker /*allow_today=*/false, calendar));
210*993b0882SAndroid Build Coastguard Worker return true;
211*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::THIS:
212*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(AdjustByRelation(relative_date_time_component,
213*993b0882SAndroid Build Coastguard Worker /*distance=*/1,
214*993b0882SAndroid Build Coastguard Worker /*allow_today=*/true, calendar))
215*993b0882SAndroid Build Coastguard Worker return true;
216*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::LAST:
217*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(AdjustByRelation(relative_date_time_component,
218*993b0882SAndroid Build Coastguard Worker /*distance=*/-1,
219*993b0882SAndroid Build Coastguard Worker /*allow_today=*/false, calendar))
220*993b0882SAndroid Build Coastguard Worker return true;
221*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::NOW:
222*993b0882SAndroid Build Coastguard Worker return true; // NOOP
223*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::TOMORROW:
224*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddDayOfMonth(1));
225*993b0882SAndroid Build Coastguard Worker return true;
226*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::YESTERDAY:
227*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddDayOfMonth(-1));
228*993b0882SAndroid Build Coastguard Worker return true;
229*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::PAST:
230*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(
231*993b0882SAndroid Build Coastguard Worker AdjustByRelation(relative_date_time_component,
232*993b0882SAndroid Build Coastguard Worker relative_date_time_component.relative_count,
233*993b0882SAndroid Build Coastguard Worker /*allow_today=*/false, calendar))
234*993b0882SAndroid Build Coastguard Worker return true;
235*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::RelativeQualifier::FUTURE:
236*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(
237*993b0882SAndroid Build Coastguard Worker AdjustByRelation(relative_date_time_component,
238*993b0882SAndroid Build Coastguard Worker relative_date_time_component.relative_count,
239*993b0882SAndroid Build Coastguard Worker /*allow_today=*/false, calendar))
240*993b0882SAndroid Build Coastguard Worker return true;
241*993b0882SAndroid Build Coastguard Worker }
242*993b0882SAndroid Build Coastguard Worker return false;
243*993b0882SAndroid Build Coastguard Worker }
244*993b0882SAndroid Build Coastguard Worker
245*993b0882SAndroid Build Coastguard Worker template <class TCalendar>
RoundToGranularity(DatetimeGranularity granularity,TCalendar * calendar)246*993b0882SAndroid Build Coastguard Worker bool CalendarLibTempl<TCalendar>::RoundToGranularity(
247*993b0882SAndroid Build Coastguard Worker DatetimeGranularity granularity, TCalendar* calendar) const {
248*993b0882SAndroid Build Coastguard Worker // Force recomputation before doing the rounding.
249*993b0882SAndroid Build Coastguard Worker int unused;
250*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->GetDayOfWeek(&unused));
251*993b0882SAndroid Build Coastguard Worker
252*993b0882SAndroid Build Coastguard Worker switch (granularity) {
253*993b0882SAndroid Build Coastguard Worker case GRANULARITY_YEAR:
254*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetMonth(0));
255*993b0882SAndroid Build Coastguard Worker TC3_FALLTHROUGH_INTENDED;
256*993b0882SAndroid Build Coastguard Worker case GRANULARITY_MONTH:
257*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetDayOfMonth(1));
258*993b0882SAndroid Build Coastguard Worker TC3_FALLTHROUGH_INTENDED;
259*993b0882SAndroid Build Coastguard Worker case GRANULARITY_DAY:
260*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetHourOfDay(0));
261*993b0882SAndroid Build Coastguard Worker TC3_FALLTHROUGH_INTENDED;
262*993b0882SAndroid Build Coastguard Worker case GRANULARITY_HOUR:
263*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetMinute(0));
264*993b0882SAndroid Build Coastguard Worker TC3_FALLTHROUGH_INTENDED;
265*993b0882SAndroid Build Coastguard Worker case GRANULARITY_MINUTE:
266*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetSecond(0));
267*993b0882SAndroid Build Coastguard Worker break;
268*993b0882SAndroid Build Coastguard Worker
269*993b0882SAndroid Build Coastguard Worker case GRANULARITY_WEEK:
270*993b0882SAndroid Build Coastguard Worker int first_day_of_week;
271*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->GetFirstDayOfWeek(&first_day_of_week));
272*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetDayOfWeek(first_day_of_week));
273*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetHourOfDay(0));
274*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetMinute(0));
275*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetSecond(0));
276*993b0882SAndroid Build Coastguard Worker break;
277*993b0882SAndroid Build Coastguard Worker
278*993b0882SAndroid Build Coastguard Worker case GRANULARITY_UNKNOWN:
279*993b0882SAndroid Build Coastguard Worker case GRANULARITY_SECOND:
280*993b0882SAndroid Build Coastguard Worker break;
281*993b0882SAndroid Build Coastguard Worker }
282*993b0882SAndroid Build Coastguard Worker return true;
283*993b0882SAndroid Build Coastguard Worker }
284*993b0882SAndroid Build Coastguard Worker
285*993b0882SAndroid Build Coastguard Worker template <class TCalendar>
AdjustByRelation(DatetimeComponent date_time_component,int distance,bool allow_today,TCalendar * calendar)286*993b0882SAndroid Build Coastguard Worker bool CalendarLibTempl<TCalendar>::AdjustByRelation(
287*993b0882SAndroid Build Coastguard Worker DatetimeComponent date_time_component, int distance, bool allow_today,
288*993b0882SAndroid Build Coastguard Worker TCalendar* calendar) const {
289*993b0882SAndroid Build Coastguard Worker const int distance_sign = distance < 0 ? -1 : 1;
290*993b0882SAndroid Build Coastguard Worker switch (date_time_component.component_type) {
291*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::DAY_OF_WEEK:
292*993b0882SAndroid Build Coastguard Worker if (!allow_today) {
293*993b0882SAndroid Build Coastguard Worker // If we're not including the same day as the reference, skip it.
294*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddDayOfMonth(distance_sign))
295*993b0882SAndroid Build Coastguard Worker }
296*993b0882SAndroid Build Coastguard Worker // Keep walking back until we hit the desired day of the week.
297*993b0882SAndroid Build Coastguard Worker while (distance != 0) {
298*993b0882SAndroid Build Coastguard Worker int day_of_week;
299*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->GetDayOfWeek(&day_of_week))
300*993b0882SAndroid Build Coastguard Worker if (day_of_week == (date_time_component.value)) {
301*993b0882SAndroid Build Coastguard Worker distance += -distance_sign;
302*993b0882SAndroid Build Coastguard Worker if (distance == 0) break;
303*993b0882SAndroid Build Coastguard Worker }
304*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddDayOfMonth(distance_sign))
305*993b0882SAndroid Build Coastguard Worker }
306*993b0882SAndroid Build Coastguard Worker return true;
307*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::SECOND:
308*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddSecond(distance));
309*993b0882SAndroid Build Coastguard Worker return true;
310*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::MINUTE:
311*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddMinute(distance));
312*993b0882SAndroid Build Coastguard Worker return true;
313*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::HOUR:
314*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddHourOfDay(distance));
315*993b0882SAndroid Build Coastguard Worker return true;
316*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::DAY_OF_MONTH:
317*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddDayOfMonth(distance));
318*993b0882SAndroid Build Coastguard Worker return true;
319*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::WEEK:
320*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddDayOfMonth(7 * distance))
321*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetDayOfWeek(1))
322*993b0882SAndroid Build Coastguard Worker return true;
323*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::MONTH:
324*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddMonth(distance))
325*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetDayOfMonth(1))
326*993b0882SAndroid Build Coastguard Worker return true;
327*993b0882SAndroid Build Coastguard Worker case DatetimeComponent::ComponentType::YEAR:
328*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->AddYear(distance))
329*993b0882SAndroid Build Coastguard Worker TC3_CALENDAR_CHECK(calendar->SetDayOfYear(1))
330*993b0882SAndroid Build Coastguard Worker return true;
331*993b0882SAndroid Build Coastguard Worker default:
332*993b0882SAndroid Build Coastguard Worker TC3_LOG(ERROR) << "Unknown relation type: "
333*993b0882SAndroid Build Coastguard Worker << static_cast<int>(date_time_component.component_type);
334*993b0882SAndroid Build Coastguard Worker return false;
335*993b0882SAndroid Build Coastguard Worker }
336*993b0882SAndroid Build Coastguard Worker return false;
337*993b0882SAndroid Build Coastguard Worker }
338*993b0882SAndroid Build Coastguard Worker
339*993b0882SAndroid Build Coastguard Worker template <class TCalendar>
GetGranularity(const DatetimeParsedData & data)340*993b0882SAndroid Build Coastguard Worker DatetimeGranularity CalendarLibTempl<TCalendar>::GetGranularity(
341*993b0882SAndroid Build Coastguard Worker const DatetimeParsedData& data) const {
342*993b0882SAndroid Build Coastguard Worker return data.GetFinestGranularity();
343*993b0882SAndroid Build Coastguard Worker }
344*993b0882SAndroid Build Coastguard Worker
345*993b0882SAndroid Build Coastguard Worker }; // namespace calendar
346*993b0882SAndroid Build Coastguard Worker
347*993b0882SAndroid Build Coastguard Worker #undef TC3_CALENDAR_CHECK
348*993b0882SAndroid Build Coastguard Worker
349*993b0882SAndroid Build Coastguard Worker } // namespace libtextclassifier3
350*993b0882SAndroid Build Coastguard Worker
351*993b0882SAndroid Build Coastguard Worker #endif // LIBTEXTCLASSIFIER_UTILS_CALENDAR_CALENDAR_COMMON_H_
352