xref: /aosp_15_r20/cts/tests/tests/text/src/android/text/format/cts/NativeTimeFunctions.java (revision b7c941bb3fa97aba169d73cee0bed2de8ac964bf)
1 /*
2  * Copyright (C) 2019 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 android.text.format.cts;
18 
19 import static junit.framework.Assert.assertEquals;
20 
21 import java.time.LocalDateTime;
22 
23 /**
24  * A test helper class for calling localtime_r() and mktime() for a given time zone.
25  */
26 class NativeTimeFunctions {
27     static {
28         System.loadLibrary("ctstext_jni");
29     }
30 
NativeTimeFunctions()31     private NativeTimeFunctions() {}
32 
localtime_tz(int timep, String tzId)33     private static native StructTm localtime_tz(int timep, String tzId);
mktime_tz(StructTm tm, String tzId)34     private static native int mktime_tz(StructTm tm, String tzId);
35 
36     /**
37      * Tries native time functions to see if they produce expected results.
38      *
39      * <p>localtime() is called with {tzId + localDateTime} and the result is checked against
40      * timeMillis. mktime() is called with {tzId + timeMillis} and the result is checked against
41      * localDateTime.
42      *
43      * <p>This method only works to second precision in the range of times that Android's
44      * localtime() / mktime() work across all architectures; signed int32 seconds (because time_t
45      * is dependent on word-size on Android). It may not work for ambiguous local times, i.e. local
46      * times that don't exist (because of a "skip forward") or are duplicated (because of a "fall
47      * back"). This method is not threadsafe as it uses the TZ environment variable.
48      */
assertNativeTimeResults(String tzId, LocalDateTime localDateTime, long timeMillis)49     static void assertNativeTimeResults(String tzId, LocalDateTime localDateTime, long timeMillis) {
50         assertLocaltimeResult(tzId, timeMillis, localDateTime);
51         assertMktimeResult(tzId, localDateTime, timeMillis);
52     }
53 
assertLocaltimeResult(String tzId, long timeMillis, LocalDateTime expected)54     private static void assertLocaltimeResult(String tzId, long timeMillis,
55             LocalDateTime expected) {
56         StructTm structTm = localtime_tz((int) (timeMillis / 1000), tzId);
57 
58         LocalDateTime actual = LocalDateTime.of(
59                 structTm.tm_year + 1900,
60                 structTm.tm_mon + 1,
61                 structTm.tm_mday,
62                 structTm.tm_hour,
63                 structTm.tm_min,
64                 structTm.tm_sec);
65         assertEquals(timeMillis + " in " + tzId, expected, actual);
66     }
67 
assertMktimeResult(String tzId, LocalDateTime localDateTime, long expectedTimeMillis)68     private static void assertMktimeResult(String tzId, LocalDateTime localDateTime,
69             long expectedTimeMillis) {
70 
71         // Create a StructTm from the (second precision) information held in the LocalDateTime.
72         StructTm tm = new StructTm();
73         tm.tm_sec = localDateTime.getSecond();
74         tm.tm_min = localDateTime.getMinute();
75         tm.tm_hour = localDateTime.getHour();
76         tm.tm_mday = localDateTime.getDayOfMonth();
77         tm.tm_mon = localDateTime.getMonthValue() - 1;
78         tm.tm_year = localDateTime.getYear() - 1900;
79         tm.tm_isdst = -1;
80         int actualTimeMillis = mktime_tz(tm, tzId);
81         assertEquals(localDateTime + " in " + tzId,
82                 expectedTimeMillis, actualTimeMillis * 1000L);
83     }
84 
85     /**
86      * A basic Java representation of bionic's struct tm.
87      */
88     static class StructTm {
89         public int tm_sec;    /* Seconds (0-60) */
90         public int tm_min;    /* Minutes (0-59) */
91         public int tm_hour;   /* Hours (0-23) */
92         public int tm_mday;   /* Day of the month (1-31) */
93         public int tm_mon;    /* Month (0-11) */
94         public int tm_year;   /* Year - 1900 */
95         public int tm_wday;   /* Day of the week (0-6, Sunday = 0) */
96         public int tm_yday;   /* Day in the year (0-365, 1 Jan = 0) */
97         public int tm_isdst;  /* Daylight saving time */
98         public long tm_gmtoff;
99         public String tm_zone;
100     }
101 }
102