--- /dev/null
+# 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
+ <PropertyGroup>
+ <InvariantTimezone>true</InvariantTimezone>
+ </PropertyGroup>
+ ```
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
<!-- Runtime feature defaults to trim unnecessary code -->
<InvariantGlobalization Condition="'$(InvariantGlobalization)' == ''">false</InvariantGlobalization>
+ <InvariantTimezone Condition="'$(BlazorEnableTimeZoneSupport)' == 'false'">true</InvariantTimezone>
+ <InvariantTimezone Condition="'$(InvariantTimezone)' == ''">false</InvariantTimezone>
<EventSourceSupport Condition="'$(EventSourceSupport)' == ''">false</EventSourceSupport>
<UseSystemResourceKeys Condition="'$(UseSystemResourceKeys)' == ''">true</UseSystemResourceKeys>
<EnableUnsafeUTF7Encoding Condition="'$(EnableUnsafeUTF7Encoding)' == ''">false</EnableUnsafeUTF7Encoding>
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;
}
<PropertyGroup>
<EnableAggressiveTrimming>true</EnableAggressiveTrimming>
<PublishTrimmed>true</PublishTrimmed>
+ <InvariantTimezone>true</InvariantTimezone>
<WasmEnableLegacyJsInterop>false</WasmEnableLegacyJsInterop>
<WasmEnableWebcil>false</WasmEnableWebcil>
<WasmEmitSymbolMap>true</WasmEmitSymbolMap>
UseCache: false));
}
- public static TheoryData<string, bool> TestDataForConsolePublishAndRun()
+ public static TheoryData<string, bool, bool> TestDataForConsolePublishAndRun()
{
- var data = new TheoryData<string, bool>();
- data.Add("Debug", false);
- data.Add("Debug", true);
- data.Add("Release", false); // Release relinks by default
+ var data = new TheoryData<string, bool, bool>();
+ 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");
string extraProperties = "<WasmSingleFileBundle>true</WasmSingleFileBundle>";
if (relinking)
extraProperties += "<WasmBuildNative>true</WasmBuildNative>";
+ if (invariantTimezone)
+ extraProperties += "<InvariantTimezone>true</InvariantTimezone>";
AddItemsPropertiesToProject(projectFile, extraProperties);
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 = """
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;
""";
}
<WasmBuildNative Condition="'$(RunAOTCompilation)' == 'true' and '$(RunAOTCompilationAfterBuild)' == 'true'">true</WasmBuildNative>
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(WasmEnableSIMD)' == 'true'">true</WasmBuildNative>
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantTimezone)' == 'true'">true</WasmBuildNative>
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantGlobalization)' == 'true'">true</WasmBuildNative>
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and @(NativeFileReference->Count()) > 0" >true</WasmBuildNative>
<WasmBuildNative Condition="'$(RunAOTCompilation)' == 'true'">true</WasmBuildNative>
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and @(NativeFileReference->Count()) > 0" >true</WasmBuildNative>
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(WasmEnableSIMD)' == 'true'">true</WasmBuildNative>
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantTimezone)' == 'true'">true</WasmBuildNative>
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantGlobalization)' == 'true'">true</WasmBuildNative>
<!-- not aot, not trimmed app, no reason to relink -->
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(PublishTrimmed)' != 'true'">false</WasmBuildNative>
<ItemGroup>
<_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" />
<!-- Adding optimization flag at the top, so it gets precedence -->
<!--<_EmccCFlags Include="$(EmccCompileOptimizationFlag)" />-->
<!--<_WasmNativeFileForLinking Include="%(_BitcodeFile.ObjectFile)" />-->
<!--<_WasmNativeFileForLinking Include="%(_WasmSourceFileToCompile.ObjectFile)" />-->
<_MonoRuntimeComponentDontLink Include="libmono-component-diagnostics_tracing-static.a" />
+ <_MonoRuntimeComponentDontLink Include="wasm-bundled-timezones.a" Condition="'$(InvariantTimezone)' == 'true'"/>
<_WasmNativeFileForLinking
Include="$(MicrosoftNetCoreAppRuntimePackRidNativeDir)*.a"
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)
- $(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
<WasmSingleFileBundle Condition="'$(WasmSingleFileBundle)' == ''">false</WasmSingleFileBundle>
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(WasmSingleFileBundle)' == 'true'">true</WasmBuildNative>
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantGlobalization)' == 'true'">true</WasmBuildNative>
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantTimezone)' == 'true'">true</WasmBuildNative>
<WasiBundleAssemblies Condition="'$(WasiBundleAssemblies)' == ''">true</WasiBundleAssemblies>
<WasiRunner Condition="'$(WasiRunner)' == ''">wasmtime</WasiRunner>
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
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
</Target>
<UsingTask TaskName="EmitBundleObjectFiles" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" />
- <Target Name="GenerateTimezonesArchive" Returns="@(_WasmArchivedTimezones)">
+ <Target Name="GenerateTimezonesArchive" Returns="@(_WasmArchivedTimezones)" Condition="'$(InvariantTimezone)' != 'true'">
<PropertyGroup>
<_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data'))</_WasmTimezonesPath>
<_WasmTimezonesBundleObjectFile>wasm-bundled-timezones.o</_WasmTimezonesBundleObjectFile>
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));
--- /dev/null
+// 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<object?[]> 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: "<WasmBuildNative>true</WasmBuildNative>",
+ 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>{invariantTimezone}</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);
+ }
+ }
+ }
+}
<!-- removing legacy interop needs relink -->
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(WasmEnableLegacyJsInterop)' == 'false'" >true</WasmBuildNative>
+ <!-- InvariantTimezone and InvariantGlobalization need rebuild -->
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantTimezone)' == 'true'">true</WasmBuildNative>
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantGlobalization)' == 'true'">true</WasmBuildNative>
+
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and @(NativeFileReference->Count()) > 0" >true</WasmBuildNative>
<WasmBuildNative Condition="'$(WasmBuildNative)' == ''">false</WasmBuildNative>
<!-- removing legacy interop needs relink -->
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(WasmEnableLegacyJsInterop)' == 'false'" >true</WasmBuildNative>
+ <!-- InvariantTimezone and InvariantGlobalization need rebuild -->
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantTimezone)' == 'true'">true</WasmBuildNative>
+ <WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(InvariantGlobalization)' == 'true'">true</WasmBuildNative>
+
<!-- not aot, not trimmed app, no reason to relink -->
<WasmBuildNative Condition="'$(WasmBuildNative)' == '' and '$(PublishTrimmed)' != 'true'">false</WasmBuildNative>
<_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'))" />
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)
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
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);
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);
"mono_wasm_install_js_worker_interop",
"mono_wasm_uninstall_js_worker_interop",
]
+#endif
if (ENABLE_AOT_PROFILER) {
linked_functions = [...linked_functions,
]
}
-#endif
if (!DISABLE_LEGACY_JS_INTEROP) {
linked_functions = [...linked_functions,
"mono_wasm_invoke_js_with_args_ref",
--- /dev/null
+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;
--- /dev/null
+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;
</Target>
<UsingTask TaskName="EmitBundleSourceFiles" AssemblyFile="$(MonoTargetsTasksAssemblyPath)" />
- <Target Name="GenerateTimezonesArchive" Returns="@(_WasmArchivedTimezones)">
+ <Target Name="GenerateTimezonesArchive" Returns="@(_WasmArchivedTimezones)" Condition="'$(InvariantTimezone)' != 'true'">
<PropertyGroup>
<_WasmTimezonesPath>$([MSBuild]::NormalizePath('$(PkgSystem_Runtime_TimeZoneData)', 'contentFiles', 'any', 'any', 'data'))</_WasmTimezonesPath>
<_WasmTimezonesBundleSourceFile>wasm-bundled-timezones.c</_WasmTimezonesBundleSourceFile>