From edae8fe5b75a51f11503d2624f582b8213e30b07 Mon Sep 17 00:00:00 2001 From: Steve Pfister Date: Mon, 6 Jun 2022 12:14:36 -0400 Subject: [PATCH] [release/6.0][iOS] Grab the default timezone using native API Backport of https://github.com/dotnet/runtime/pull/70149 --- ...> Interop.GetDefaultTimeZone.AnyMobile.cs} | 0 .../Native/Unix/System.Native/CMakeLists.txt | 5 +++++ .../Native/Unix/System.Native/pal_datetime.h | 2 +- .../Native/Unix/System.Native/pal_datetime.m | 12 ++++++++++++ .../System.Private.CoreLib.Shared.projitems | 4 ++-- .../System/TimeZoneInfo.Unix.NonAndroid.cs | 19 ++++++++++++++++--- .../tests/System/TimeZoneInfoTests.cs | 7 +++++++ 7 files changed, 43 insertions(+), 6 deletions(-) rename src/libraries/Common/src/Interop/Unix/System.Native/{Interop.GetDefaultTimeZone.Android.cs => Interop.GetDefaultTimeZone.AnyMobile.cs} (100%) create mode 100644 src/libraries/Native/Unix/System.Native/pal_datetime.m diff --git a/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.Android.cs b/src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.AnyMobile.cs similarity index 100% rename from src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.Android.cs rename to src/libraries/Common/src/Interop/Unix/System.Native/Interop.GetDefaultTimeZone.AnyMobile.cs diff --git a/src/libraries/Native/Unix/System.Native/CMakeLists.txt b/src/libraries/Native/Unix/System.Native/CMakeLists.txt index 188ca5fc6bde86..8aadd0fe224c07 100644 --- a/src/libraries/Native/Unix/System.Native/CMakeLists.txt +++ b/src/libraries/Native/Unix/System.Native/CMakeLists.txt @@ -46,6 +46,11 @@ else() list (APPEND NATIVE_SOURCES pal_environment.c) endif() +if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) + set(NATIVE_SOURCES ${NATIVE_SOURCES} + pal_datetime.m) +endif() + if (CLR_CMAKE_TARGET_MACCATALYST OR CLR_CMAKE_TARGET_IOS OR CLR_CMAKE_TARGET_TVOS) set(NATIVE_SOURCES ${NATIVE_SOURCES} pal_log.m diff --git a/src/libraries/Native/Unix/System.Native/pal_datetime.h b/src/libraries/Native/Unix/System.Native/pal_datetime.h index 1b88d472780fd1..bc59762a066b0d 100644 --- a/src/libraries/Native/Unix/System.Native/pal_datetime.h +++ b/src/libraries/Native/Unix/System.Native/pal_datetime.h @@ -8,6 +8,6 @@ PALEXPORT int64_t SystemNative_GetSystemTimeAsTicks(void); -#if defined(TARGET_ANDROID) +#if defined(TARGET_ANDROID) || defined(__APPLE__) PALEXPORT char* SystemNative_GetDefaultTimeZone(void); #endif diff --git a/src/libraries/Native/Unix/System.Native/pal_datetime.m b/src/libraries/Native/Unix/System.Native/pal_datetime.m new file mode 100644 index 00000000000000..cd45b54358fc4c --- /dev/null +++ b/src/libraries/Native/Unix/System.Native/pal_datetime.m @@ -0,0 +1,12 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include "pal_datetime.h" +#import + +char* SystemNative_GetDefaultTimeZone() +{ + NSTimeZone *tz = [NSTimeZone localTimeZone]; + NSString *name = [tz name]; + return (name != nil) ? strdup([name UTF8String]) : NULL; +} \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems index 61669938c573c0..67870cf5aadf92 100644 --- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems +++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems @@ -1954,8 +1954,8 @@ Common\Interop\Unix\System.Native\Interop.GetCwd.cs - - Common\Interop\Unix\System.Native\Interop.GetDefaultTimeZone.Android.cs + + Common\Interop\Unix\System.Native\Interop.GetDefaultTimeZone.AnyMobile.cs Common\Interop\Unix\System.Native\Interop.GetEGid.cs diff --git a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs index d7e54e1ebab2ea..998ece9eb2d913 100644 --- a/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs +++ b/src/libraries/System.Private.CoreLib/src/System/TimeZoneInfo.Unix.NonAndroid.cs @@ -5,8 +5,9 @@ using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.IO; -using System.Text; +using System.Runtime.InteropServices; using System.Security; +using System.Text; using Microsoft.Win32.SafeHandles; namespace System @@ -382,6 +383,13 @@ private static bool TryLoadTzFile(string tzFilePath, [NotNullWhen(true)] ref byt /// /// Gets the tzfile raw data for the current 'local' time zone using the following rules. + /// + /// On iOS / tvOS + /// 1. Read the TZ environment variable. If it is set, use it. + /// 2. Get the default TZ from the device + /// 3. Use UTC if all else fails. + /// + /// On all other platforms /// 1. Read the TZ environment variable. If it is set, use it. /// 2. Look for the data in /etc/localtime. /// 3. Look for the data in GetTimeZoneDirectory()/localtime. @@ -393,16 +401,21 @@ private static bool TryGetLocalTzFile([NotNullWhen(true)] out byte[]? rawData, [ id = null; string? tzVariable = GetTzEnvironmentVariable(); - // If the env var is null, use the localtime file + // If the env var is null, on iOS/tvOS, grab the default tz from the device. + // On all other platforms, use the localtime file. if (tzVariable == null) { +#if TARGET_IOS || TARGET_TVOS + tzVariable = Interop.Sys.GetDefaultTimeZone(); +#else return TryLoadTzFile("/etc/localtime", ref rawData, ref id) || TryLoadTzFile(Path.Combine(GetTimeZoneDirectory(), "localtime"), ref rawData, ref id); +#endif } // If it's empty, use UTC (TryGetLocalTzFile() should return false). - if (tzVariable.Length == 0) + if (string.IsNullOrEmpty(tzVariable)) { return false; } diff --git a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs index 236adb890ec175..b1cad7231f63d9 100644 --- a/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs +++ b/src/libraries/System.Runtime/tests/System/TimeZoneInfoTests.cs @@ -2887,6 +2887,13 @@ public static void NoBackwardTimeZones() Assert.Equal(tzCollection.Count, tzDisplayNames.Count); } + [Fact] + [PlatformSpecific(TestPlatforms.Android | TestPlatforms.iOS | TestPlatforms.tvOS)] + public static void LocalTzIsNotUtc() + { + Assert.NotEqual(TimeZoneInfo.Utc.StandardName, TimeZoneInfo.Local.StandardName); + } + private static bool IsEnglishUILanguage => CultureInfo.CurrentUICulture.Name.Length == 0 || CultureInfo.CurrentUICulture.TwoLetterISOLanguageName == "en"; private static bool IsEnglishUILanguageAndRemoteExecutorSupported => IsEnglishUILanguage && RemoteExecutor.IsSupported;