diff --git a/docs/design/features/timezone-invariant-mode.md b/docs/design/features/timezone-invariant-mode.md new file mode 100644 index 0000000000000..4fc3069602d1d --- /dev/null +++ b/docs/design/features/timezone-invariant-mode.md @@ -0,0 +1,16 @@ +# Timezone Invariant Mode + +Author: [Pavel Savara](https://github.com/pavelsavara) + +It's currently only available for Browser OS. +The timezone database is not part of the browser environment (as opposed to other operating systems). +Therefore dotnet bundles the timezone database as binary as part of the runtime. +That makes download size larger and application startup slower. +If your application doesn't need to work with time zone information, you could use this feature to make the runtime about 200KB smaller. + +You enable it in project file: + ```xml + + true + + ``` diff --git a/eng/testing/scenarios/BuildWasmAppsJobsList.txt b/eng/testing/scenarios/BuildWasmAppsJobsList.txt index e84e70c3f8f73..64f6abf5a1a65 100644 --- a/eng/testing/scenarios/BuildWasmAppsJobsList.txt +++ b/eng/testing/scenarios/BuildWasmAppsJobsList.txt @@ -14,6 +14,7 @@ Wasm.Build.Tests.ConfigSrcTests Wasm.Build.Tests.IcuShardingTests Wasm.Build.Tests.HybridGlobalizationTests Wasm.Build.Tests.InvariantGlobalizationTests +Wasm.Build.Tests.InvariantTimezoneTests Wasm.Build.Tests.MainWithArgsTests Wasm.Build.Tests.NativeBuildTests Wasm.Build.Tests.NativeLibraryTests diff --git a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets index 4186a7a43b17b..cdcf90d57502c 100644 --- a/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets +++ b/src/mono/nuget/Microsoft.NET.Sdk.WebAssembly.Pack/build/Microsoft.NET.Sdk.WebAssembly.Browser.targets @@ -47,6 +47,8 @@ Copyright (c) .NET Foundation. All rights reserved. false + true + false false true false diff --git a/src/mono/sample/wasm/browser-advanced/Program.cs b/src/mono/sample/wasm/browser-advanced/Program.cs index af6ca78e0bbda..bec9cb3256b4c 100644 --- a/src/mono/sample/wasm/browser-advanced/Program.cs +++ b/src/mono/sample/wasm/browser-advanced/Program.cs @@ -13,6 +13,26 @@ public partial class Test public static int Main(string[] args) { Console.WriteLine ("Hello, World!"); + + var start = DateTime.UtcNow; + var timezonesCount = TimeZoneInfo.GetSystemTimeZones().Count; + var end = DateTime.UtcNow; + Console.WriteLine($"Found {timezonesCount} timezones in the TZ database in {end-start}"); + + TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById("UTC"); + Console.WriteLine($"{utc.DisplayName} BaseUtcOffset is {utc.BaseUtcOffset}"); + + try + { + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo"); + Console.WriteLine($"{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}"); + } + catch (TimeZoneNotFoundException tznfe) + { + Console.WriteLine($"Could not find Asia/Tokyo: {tznfe.Message}"); + } + + return 0; } diff --git a/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj b/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj index 6875be373a9c1..fee094100d09c 100644 --- a/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj +++ b/src/mono/sample/wasm/browser-advanced/Wasm.Advanced.Sample.csproj @@ -3,6 +3,7 @@ true true + true false false true diff --git a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs index cad7521379378..196d9305d1f25 100644 --- a/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs +++ b/src/mono/wasi/Wasi.Build.Tests/WasiTemplateTests.cs @@ -74,19 +74,19 @@ public void ConsoleBuildThenPublish(string config) UseCache: false)); } - public static TheoryData TestDataForConsolePublishAndRun() + public static TheoryData TestDataForConsolePublishAndRun() { - var data = new TheoryData(); - data.Add("Debug", false); - data.Add("Debug", true); - data.Add("Release", false); // Release relinks by default + var data = new TheoryData(); + data.Add("Debug", false, false); + data.Add("Debug", true, true); + data.Add("Release", false, false); // Release relinks by default return data; } [ConditionalTheory(typeof(BuildTestBase), nameof(IsUsingWorkloads))] [ActiveIssue("https://github.com/dotnet/runtime/issues/82515", TestPlatforms.Windows)] [MemberData(nameof(TestDataForConsolePublishAndRun))] - public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinking) + public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinking, bool invariantTimezone) { string id = $"{config}_{Path.GetRandomFileName()}"; string projectFile = CreateWasmTemplateProject(id, "wasiconsole"); @@ -96,6 +96,8 @@ public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinkin string extraProperties = "true"; if (relinking) extraProperties += "true"; + if (invariantTimezone) + extraProperties += "true"; AddItemsPropertiesToProject(projectFile, extraProperties); @@ -125,6 +127,15 @@ public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinkin Assert.Contains("args[0] = x", res.Output); Assert.Contains("args[1] = y", res.Output); Assert.Contains("args[2] = z", res.Output); + if(invariantTimezone) + { + Assert.Contains("Could not find Asia/Tokyo", res.Output); + } + else + { + Assert.Contains("Asia/Tokyo BaseUtcOffset is 09:00:00", res.Output); + } + } private static readonly string s_simpleMainWithArgs = """ @@ -133,6 +144,17 @@ public void ConsolePublishAndRunForSingleFileBundle(string config, bool relinkin Console.WriteLine("Hello, Wasi Console!"); for (int i = 0; i < args.Length; i ++) Console.WriteLine($"args[{i}] = {args[i]}"); + + try + { + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo"); + Console.WriteLine($"{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}"); + } + catch (TimeZoneNotFoundException tznfe) + { + Console.WriteLine($"Could not find Asia/Tokyo: {tznfe.Message}"); + } + return 42; """; } diff --git a/src/mono/wasi/build/WasiApp.Native.targets b/src/mono/wasi/build/WasiApp.Native.targets index e0e43c0edffc4..bcc99310d6d89 100644 --- a/src/mono/wasi/build/WasiApp.Native.targets +++ b/src/mono/wasi/build/WasiApp.Native.targets @@ -63,6 +63,8 @@ true true + true + true true @@ -75,6 +77,8 @@ true true true + true + true false @@ -168,8 +172,9 @@ <_WasmCommonCFlags Include="-DGEN_PINVOKE=1" /> - <_WasmCommonCFlags Condition="'$(WasmSingleFileBundle)' == 'true'" Include="-DWASM_SINGLE_FILE=1" /> + <_WasmCommonCFlags Condition="'$(WasmSingleFileBundle)' == 'true'" Include="-DWASM_SINGLE_FILE=1" /> <_WasmCommonCFlags Condition="'$(InvariantGlobalization)' == 'true'" Include="-DINVARIANT_GLOBALIZATION=1" /> + <_WasmCommonCFlags Condition="'$(InvariantTimezone)' == 'true'" Include="-DINVARIANT_TIMEZONE=1" /> @@ -273,6 +278,7 @@ <_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a" /> + <_MonoRuntimeComponentDontLink Include="wasm-bundled-timezones.a" Condition="'$(InvariantTimezone)' == 'true'"/> <_WasmNativeFileForLinking Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)*.a" diff --git a/src/mono/wasi/build/WasiApp.targets b/src/mono/wasi/build/WasiApp.targets index c39ec3a0a880f..8909c89aa4400 100644 --- a/src/mono/wasi/build/WasiApp.targets +++ b/src/mono/wasi/build/WasiApp.targets @@ -11,9 +11,9 @@ Public properties (optional): - $(WasmAppDir) - AppBundle dir (Defaults to `$(OutputPath)\$(Configuration)\AppBundle`) - $(WasmMainAssemblyFileName)- Defaults to $(TargetFileName) - - $(WasmBuildNative) - Whenever to build the native executable. Defaults to false. - - $(WasmNativeStrip) - Whenever to strip the native executable. Defaults to true. - - $(WasmLinkIcalls) - Whenever to link out unused icalls. Defaults to $(WasmBuildNative). + - $(WasmBuildNative) - Whether to build the native executable. Defaults to false. + - $(WasmNativeStrip) - Whether to strip the native executable. Defaults to true. + - $(WasmLinkIcalls) - Whether to link out unused icalls. Defaults to $(WasmBuildNative). - $(RunAOTCompilation) - Defaults to false. - $(WasmDebugLevel) @@ -24,11 +24,12 @@ - $(WasmNativeDebugSymbols) - Build with native debug symbols, useful only with `$(RunAOTCompilation)`, or `$(WasmBuildNative)` Defaults to true. - $(WasmEmitSymbolMap) - Generates a `dotnet.js.symbols` file with a map of wasm function number to name. - - $(WasmDedup) - Whenever to dedup generic instances when using AOT. Defaults to true. + - $(WasmDedup) - Whether to dedup generic instances when using AOT. Defaults to true. - $(WasmProfilers) - Profilers to use - $(AOTProfilePath) - profile data file to be used for profile-guided optimization - - $(InvariantGlobalization) - Whenever to disable ICU. Defaults to false. + - $(InvariantGlobalization) - Whether to disable ICU. Defaults to false. + - $(InvariantTimezone) - Whether to disable Timezone database. Defaults to false. - $(WasmResolveAssembliesBeforeBuild) - Resolve the assembly dependencies. Defaults to false - $(WasmAssemblySearchPaths) - used for resolving assembly dependencies @@ -119,6 +120,7 @@ false true true + true true wasmtime diff --git a/src/mono/wasi/runtime/driver.c b/src/mono/wasi/runtime/driver.c index d6a51f9be51b0..98fbe1fef04bb 100644 --- a/src/mono/wasi/runtime/driver.c +++ b/src/mono/wasi/runtime/driver.c @@ -63,7 +63,9 @@ int32_t monoeg_g_hasenv(const char *variable); void mono_free (void*); int32_t mini_parse_debug_option (const char *option); char *mono_method_get_full_name (MonoMethod *method); +#ifndef INVARIANT_TIMEZONE extern void mono_register_timezones_bundle (void); +#endif /* INVARIANT_TIMEZONE */ #ifdef WASM_SINGLE_FILE extern void mono_register_assemblies_bundle (void); #ifndef INVARIANT_GLOBALIZATION @@ -439,7 +441,9 @@ mono_wasm_load_runtime (const char *unused, int debug_level) mini_parse_debug_option ("top-runtime-invoke-unhandled"); +#ifndef INVARIANT_TIMEZONE mono_register_timezones_bundle (); +#endif /* INVARIANT_TIMEZONE */ #ifdef WASM_SINGLE_FILE mono_register_assemblies_bundle (); #endif diff --git a/src/mono/wasi/wasi.proj b/src/mono/wasi/wasi.proj index fbf434ce4964a..d601f2c9e09ab 100644 --- a/src/mono/wasi/wasi.proj +++ b/src/mono/wasi/wasi.proj @@ -66,7 +66,7 @@ - + <_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data')) <_WasmTimezonesBundleObjectFile>wasm-bundled-timezones.o diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs index 41dac50141cf7..ea5a045e7f6c2 100644 --- a/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs +++ b/src/mono/wasm/Wasm.Build.Tests/InvariantGlobalizationTests.cs @@ -54,29 +54,10 @@ private void TestInvariantGlobalization(BuildArgs buildArgs, bool? invariantGlob if (dotnetWasmFromRuntimePack == null) dotnetWasmFromRuntimePack = !(buildArgs.AOT || buildArgs.Config == "Release"); - string programText = @" - using System; - using System.Globalization; - - // https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md#cultures-and-culture-data - try - { - CultureInfo culture = new (""es-ES"", false); - Console.WriteLine($""es-ES: Is Invariant LCID: {culture.LCID == CultureInfo.InvariantCulture.LCID}, NativeName: {culture.NativeName}""); - } - catch (CultureNotFoundException cnfe) - { - Console.WriteLine($""Could not create es-ES culture: {cnfe.Message}""); - } - - Console.WriteLine($""CurrentCulture.NativeName: {CultureInfo.CurrentCulture.NativeName}""); - return 42; - "; - BuildProject(buildArgs, id: id, new BuildProjectOptions( - InitProject: () => File.WriteAllText(Path.Combine(_projectDir!, "Program.cs"), programText), + InitProject: () => File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "Wasm.Buid.Tests.Programs", "InvariantGlobalization.cs"), Path.Combine(_projectDir!, "Program.cs")), DotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack, GlobalizationMode: invariantGlobalization == true ? GlobalizationMode.Invariant : null)); diff --git a/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs new file mode 100644 index 0000000000000..f89e04d508307 --- /dev/null +++ b/src/mono/wasm/Wasm.Build.Tests/InvariantTimezoneTests.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.IO; +using Xunit; +using Xunit.Abstractions; + +#nullable enable + +namespace Wasm.Build.Tests +{ + public class InvariantTimezoneTests : BuildTestBase + { + public InvariantTimezoneTests(ITestOutputHelper output, SharedBuildPerTestClassFixture buildContext) + : base(output, buildContext) + { + } + + public static IEnumerable InvariantTimezoneTestData(bool aot, RunHost host) + => ConfigWithAOTData(aot) + .Multiply( + new object?[] { null }, + new object?[] { false }, + new object?[] { true }) + .WithRunHosts(host) + .UnwrapItemsAsArrays(); + + [Theory] + [MemberData(nameof(InvariantTimezoneTestData), parameters: new object[] { /*aot*/ false, RunHost.All })] + [MemberData(nameof(InvariantTimezoneTestData), parameters: new object[] { /*aot*/ true, RunHost.All })] + public void AOT_InvariantTimezone(BuildArgs buildArgs, bool? invariantTimezone, RunHost host, string id) + => TestInvariantTimezone(buildArgs, invariantTimezone, host, id); + + [Theory] + [MemberData(nameof(InvariantTimezoneTestData), parameters: new object[] { /*aot*/ false, RunHost.All })] + public void RelinkingWithoutAOT(BuildArgs buildArgs, bool? invariantTimezone, RunHost host, string id) + => TestInvariantTimezone(buildArgs, invariantTimezone, host, id, + extraProperties: "true", + dotnetWasmFromRuntimePack: false); + + private void TestInvariantTimezone(BuildArgs buildArgs, bool? invariantTimezone, + RunHost host, string id, string extraProperties="", bool? dotnetWasmFromRuntimePack=null) + { + string projectName = $"invariant_{invariantTimezone?.ToString() ?? "unset"}"; + if (invariantTimezone != null) + extraProperties = $"{extraProperties}{invariantTimezone}"; + + buildArgs = buildArgs with { ProjectName = projectName }; + buildArgs = ExpandBuildArgs(buildArgs, extraProperties); + + if (dotnetWasmFromRuntimePack == null) + dotnetWasmFromRuntimePack = !(buildArgs.AOT || buildArgs.Config == "Release"); + + BuildProject(buildArgs, + id: id, + new BuildProjectOptions( + InitProject: () => File.Copy(Path.Combine(BuildEnvironment.TestAssetsPath, "Wasm.Buid.Tests.Programs", "InvariantTimezone.cs"), Path.Combine(_projectDir!, "Program.cs")), + DotnetWasmFromRuntimePack: dotnetWasmFromRuntimePack)); + + string output = RunAndTestWasmApp(buildArgs, expectedExitCode: 42, host: host, id: id); + Assert.Contains("UTC BaseUtcOffset is 0", output); + if (invariantTimezone == true) + { + Assert.Contains("Could not find Asia/Tokyo", output); + } + else + { + Assert.Contains("Asia/Tokyo BaseUtcOffset is 09:00:00", output); + } + } + } +} diff --git a/src/mono/wasm/build/WasmApp.Native.targets b/src/mono/wasm/build/WasmApp.Native.targets index 310d77cf36d6d..34736613dd8f6 100644 --- a/src/mono/wasm/build/WasmApp.Native.targets +++ b/src/mono/wasm/build/WasmApp.Native.targets @@ -115,6 +115,10 @@ true + + true + true + true false @@ -129,6 +133,10 @@ true + + true + true + false @@ -219,6 +227,7 @@ <_EmccCFlags Include="-DENABLE_AOT=1" Condition="'$(_WasmShouldAOT)' == 'true'" /> <_EmccCFlags Include="-DDRIVER_GEN=1" Condition="'$(_WasmShouldAOT)' == 'true'" /> <_EmccCFlags Include="-DINVARIANT_GLOBALIZATION=1" Condition="'$(InvariantGlobalization)' == 'true'" /> + <_EmccCFlags Include="-DINVARIANT_TIMEZONE=1" Condition="'$(InvariantTimezone)' == 'true'" /> <_EmccCFlags Include="-DLINK_ICALLS=1" Condition="'$(WasmLinkIcalls)' == 'true'" /> <_EmccCFlags Include="-DENABLE_AOT_PROFILER=1" Condition="$(WasmProfilers.Contains('aot'))" /> <_EmccCFlags Include="-DENABLE_BROWSER_PROFILER=1" Condition="$(WasmProfilers.Contains('browser'))" /> diff --git a/src/mono/wasm/build/WasmApp.targets b/src/mono/wasm/build/WasmApp.targets index 68f687774d6b8..ba181982935c4 100644 --- a/src/mono/wasm/build/WasmApp.targets +++ b/src/mono/wasm/build/WasmApp.targets @@ -10,9 +10,9 @@ Public properties (optional): - $(WasmAppDir) - AppBundle dir (Defaults to `$(OutputPath)\$(Configuration)\AppBundle`) - $(WasmMainAssemblyFileName)- Defaults to $(TargetFileName) - - $(WasmBuildNative) - Whenever to build the native executable. Defaults to false. - - $(WasmNativeStrip) - Whenever to strip the native executable. Defaults to true. - - $(WasmLinkIcalls) - Whenever to link out unused icalls. Defaults to $(WasmBuildNative). + - $(WasmBuildNative) - Whether to build the native executable. Defaults to false. + - $(WasmNativeStrip) - Whether to strip the native executable. Defaults to true. + - $(WasmLinkIcalls) - Whether to link out unused icalls. Defaults to $(WasmBuildNative). - $(RunAOTCompilation) - Defaults to false. - $(WasmDebugLevel) @@ -24,12 +24,13 @@ Defaults to true. - $(WasmEmitSymbolMap) - Generates a `dotnet.native.js.symbols` file with a map of wasm function number to name. - $(WasmEmitSourceMap) - Generates `dotnet.runtime.js.map` and `dotnet.js.map` files with a TypeScript source map. - - $(WasmDedup) - Whenever to dedup generic instances when using AOT. Defaults to true. + - $(WasmDedup) - Whether to dedup generic instances when using AOT. Defaults to true. - $(WasmProfilers) - Profilers to use - $(AOTProfilePath) - profile data file to be used for profile-guided optimization - - $(InvariantGlobalization) - Whenever to disable ICU. Defaults to false. - - $(HybridGlobalization) - Whenever to enable reduced ICU + native platform functions. Defaults to false and can be set only for InvariantGlobalization=false, WasmIncludeFullIcuData=false and empty WasmIcuDataFileName. + - $(InvariantGlobalization) - Whether to disable ICU. Defaults to false. + - $(InvariantTimezone) - Whether to disable Timezone database. Defaults to false. + - $(HybridGlobalization) - Whether to enable reduced ICU + native platform functions. Defaults to false and can be set only for InvariantGlobalization=false, WasmIncludeFullIcuData=false and empty WasmIcuDataFileName. - $(WasmResolveAssembliesBeforeBuild) - Resolve the assembly dependencies. Defaults to false - $(WasmAssemblySearchPaths) - used for resolving assembly dependencies diff --git a/src/mono/wasm/runtime/driver.c b/src/mono/wasm/runtime/driver.c index 51cd2497a1b9d..551d1b4ca8709 100644 --- a/src/mono/wasm/runtime/driver.c +++ b/src/mono/wasm/runtime/driver.c @@ -54,7 +54,9 @@ int monoeg_g_setenv(const char *variable, const char *value, int overwrite); int32_t mini_parse_debug_option (const char *option); char *mono_method_get_full_name (MonoMethod *method); +#ifndef INVARIANT_TIMEZONE extern void mono_register_timezones_bundle (void); +#endif /* INVARIANT_TIMEZONE */ extern void mono_wasm_set_entrypoint_breakpoint (const char* assembly_name, int method_token); static void mono_wasm_init_finalizer_thread (void); @@ -473,7 +475,9 @@ mono_wasm_load_runtime (const char *unused, int debug_level) mini_parse_debug_option ("top-runtime-invoke-unhandled"); +#ifndef INVARIANT_TIMEZONE mono_register_timezones_bundle (); +#endif /* INVARIANT_TIMEZONE */ mono_dl_fallback_register (wasm_dl_load, wasm_dl_symbol, NULL, NULL); mono_wasm_install_get_native_to_interp_tramp (get_native_to_interp); diff --git a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js index cea78ac93822a..8ea0b7deb2f89 100644 --- a/src/mono/wasm/runtime/es6/dotnet.es6.lib.js +++ b/src/mono/wasm/runtime/es6/dotnet.es6.lib.js @@ -137,6 +137,7 @@ linked_functions = [...linked_functions, "mono_wasm_install_js_worker_interop", "mono_wasm_uninstall_js_worker_interop", ] +#endif if (ENABLE_AOT_PROFILER) { linked_functions = [...linked_functions, @@ -153,7 +154,6 @@ if (ENABLE_AOT_PROFILER) { ] } -#endif if (!DISABLE_LEGACY_JS_INTEROP) { linked_functions = [...linked_functions, "mono_wasm_invoke_js_with_args_ref", diff --git a/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantGlobalization.cs b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantGlobalization.cs new file mode 100644 index 0000000000000..9237110cbc498 --- /dev/null +++ b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantGlobalization.cs @@ -0,0 +1,16 @@ +using System; +using System.Globalization; + +// https://github.com/dotnet/runtime/blob/main/docs/design/features/globalization-invariant-mode.md#cultures-and-culture-data +try +{ + CultureInfo culture = new ("es-ES", false); + Console.WriteLine($"es-ES: Is Invariant LCID: {culture.LCID == CultureInfo.InvariantCulture.LCID}, NativeName: {culture.NativeName}"); +} +catch (CultureNotFoundException cnfe) +{ + Console.WriteLine($"Could not create es-ES culture: {cnfe.Message}"); +} + +Console.WriteLine($"CurrentCulture.NativeName: {CultureInfo.CurrentCulture.NativeName}"); +return 42; diff --git a/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantTimezone.cs b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantTimezone.cs new file mode 100644 index 0000000000000..deba28c7be27e --- /dev/null +++ b/src/mono/wasm/testassets/Wasm.Buid.Tests.Programs/InvariantTimezone.cs @@ -0,0 +1,21 @@ +using System; + +// https://github.com/dotnet/runtime/blob/main/docs/design/features/timezone-invariant-mode.md + +var timezonesCount = TimeZoneInfo.GetSystemTimeZones().Count; +Console.WriteLine($"Found {timezonesCount} timezones in the TZ database"); + +TimeZoneInfo utc = TimeZoneInfo.FindSystemTimeZoneById("UTC"); +Console.WriteLine($"{utc.DisplayName} BaseUtcOffset is {utc.BaseUtcOffset}"); + +try +{ + TimeZoneInfo tst = TimeZoneInfo.FindSystemTimeZoneById("Asia/Tokyo"); + Console.WriteLine($"{tst.DisplayName} BaseUtcOffset is {tst.BaseUtcOffset}"); +} +catch (TimeZoneNotFoundException tznfe) +{ + Console.WriteLine($"Could not find Asia/Tokyo: {tznfe.Message}"); +} + +return 42; diff --git a/src/mono/wasm/wasm.proj b/src/mono/wasm/wasm.proj index 2842fb19f2507..33441e6abd505 100644 --- a/src/mono/wasm/wasm.proj +++ b/src/mono/wasm/wasm.proj @@ -80,7 +80,7 @@ - + <_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data')) <_WasmTimezonesBundleSourceFile>wasm-bundled-timezones.c