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