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
-
+
<_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data'))
<_WasmTimezonesBundleSourceFile>wasm-bundled-timezones.c