xref: /aosp_15_r20/external/libtextclassifier/native/annotator/datetime/datetime-grounder.cc (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
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 #include "annotator/datetime/datetime-grounder.h"
18*993b0882SAndroid Build Coastguard Worker 
19*993b0882SAndroid Build Coastguard Worker #include <algorithm>
20*993b0882SAndroid Build Coastguard Worker #include <limits>
21*993b0882SAndroid Build Coastguard Worker #include <unordered_map>
22*993b0882SAndroid Build Coastguard Worker #include <vector>
23*993b0882SAndroid Build Coastguard Worker 
24*993b0882SAndroid Build Coastguard Worker #include "annotator/datetime/datetime_generated.h"
25*993b0882SAndroid Build Coastguard Worker #include "annotator/datetime/utils.h"
26*993b0882SAndroid Build Coastguard Worker #include "annotator/types.h"
27*993b0882SAndroid Build Coastguard Worker #include "utils/base/integral_types.h"
28*993b0882SAndroid Build Coastguard Worker #include "utils/base/status.h"
29*993b0882SAndroid Build Coastguard Worker #include "utils/base/status_macros.h"
30*993b0882SAndroid Build Coastguard Worker 
31*993b0882SAndroid Build Coastguard Worker using ::libtextclassifier3::grammar::datetime::AbsoluteDateTime;
32*993b0882SAndroid Build Coastguard Worker using ::libtextclassifier3::grammar::datetime::ComponentType;
33*993b0882SAndroid Build Coastguard Worker using ::libtextclassifier3::grammar::datetime::Meridiem;
34*993b0882SAndroid Build Coastguard Worker using ::libtextclassifier3::grammar::datetime::RelativeDateTime;
35*993b0882SAndroid Build Coastguard Worker using ::libtextclassifier3::grammar::datetime::RelativeDatetimeComponent;
36*993b0882SAndroid Build Coastguard Worker using ::libtextclassifier3::grammar::datetime::UngroundedDatetime;
37*993b0882SAndroid Build Coastguard Worker using ::libtextclassifier3::grammar::datetime::RelativeDatetimeComponent_::
38*993b0882SAndroid Build Coastguard Worker     Modifier;
39*993b0882SAndroid Build Coastguard Worker 
40*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
41*993b0882SAndroid Build Coastguard Worker 
42*993b0882SAndroid Build Coastguard Worker namespace {
43*993b0882SAndroid Build Coastguard Worker 
44*993b0882SAndroid Build Coastguard Worker const std::unordered_map<int, int> kMonthDefaultLastDayMap(
45*993b0882SAndroid Build Coastguard Worker     {{/*no_month*/ 0, 31},
46*993b0882SAndroid Build Coastguard Worker      {/*January*/ 1, 31},
47*993b0882SAndroid Build Coastguard Worker      {/*Febuary*/ 2, 29},
48*993b0882SAndroid Build Coastguard Worker      {/*March*/ 3, 31},
49*993b0882SAndroid Build Coastguard Worker      {/*April*/ 4, 30},
50*993b0882SAndroid Build Coastguard Worker      {/*May*/ 5, 31},
51*993b0882SAndroid Build Coastguard Worker      {/*June*/ 6, 30},
52*993b0882SAndroid Build Coastguard Worker      {/*July*/ 7, 31},
53*993b0882SAndroid Build Coastguard Worker      {/*August*/ 8, 31},
54*993b0882SAndroid Build Coastguard Worker      {/*September*/ 9, 30},
55*993b0882SAndroid Build Coastguard Worker      {/*October*/ 10, 31},
56*993b0882SAndroid Build Coastguard Worker      {/*November*/ 11, 30},
57*993b0882SAndroid Build Coastguard Worker      {/*December*/ 12, 31}});
58*993b0882SAndroid Build Coastguard Worker 
IsValidDatetime(const AbsoluteDateTime * absolute_datetime)59*993b0882SAndroid Build Coastguard Worker bool IsValidDatetime(const AbsoluteDateTime* absolute_datetime) {
60*993b0882SAndroid Build Coastguard Worker   // Sanity Checks.
61*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->minute() > 59 || absolute_datetime->second() > 59 ||
62*993b0882SAndroid Build Coastguard Worker       absolute_datetime->hour() > 23 || absolute_datetime->month() > 12 ||
63*993b0882SAndroid Build Coastguard Worker       absolute_datetime->month() == 0) {
64*993b0882SAndroid Build Coastguard Worker     return false;
65*993b0882SAndroid Build Coastguard Worker   }
66*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->day() >= 0) {
67*993b0882SAndroid Build Coastguard Worker     int min_day_value = 1;
68*993b0882SAndroid Build Coastguard Worker     int max_day_value = 31;
69*993b0882SAndroid Build Coastguard Worker     if (absolute_datetime->month() >= 0 && absolute_datetime->month() <= 12) {
70*993b0882SAndroid Build Coastguard Worker       max_day_value = kMonthDefaultLastDayMap.at(absolute_datetime->month());
71*993b0882SAndroid Build Coastguard Worker       if (absolute_datetime->day() < min_day_value ||
72*993b0882SAndroid Build Coastguard Worker           absolute_datetime->day() > max_day_value) {
73*993b0882SAndroid Build Coastguard Worker         return false;
74*993b0882SAndroid Build Coastguard Worker       }
75*993b0882SAndroid Build Coastguard Worker     }
76*993b0882SAndroid Build Coastguard Worker   }
77*993b0882SAndroid Build Coastguard Worker   return true;
78*993b0882SAndroid Build Coastguard Worker }
79*993b0882SAndroid Build Coastguard Worker 
IsValidDatetime(const RelativeDateTime * relative_datetime)80*993b0882SAndroid Build Coastguard Worker bool IsValidDatetime(const RelativeDateTime* relative_datetime) {
81*993b0882SAndroid Build Coastguard Worker   if (relative_datetime->base()) {
82*993b0882SAndroid Build Coastguard Worker     return IsValidDatetime(relative_datetime->base());
83*993b0882SAndroid Build Coastguard Worker   }
84*993b0882SAndroid Build Coastguard Worker   return true;
85*993b0882SAndroid Build Coastguard Worker }
86*993b0882SAndroid Build Coastguard Worker 
ToRelativeQualifier(const Modifier & modifier)87*993b0882SAndroid Build Coastguard Worker StatusOr<DatetimeComponent::RelativeQualifier> ToRelativeQualifier(
88*993b0882SAndroid Build Coastguard Worker     const Modifier& modifier) {
89*993b0882SAndroid Build Coastguard Worker   switch (modifier) {
90*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_THIS:
91*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::THIS;
92*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_LAST:
93*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::LAST;
94*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_NEXT:
95*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::NEXT;
96*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_NOW:
97*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::NOW;
98*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_TOMORROW:
99*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::TOMORROW;
100*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_YESTERDAY:
101*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::YESTERDAY;
102*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_PAST:
103*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::PAST;
104*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_FUTURE:
105*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::FUTURE;
106*993b0882SAndroid Build Coastguard Worker     case Modifier::Modifier_UNSPECIFIED:
107*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::RelativeQualifier::UNSPECIFIED;
108*993b0882SAndroid Build Coastguard Worker     default:
109*993b0882SAndroid Build Coastguard Worker       return Status(StatusCode::INTERNAL,
110*993b0882SAndroid Build Coastguard Worker                     "Couldn't parse the Modifier to RelativeQualifier.");
111*993b0882SAndroid Build Coastguard Worker   }
112*993b0882SAndroid Build Coastguard Worker }
113*993b0882SAndroid Build Coastguard Worker 
ToComponentType(const grammar::datetime::ComponentType component_type)114*993b0882SAndroid Build Coastguard Worker StatusOr<DatetimeComponent::ComponentType> ToComponentType(
115*993b0882SAndroid Build Coastguard Worker     const grammar::datetime::ComponentType component_type) {
116*993b0882SAndroid Build Coastguard Worker   switch (component_type) {
117*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_YEAR:
118*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::YEAR;
119*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_MONTH:
120*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::MONTH;
121*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_WEEK:
122*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::WEEK;
123*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_DAY_OF_WEEK:
124*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::DAY_OF_WEEK;
125*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_DAY_OF_MONTH:
126*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::DAY_OF_MONTH;
127*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_HOUR:
128*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::HOUR;
129*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_MINUTE:
130*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::MINUTE;
131*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_SECOND:
132*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::SECOND;
133*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_MERIDIEM:
134*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::MERIDIEM;
135*993b0882SAndroid Build Coastguard Worker     case grammar::datetime::ComponentType_UNSPECIFIED:
136*993b0882SAndroid Build Coastguard Worker       return DatetimeComponent::ComponentType::UNSPECIFIED;
137*993b0882SAndroid Build Coastguard Worker     default:
138*993b0882SAndroid Build Coastguard Worker       return Status(StatusCode::INTERNAL,
139*993b0882SAndroid Build Coastguard Worker                     "Couldn't parse the DatetimeComponent's ComponentType from "
140*993b0882SAndroid Build Coastguard Worker                     "grammar's datetime ComponentType.");
141*993b0882SAndroid Build Coastguard Worker   }
142*993b0882SAndroid Build Coastguard Worker }
143*993b0882SAndroid Build Coastguard Worker 
FillAbsoluteDateTimeComponents(const grammar::datetime::AbsoluteDateTime * absolute_datetime,DatetimeParsedData * datetime_parsed_data)144*993b0882SAndroid Build Coastguard Worker void FillAbsoluteDateTimeComponents(
145*993b0882SAndroid Build Coastguard Worker     const grammar::datetime::AbsoluteDateTime* absolute_datetime,
146*993b0882SAndroid Build Coastguard Worker     DatetimeParsedData* datetime_parsed_data) {
147*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->year() >= 0) {
148*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
149*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::YEAR,
150*993b0882SAndroid Build Coastguard Worker         GetAdjustedYear(absolute_datetime->year()));
151*993b0882SAndroid Build Coastguard Worker   }
152*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->month() >= 0) {
153*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
154*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::MONTH, absolute_datetime->month());
155*993b0882SAndroid Build Coastguard Worker   }
156*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->day() >= 0) {
157*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
158*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::DAY_OF_MONTH,
159*993b0882SAndroid Build Coastguard Worker         absolute_datetime->day());
160*993b0882SAndroid Build Coastguard Worker   }
161*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->week_day() >= 0) {
162*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
163*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::DAY_OF_WEEK,
164*993b0882SAndroid Build Coastguard Worker         absolute_datetime->week_day());
165*993b0882SAndroid Build Coastguard Worker   }
166*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->hour() >= 0) {
167*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
168*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::HOUR, absolute_datetime->hour());
169*993b0882SAndroid Build Coastguard Worker   }
170*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->minute() >= 0) {
171*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
172*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::MINUTE, absolute_datetime->minute());
173*993b0882SAndroid Build Coastguard Worker   }
174*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->second() >= 0) {
175*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
176*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::SECOND, absolute_datetime->second());
177*993b0882SAndroid Build Coastguard Worker   }
178*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->meridiem() != grammar::datetime::Meridiem_UNKNOWN) {
179*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
180*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::MERIDIEM,
181*993b0882SAndroid Build Coastguard Worker         absolute_datetime->meridiem() == grammar::datetime::Meridiem_AM ? 0
182*993b0882SAndroid Build Coastguard Worker                                                                         : 1);
183*993b0882SAndroid Build Coastguard Worker   }
184*993b0882SAndroid Build Coastguard Worker   if (absolute_datetime->time_zone()) {
185*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data->SetAbsoluteValue(
186*993b0882SAndroid Build Coastguard Worker         DatetimeComponent::ComponentType::ZONE_OFFSET,
187*993b0882SAndroid Build Coastguard Worker         absolute_datetime->time_zone()->utc_offset_mins());
188*993b0882SAndroid Build Coastguard Worker   }
189*993b0882SAndroid Build Coastguard Worker }
190*993b0882SAndroid Build Coastguard Worker 
FillRelativeDateTimeComponents(const grammar::datetime::RelativeDateTime * relative_datetime)191*993b0882SAndroid Build Coastguard Worker StatusOr<DatetimeParsedData> FillRelativeDateTimeComponents(
192*993b0882SAndroid Build Coastguard Worker     const grammar::datetime::RelativeDateTime* relative_datetime) {
193*993b0882SAndroid Build Coastguard Worker   DatetimeParsedData datetime_parsed_data;
194*993b0882SAndroid Build Coastguard Worker   for (const RelativeDatetimeComponent* relative_component :
195*993b0882SAndroid Build Coastguard Worker        *relative_datetime->relative_datetime_component()) {
196*993b0882SAndroid Build Coastguard Worker     TC3_ASSIGN_OR_RETURN(const DatetimeComponent::ComponentType component_type,
197*993b0882SAndroid Build Coastguard Worker                          ToComponentType(relative_component->component_type()));
198*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data.SetRelativeCount(component_type,
199*993b0882SAndroid Build Coastguard Worker                                           relative_component->value());
200*993b0882SAndroid Build Coastguard Worker     TC3_ASSIGN_OR_RETURN(
201*993b0882SAndroid Build Coastguard Worker         const DatetimeComponent::RelativeQualifier relative_qualifier,
202*993b0882SAndroid Build Coastguard Worker         ToRelativeQualifier(relative_component->modifier()));
203*993b0882SAndroid Build Coastguard Worker     datetime_parsed_data.SetRelativeValue(component_type, relative_qualifier);
204*993b0882SAndroid Build Coastguard Worker   }
205*993b0882SAndroid Build Coastguard Worker   if (relative_datetime->base()) {
206*993b0882SAndroid Build Coastguard Worker     FillAbsoluteDateTimeComponents(relative_datetime->base(),
207*993b0882SAndroid Build Coastguard Worker                                    &datetime_parsed_data);
208*993b0882SAndroid Build Coastguard Worker   }
209*993b0882SAndroid Build Coastguard Worker   return datetime_parsed_data;
210*993b0882SAndroid Build Coastguard Worker }
211*993b0882SAndroid Build Coastguard Worker 
212*993b0882SAndroid Build Coastguard Worker }  // namespace
213*993b0882SAndroid Build Coastguard Worker 
DatetimeGrounder(const CalendarLib * calendarlib)214*993b0882SAndroid Build Coastguard Worker DatetimeGrounder::DatetimeGrounder(const CalendarLib* calendarlib)
215*993b0882SAndroid Build Coastguard Worker     : calendarlib_(*calendarlib) {}
216*993b0882SAndroid Build Coastguard Worker 
Ground(const int64 reference_time_ms_utc,const std::string & reference_timezone,const std::string & reference_locale,const grammar::datetime::UngroundedDatetime * ungrounded_datetime) const217*993b0882SAndroid Build Coastguard Worker StatusOr<std::vector<DatetimeParseResult>> DatetimeGrounder::Ground(
218*993b0882SAndroid Build Coastguard Worker     const int64 reference_time_ms_utc, const std::string& reference_timezone,
219*993b0882SAndroid Build Coastguard Worker     const std::string& reference_locale,
220*993b0882SAndroid Build Coastguard Worker     const grammar::datetime::UngroundedDatetime* ungrounded_datetime) const {
221*993b0882SAndroid Build Coastguard Worker   DatetimeParsedData datetime_parsed_data;
222*993b0882SAndroid Build Coastguard Worker   if (ungrounded_datetime->absolute_datetime()) {
223*993b0882SAndroid Build Coastguard Worker     FillAbsoluteDateTimeComponents(ungrounded_datetime->absolute_datetime(),
224*993b0882SAndroid Build Coastguard Worker                                    &datetime_parsed_data);
225*993b0882SAndroid Build Coastguard Worker   } else if (ungrounded_datetime->relative_datetime()) {
226*993b0882SAndroid Build Coastguard Worker     TC3_ASSIGN_OR_RETURN(datetime_parsed_data,
227*993b0882SAndroid Build Coastguard Worker                          FillRelativeDateTimeComponents(
228*993b0882SAndroid Build Coastguard Worker                              ungrounded_datetime->relative_datetime()));
229*993b0882SAndroid Build Coastguard Worker   }
230*993b0882SAndroid Build Coastguard Worker   std::vector<DatetimeParsedData> interpretations;
231*993b0882SAndroid Build Coastguard Worker   FillInterpretations(datetime_parsed_data,
232*993b0882SAndroid Build Coastguard Worker                       calendarlib_.GetGranularity(datetime_parsed_data),
233*993b0882SAndroid Build Coastguard Worker                       &interpretations);
234*993b0882SAndroid Build Coastguard Worker   std::vector<DatetimeParseResult> datetime_parse_result;
235*993b0882SAndroid Build Coastguard Worker 
236*993b0882SAndroid Build Coastguard Worker   for (const DatetimeParsedData& interpretation : interpretations) {
237*993b0882SAndroid Build Coastguard Worker     std::vector<DatetimeComponent> date_components;
238*993b0882SAndroid Build Coastguard Worker     interpretation.GetDatetimeComponents(&date_components);
239*993b0882SAndroid Build Coastguard Worker     DatetimeParseResult result;
240*993b0882SAndroid Build Coastguard Worker     // Text classifier only provides ambiguity limited to “AM/PM” which is
241*993b0882SAndroid Build Coastguard Worker     // encoded in the pair of DatetimeParseResult; both corresponding to the
242*993b0882SAndroid Build Coastguard Worker     // same date, but one corresponding to “AM” and the other one corresponding
243*993b0882SAndroid Build Coastguard Worker     //  to “PM”.
244*993b0882SAndroid Build Coastguard Worker     if (!calendarlib_.InterpretParseData(
245*993b0882SAndroid Build Coastguard Worker             interpretation, reference_time_ms_utc, reference_timezone,
246*993b0882SAndroid Build Coastguard Worker             reference_locale, /*prefer_future_for_unspecified_date=*/true,
247*993b0882SAndroid Build Coastguard Worker             &(result.time_ms_utc), &(result.granularity))) {
248*993b0882SAndroid Build Coastguard Worker       return Status(
249*993b0882SAndroid Build Coastguard Worker           StatusCode::INTERNAL,
250*993b0882SAndroid Build Coastguard Worker           "Couldn't parse the UngroundedDatetime to DatetimeParseResult.");
251*993b0882SAndroid Build Coastguard Worker     }
252*993b0882SAndroid Build Coastguard Worker 
253*993b0882SAndroid Build Coastguard Worker     // Sort the date time units by component type.
254*993b0882SAndroid Build Coastguard Worker     std::stable_sort(date_components.begin(), date_components.end(),
255*993b0882SAndroid Build Coastguard Worker                      [](DatetimeComponent a, DatetimeComponent b) {
256*993b0882SAndroid Build Coastguard Worker                        return a.component_type > b.component_type;
257*993b0882SAndroid Build Coastguard Worker                      });
258*993b0882SAndroid Build Coastguard Worker     result.datetime_components.swap(date_components);
259*993b0882SAndroid Build Coastguard Worker     datetime_parse_result.push_back(result);
260*993b0882SAndroid Build Coastguard Worker   }
261*993b0882SAndroid Build Coastguard Worker   return datetime_parse_result;
262*993b0882SAndroid Build Coastguard Worker }
263*993b0882SAndroid Build Coastguard Worker 
IsValidUngroundedDatetime(const UngroundedDatetime * ungrounded_datetime) const264*993b0882SAndroid Build Coastguard Worker bool DatetimeGrounder::IsValidUngroundedDatetime(
265*993b0882SAndroid Build Coastguard Worker     const UngroundedDatetime* ungrounded_datetime) const {
266*993b0882SAndroid Build Coastguard Worker   if (ungrounded_datetime->absolute_datetime()) {
267*993b0882SAndroid Build Coastguard Worker     return IsValidDatetime(ungrounded_datetime->absolute_datetime());
268*993b0882SAndroid Build Coastguard Worker   } else if (ungrounded_datetime->relative_datetime()) {
269*993b0882SAndroid Build Coastguard Worker     return IsValidDatetime(ungrounded_datetime->relative_datetime());
270*993b0882SAndroid Build Coastguard Worker   }
271*993b0882SAndroid Build Coastguard Worker   return false;
272*993b0882SAndroid Build Coastguard Worker }
273*993b0882SAndroid Build Coastguard Worker 
274*993b0882SAndroid Build Coastguard Worker }  // namespace libtextclassifier3
275