1 /*
2  * Copyright 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package androidx.appsearch.utils;
18 
19 import static androidx.annotation.RestrictTo.Scope.LIBRARY;
20 
21 import androidx.annotation.RestrictTo;
22 
23 import org.jspecify.annotations.NonNull;
24 
25 import java.text.DateFormat;
26 import java.text.ParseException;
27 import java.text.SimpleDateFormat;
28 import java.util.Date;
29 import java.util.Locale;
30 
31 /**
32  * Helper class used to validate date time formats.
33  *
34  * @exportToFramework:hide
35  */
36 @RestrictTo(LIBRARY)
37 public final class DateTimeFormatValidator {
DateTimeFormatValidator()38     private DateTimeFormatValidator() {}
39 
40     /**
41      * Returns true if the date string matches yyyy-MM-dd
42      */
validateISO8601Date(@onNull String dateString)43     public static boolean validateISO8601Date(@NonNull String dateString) {
44         return validateDateFormat("yyyy-MM-dd", dateString);
45     }
46 
47     /**
48      * Returns true if the date string matches yyyy-MM-ddTHH:mm:ss
49      */
validateISO8601DateTime(@onNull String dateString)50     public static boolean validateISO8601DateTime(@NonNull String dateString) {
51         return validateDateFormat("yyyy-MM-dd'T'HH:mm", dateString)
52                 || validateDateFormat("yyyy-MM-dd'T'HH:mm:ss", dateString);
53     }
54 
55     /**
56      * Returns true if the date string matches the provided format exactly.
57      */
validateDateFormat(@onNull String format, @NonNull String dateString)58     public static boolean validateDateFormat(@NonNull String format, @NonNull String dateString) {
59         // ISO 8601 DateTime format must be represented using arabic numerals (0-9). en-US is
60         // one of many locales that uses arabic numerals, therefore it is used during formatting.
61         // Even if the user's device is not in the en-US locale, this will still work since ISO
62         // 8601 is an international standard, and does not change based on locales.
63         DateFormat dateFormat = new SimpleDateFormat(format, Locale.US);
64         dateFormat.setLenient(false);
65         try {
66             Date date = dateFormat.parse(dateString);
67             // ensure exact match
68             if (date == null || !dateString.equals(dateFormat.format(date))) {
69                 return false;
70             }
71         } catch (ParseException e) {
72             return false;
73         }
74 
75         return true;
76     }
77 }
78