diff --git a/src/TimeZoneConverter.Posix/mj1856_oss.snk b/.assets/mattjohnsonpint.snk
similarity index 100%
rename from src/TimeZoneConverter.Posix/mj1856_oss.snk
rename to .assets/mattjohnsonpint.snk
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..d5a418d
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,18 @@
+# To learn more about .editorconfig see https://aka.ms/editorconfigdocs
+###############################
+# Core EditorConfig Options #
+###############################
+
+# All files
+[*]
+indent_style = space
+insert_final_newline = true
+charset = utf-8
+
+# Project files
+[*.{csproj,props,targets}]
+indent_size = 2
+
+# Code files
+[*.{cs}]
+indent_size = 4
diff --git a/.gitattributes b/.gitattributes
deleted file mode 100644
index 1ff0c42..0000000
--- a/.gitattributes
+++ /dev/null
@@ -1,63 +0,0 @@
-###############################################################################
-# Set default behavior to automatically normalize line endings.
-###############################################################################
-* text=auto
-
-###############################################################################
-# Set default behavior for command prompt diff.
-#
-# This is need for earlier builds of msysgit that does not have it on by
-# default for csharp files.
-# Note: This is only used by command line
-###############################################################################
-#*.cs diff=csharp
-
-###############################################################################
-# Set the merge driver for project and solution files
-#
-# Merging from the command prompt will add diff markers to the files if there
-# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
-# file extensions to fail to load in VS. An alternative would be to treat
-# these files as binary and thus will always conflict and require user
-# intervention with every merge. To do so, just uncomment the entries below
-###############################################################################
-#*.sln merge=binary
-#*.csproj merge=binary
-#*.vbproj merge=binary
-#*.vcxproj merge=binary
-#*.vcproj merge=binary
-#*.dbproj merge=binary
-#*.fsproj merge=binary
-#*.lsproj merge=binary
-#*.wixproj merge=binary
-#*.modelproj merge=binary
-#*.sqlproj merge=binary
-#*.wwaproj merge=binary
-
-###############################################################################
-# behavior for image files
-#
-# image files are treated as binary by default.
-###############################################################################
-#*.jpg binary
-#*.png binary
-#*.gif binary
-
-###############################################################################
-# diff behavior for common document formats
-#
-# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the
-# entries below.
-###############################################################################
-#*.doc diff=astextplain
-#*.DOC diff=astextplain
-#*.docx diff=astextplain
-#*.DOCX diff=astextplain
-#*.dot diff=astextplain
-#*.DOT diff=astextplain
-#*.pdf diff=astextplain
-#*.PDF diff=astextplain
-#*.rtf diff=astextplain
-#*.RTF diff=astextplain
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 0000000..66d6b24
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,10 @@
+version: 2
+updates:
+ - package-ecosystem: "nuget"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
new file mode 100644
index 0000000..1791016
--- /dev/null
+++ b/.github/workflows/build.yaml
@@ -0,0 +1,47 @@
+name: build
+
+on:
+ push:
+ branches:
+ - main
+ pull_request:
+
+env:
+ DOTNET_CLI_TELEMETRY_OPTOUT: 1
+ DOTNET_NOLOGO: 1
+
+jobs:
+ build:
+ name: ${{ matrix.os }}
+ runs-on: ${{ matrix.os }}
+
+ strategy:
+ fail-fast: false
+ matrix:
+ os: [ubuntu-latest, windows-latest, macos-15-intel]
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+
+ - name: Update tzdata on Linux
+ if: runner.os == 'Linux'
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y tzdata
+ sudo dpkg --remove --force-depends tzdata-legacy
+ env:
+ DEBIAN_FRONTEND: noninteractive
+
+ - name: Check tzdata version on MacOS
+ if: runner.os == 'macOS'
+ run: cat /usr/share/zoneinfo/+VERSION
+
+ - name: Restore
+ run: dotnet restore --nologo
+
+ - name: Build
+ run: dotnet build -c Release --nologo --no-restore
+
+ - name: Test
+ run: dotnet test -c Release --nologo --no-build -l GitHubActions -l "trx;LogFilePrefix=testresults_${{ runner.os }}"
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
new file mode 100644
index 0000000..2f16116
--- /dev/null
+++ b/.github/workflows/release.yaml
@@ -0,0 +1,44 @@
+name: release
+
+on:
+ workflow_dispatch:
+
+env:
+ DOTNET_CLI_TELEMETRY_OPTOUT: 1
+ DOTNET_NOLOGO: 1
+
+jobs:
+ release:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v5
+
+ - name: Update tzdata
+ run: sudo apt-get update && sudo apt-get install -y tzdata
+
+ - name: Restore
+ run: dotnet restore --nologo
+
+ - name: Build
+ run: dotnet build -c Release --nologo --no-restore
+
+ - name: Test
+ run: dotnet test -c Release --nologo --no-build -l GitHubActions -l "trx;LogFilePrefix=testresults_${{ runner.os }}"
+
+ - name: Pack
+ run: dotnet pack -c Release --nologo --no-build
+
+ - name: Push TimeZoneConverter to NuGet
+ run: dotnet nuget push --skip-duplicate -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} src/TimeZoneConverter/**/*.nupkg
+
+ - name: Push TimeZoneConverter.Posix to NuGet
+ run: dotnet nuget push --skip-duplicate -s https://api.nuget.org/v3/index.json -k ${{secrets.NUGET_API_KEY}} src/TimeZoneConverter.Posix/**/*.nupkg
+
+ - name: Archive Artifacts
+ uses: actions/upload-artifact@v5
+ with:
+ name: nuget-packages
+ path: src/**/Release/*.*nupkg
+ if-no-files-found: error
diff --git a/.gitignore b/.gitignore
index 1c9a181..d4d8686 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,7 +1,10 @@
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
+##
+## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
# User-specific files
+*.rsuser
*.suo
*.user
*.userosscache
@@ -10,48 +13,75 @@
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
+# Mono auto generated files
+mono_crash.*
+
# Build results
[Dd]ebug/
[Dd]ebugPublic/
[Rr]elease/
[Rr]eleases/
-[Xx]64/
-[Xx]86/
-[Bb]uild/
+x64/
+x86/
+[Ww][Ii][Nn]32/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
+[Ll]og/
+[Ll]ogs/
-# Visual Studio 2015 cache/options directory
+# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
+# Visual Studio 2017 auto generated files
+Generated\ Files/
+
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
-# NUNIT
+# NUnit
*.VisualState.xml
TestResult.xml
+nunit-*.xml
# Build Results of an ATL Project
[Dd]ebugPS/
[Rr]eleasePS/
dlldata.c
-# DNX
+# Benchmark Results
+BenchmarkDotNet.Artifacts/
+
+# .NET
project.lock.json
+project.fragment.lock.json
artifacts/
+# Tye
+.tye/
+
+# ASP.NET Scaffolding
+ScaffoldingReadMe.txt
+
+# StyleCop
+StyleCopReport.xml
+
+# Files built by Visual Studio
*_i.c
*_p.c
-*_i.h
+*_h.h
*.ilk
*.meta
*.obj
+*.iobj
*.pch
*.pdb
+*.ipdb
*.pgc
*.pgd
*.rsp
@@ -61,6 +91,7 @@ artifacts/
*.tlh
*.tmp
*.tmp_proj
+*_wpftmp.csproj
*.log
*.vspscc
*.vssscc
@@ -81,6 +112,7 @@ ipch/
*.sdf
*.cachefile
*.VC.db
+*.VC.VC.opendb
# Visual Studio profiler
*.psess
@@ -88,6 +120,9 @@ ipch/
*.vspx
*.sap
+# Visual Studio Trace Files
+*.e2e
+
# TFS 2012 Local Workspace
$tf/
@@ -99,15 +134,25 @@ _ReSharper*/
*.[Rr]e[Ss]harper
*.DotSettings.user
-# JustCode is a .NET coding add-in
-.JustCode
-
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
+# AxoCover is a Code Coverage Tool
+.axoCover/*
+!.axoCover/settings.json
+
+# Coverlet is a free, cross platform Code Coverage Tool
+coverage*.json
+coverage*.xml
+coverage*.info
+
+# Visual Studio code coverage results
+*.coverage
+*.coveragexml
+
# NCrunch
_NCrunch_*
.*crunch*.local.xml
@@ -139,22 +184,27 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
-
-# TODO: Un-comment the next line if you do not want to checkin
-# your web deploy settings because they may include unencrypted
-# passwords
-#*.pubxml
+# Note: Comment the next line if you want to checkin your web deploy settings,
+# but database connection strings (with potential passwords) will be unencrypted
+*.pubxml
*.publishproj
+# Microsoft Azure Web App publish settings. Comment the next line if you want to
+# checkin your Azure Web App publish settings, but sensitive information contained
+# in these scripts will be unencrypted
+PublishScripts/
+
# NuGet Packages
*.nupkg
+# NuGet Symbol Packages
+*.snupkg
# The packages folder can be ignored because of Package Restore
-**/packages/*
+**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
-!**/packages/build/
+!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
@@ -166,28 +216,40 @@ csx/
ecf/
rcf/
-# Windows Store app package directory
+# Windows Store app package directories and files
AppPackages/
BundleArtifacts/
+Package.StoreAssociation.xml
+_pkginfo.txt
+*.appx
+*.appxbundle
+*.appxupload
# Visual Studio cache files
# files ending in .cache can be ignored
*.[Cc]ache
# but keep track of directories ending in .cache
-!*.[Cc]ache/
+!?*.[Cc]ache/
# Others
ClientBin/
-[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.dbproj.schemaview
+*.jfm
*.pfx
*.publishsettings
-node_modules/
orleans.codegen.cs
+# Including strong name files can present a security risk
+# (https://github.com/github/gitignore/pull/2483#issue-259490424)
+#*.snk
+
+# Since there are multiple workflows, uncomment next line to ignore bower_components
+# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
+#bower_components/
+
# RIA/Silverlight projects
Generated_Code/
@@ -198,15 +260,22 @@ _UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
+ServiceFabricBackup/
+*.rptproj.bak
# SQL Server files
*.mdf
*.ldf
+*.ndf
# Business Intelligence projects
*.rdl.data
*.bim.layout
*.bim_*.settings
+*.rptproj.rsuser
+*- [Bb]ackup.rdl
+*- [Bb]ackup ([0-9]).rdl
+*- [Bb]ackup ([0-9][0-9]).rdl
# Microsoft Fakes
FakesAssemblies/
@@ -216,6 +285,7 @@ FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
+node_modules/
# Visual Studio 6 build log
*.plg
@@ -223,6 +293,9 @@ FakesAssemblies/
# Visual Studio 6 workspace options file
*.opt
+# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
+*.vbw
+
# Visual Studio LightSwitch build output
**/*.HTMLClient/GeneratedArtifacts
**/*.DesktopClient/GeneratedArtifacts
@@ -231,12 +304,155 @@ FakesAssemblies/
**/*.Server/ModelManifest.xml
_Pvt_Extensions
-# LightSwitch generated files
-GeneratedArtifacts/
-ModelManifest.xml
-
# Paket dependency manager
.paket/paket.exe
+paket-files/
# FAKE - F# Make
.fake/
+
+# CodeRush personal settings
+.cr/personal
+
+# Python Tools for Visual Studio (PTVS)
+__pycache__/
+*.pyc
+
+# Cake - Uncomment if you are using it
+# tools/**
+# !tools/packages.config
+
+# Tabs Studio
+*.tss
+
+# Telerik's JustMock configuration file
+*.jmconfig
+
+# BizTalk build output
+*.btp.cs
+*.btm.cs
+*.odx.cs
+*.xsd.cs
+
+# OpenCover UI analysis results
+OpenCover/
+
+# Azure Stream Analytics local run output
+ASALocalRun/
+
+# MSBuild Binary and Structured Log
+*.binlog
+
+# NVidia Nsight GPU debugger configuration file
+*.nvuser
+
+# MFractors (Xamarin productivity tool) working folder
+.mfractor/
+
+# Local History for Visual Studio
+.localhistory/
+
+# BeatPulse healthcheck temp database
+healthchecksdb
+
+# Backup folder for Package Reference Convert tool in Visual Studio 2017
+MigrationBackup/
+
+# Ionide (cross platform F# VS Code tools) working folder
+.ionide/
+
+# Fody - auto-generated XML schema
+FodyWeavers.xsd
+
+##
+## Visual studio for Mac
+##
+
+
+# globs
+Makefile.in
+*.userprefs
+*.usertasks
+config.make
+config.status
+aclocal.m4
+install-sh
+autom4te.cache/
+*.tar.gz
+tarballs/
+test-results/
+
+# Mac bundle stuff
+*.dmg
+*.app
+
+# content below from: https://github.com/github/gitignore/blob/master/Global/macOS.gitignore
+# General
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# Files that might appear in the root of a volume
+.DocumentRevisions-V100
+.fseventsd
+.Spotlight-V100
+.TemporaryItems
+.Trashes
+.VolumeIcon.icns
+.com.apple.timemachine.donotpresent
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+# content below from: https://github.com/github/gitignore/blob/master/Global/Windows.gitignore
+# Windows thumbnail cache files
+Thumbs.db
+ehthumbs.db
+ehthumbs_vista.db
+
+# Dump file
+*.stackdump
+
+# Folder config file
+[Dd]esktop.ini
+
+# Recycle Bin used on file shares
+$RECYCLE.BIN/
+
+# Windows Installer files
+*.cab
+*.msi
+*.msix
+*.msm
+*.msp
+
+# Windows shortcuts
+*.lnk
+
+# JetBrains Rider
+.idea/
+*.sln.iml
+
+##
+## Visual Studio Code
+##
+.vscode/*
+!.vscode/settings.json
+!.vscode/tasks.json
+!.vscode/launch.json
+!.vscode/extensions.json
+
+
+## verify received files
+*.received.txt
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 0000000..0aeceb4
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,21 @@
+
+
+
+ latest
+ true
+ enable
+
+
+
+ true
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 0000000..64f11f5
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/Extensions.cs b/Extensions.cs
new file mode 100644
index 0000000..c50eed9
--- /dev/null
+++ b/Extensions.cs
@@ -0,0 +1,11 @@
+namespace System.Linq;
+
+#if !NET7_0_OR_GREATER
+internal static class EnumerableExtensions
+{
+ public static IEnumerable Order(this IEnumerable source)
+ {
+ return source.OrderBy(x => x);
+ }
+}
+#endif
diff --git a/README.md b/README.md
index dbe3c8d..b0db686 100644
--- a/README.md
+++ b/README.md
@@ -1,32 +1,36 @@
## TimeZoneConverter [](https://www.nuget.org/packages/TimeZoneConverter/)
-## TimeZoneConverter.Posix [](https://www.nuget.org/packages/TimeZoneConverter.Posix/)
-
--------------------------------
-- TimeZoneConverter is a lightweight library to convert quickly between IANA, Windows, and Rails time zone names.
-- TimeZoneConverter.Posix adds support for generating POSIX time zone strings, which are useful in certain scenarios such as IoT.
+TimeZoneConverter is a lightweight library to convert quickly between IANA, Windows, and Rails time zone names.
-## TimeZoneConverter Installation
+*Note: A separate [`TimeZoneConverter.Posix`][1] package is also available if you need POSIX time zone support.*
-```powershell
-PM> Install-Package TimeZoneConverter
-```
+## Installation
+
+- Add the `TimeZoneConverter` NuGet package to your project.
+- Import the `TimeZoneConverter` namespace where needed.
+
+## Compatibility
-As of version 4.0.0, *TimeZoneConverter* works with all of the following:
+As of version 7.0.0, TimeZoneConverter works with all of the following:
-- .NET 5 or greater
+- .NET 6, .NET 8, .NET 9
- .NET Core 2.0 or greater
-- .NET Framework 4.6.1 and greater
+- .NET Framework 4.6.2 and greater
-Note that .NET Framework versions less than 4.6.1 are no longer supported.
+.NET Framework versions less than 4.6.2 are no longer supported.
#### Important note on .NET 6+
-.NET 6 has built-in support for IANA and Windows time zones in a cross-platform manner, removing the need for the TimeZoneConverter library.
+.NET 6 has built-in support for IANA and Windows time zones in a cross-platform manner, somewhat reducing the need for this library.
It relies on [.NET's ICU integration](https://docs.microsoft.com/dotnet/core/extensions/globalization-icu) to perform this functionality.
See [the .NET blog](https://devblogs.microsoft.com/dotnet/date-time-and-time-zone-enhancements-in-net-6/#time-zone-conversion-apis) for details.
-**If you are targeting only .NET 6 (or higher), and you have either platform-provided or App-local ICU enabled, you don't need to use the TimeZoneConverter library!**
+
+Restated, if you are targeting only .NET 6 (or higher), and you have either platform-provided or App-local ICU enabled, you *might* not need to use this library.
+However, it is indeed still supported, and many have found it continues to be useful in certain environments or on specific platforms.
+
+TimeZoneConverter has no external data dependencies at runtime. All of the data it needs is embedded in the library itself.
#### Note on OS Data Dependencies
@@ -37,32 +41,14 @@ On OSX and Linux, this data comes from a distribution of the [IANA time zone dat
For example, the Alpine Linux Docker images for .NET Core no longer ship with `tzdata`. See [dotnet/dotnet-docker#1366](https://github.com/dotnet/dotnet-docker/issues/1366) for instructions on how to add it to your Docker images.
-## TimeZoneConverter.Posix Installation
-
-```powershell
-PM> Install-Package TimeZoneConverter.Posix
-```
-
-This is a separate helper library that is maintained in the same repository. You only need it if you require support for POSIX time zones.
-
-As of version 3.0.0, *TimeZoneConverter.Posix* works with all of the following:
-
-- .NET 5 or greater
-- .NET Core 2.0 or greater
-- .NET Framework 4.6.1 and greater
-
-Note that .NET Framework versions less than 4.6.1 are no longer supported.
-
-Also note that `TimeZoneConverter.Posix` takes a dependency on both `TimeZoneConverter` and [Noda Time][2].
-
## Notes
This library uses a combination of data sources to achieve its goals:
-- The [Unicode CLDR][3] project
-- The [IANA time zone][4] data
-- Microsoft Windows [time zone updates][5]
-- The `MAPPING` data from `ActiveSupport::TimeZone` in [the Rails source code][6].
+- The [Unicode CLDR][2] project
+- The [IANA time zone][3] data
+- Microsoft Windows [time zone updates][4]
+- The `MAPPING` data from `ActiveSupport::TimeZone` in [the Rails source code][5].
- The author's best-informed knowledge and opinions
Usually, the latter is reserved for edge cases, and for newly-introduced zones that may
@@ -73,7 +59,15 @@ it is recommended that you always use the most current revision, and check for u
Additionally, this library does not attempt to determine if the time zone IDs provided are actually present on the computer where the code is running. It is assumed that the computer is kept current with time zone updates.
-For example, if one attempts to convert `Africa/Khartoum` to a Windows time zone ID, they will get `Sudan Standard Time`. If it is then used on a Windows computer that does not yet have [`KB4051956`][7] installed (which created this time zone), they will likely get a `TimeZoneNotFoundException`.
+For example, if one attempts to convert `Africa/Khartoum` to a Windows time zone ID, they will get `Sudan Standard Time`. If it is then used on a Windows computer that does not yet have [`KB4051956`][6] installed (which created this time zone), they will likely get a `TimeZoneNotFoundException`.
+
+### Unmappable Zones
+
+It is possible for a zone to be *unmappable* - meaning that there is no logical equivalent from one type of time zone to another.
+
+Currently there is only one IANA zone that is unmappable to Windows, which is `Antarctica/Troll`. In other words, there is no "correct" time zone for Windows users who may happen to be stationed in [Troll Station, Antarctica](https://en.wikipedia.org/wiki/Troll_(research_station)). Therefore, if you try to convert `Antarctica/Troll` to Windows, you will get a `TimeZoneNotFoundException`.
+
+There are *many* zones that are unmappable to Rails. The complete list is in the unit test code [here](https://github.com/mattjohnsonpint/TimeZoneConverter/blob/main/test/TimeZoneConverter.Tests/IanaToRailsTests.cs).
## Example Usage
@@ -134,42 +128,26 @@ IList tz = TZConvert.WindowsToRails("Central Standard Time (Mexico)");
// Result: { "Guadalajara", "Mexico City" }
```
-Generate a POSIX time zone string from a Windows time zone ID.
-
-*Requires `TimeZoneConverter.Posix`*
+## Extras
-```csharp
-string posix = PosixTimeZone.FromWindowsTimeZoneId("Eastern Standard Time");
-// Result: "EST5EDT,M3.2.0,M11.1.0"
-```
+There are a few additional helpers you may find useful.
-Generate a POSIX time zone string from an IANA time zone name.
+- These properties provide lists of the various types of time zones known to this library:
+ - `TZConvert.KnownIanaTimeZoneNames`
+ - `TZConvert.KnownWindowsTimeZoneIds`
+ - `TZConvert.KnownRailsTimeZoneNames`
-*Requires `TimeZoneConverter.Posix`*
-
-```csharp
-string posix = PosixTimeZone.FromIanaTimeZoneName("Australia/Sydney");
-// Result: "AEST-10AEDT,M10.1.0,M4.1.0/3"
-```
-
-Generate a POSIX time zone string from a `TimeZoneInfo` object.
-
-*Requires `TimeZoneConverter.Posix`*
-
-```csharp
-string posix = PosixTimeZone.FromTimeZoneInfo(TimeZoneInfo.Local);
-```
+- If you need a list of time zones that are applicable in a given region, you can use:
+ - `TZConvert.GetIanaTimeZoneNamesByTerritory()`
## License
-This library is provided free of charge, under the terms of the [MIT license][8].
-
+This library is provided free of charge, under the terms of the [MIT license][7].
-[1]: https://docs.microsoft.com/en-us/dotnet/articles/standard/library
-[2]: https://nodatime.org
-[3]: https://cldr.unicode.org
-[4]: https://iana.org/time-zones
-[5]: https://aka.ms/dstblog
-[6]: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/values/time_zone.rb
-[7]: https://support.microsoft.com/en-us/help/4051956/time-zone-and-dst-changes-in-windows-for-northern-cyprus-sudan-and-ton
-[8]: https://github.com/mattjohnsonpint/TimeZoneConverter/blob/main/LICENSE.txt
+[1]: https://github.com/mattjohnsonpint/TimeZoneConverter/blob/main/src/TimeZoneConverter.Posix
+[2]: https://cldr.unicode.org
+[3]: https://iana.org/time-zones
+[4]: https://aka.ms/dstblog
+[5]: https://github.com/rails/rails/blob/master/activesupport/lib/active_support/values/time_zone.rb
+[6]: https://support.microsoft.com/help/4051956/time-zone-and-dst-changes-in-windows-for-northern-cyprus-sudan-and-ton
+[7]: https://github.com/mattjohnsonpint/TimeZoneConverter/blob/main/LICENSE.txt
diff --git a/TimeZoneConverter.sln b/TimeZoneConverter.sln
index 866e942..9122470 100644
--- a/TimeZoneConverter.sln
+++ b/TimeZoneConverter.sln
@@ -1,4 +1,4 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15
VisualStudioVersion = 15.0.26403.3
@@ -7,6 +7,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9C922A24-67F
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1300AFFC-DE69-49E1-A95F-9BB30D947EDA}"
ProjectSection(SolutionItems) = preProject
+ .editorconfig = .editorconfig
LICENSE.txt = LICENSE.txt
README.md = README.md
EndProjectSection
@@ -23,6 +24,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TimeZoneConverter.Posix", "
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimeZoneConverter.Posix.Tests", "test\TimeZoneConverter.Posix.Tests\TimeZoneConverter.Posix.Tests.csproj", "{3EF2A004-2823-4C13-AB04-8A7B415B49C7}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TimeZoneConverter.Benchmarks", "test\TimeZoneConverter.Benchmarks\TimeZoneConverter.Benchmarks.csproj", "{66C9F893-5C13-4B14-B870-594459EB739F}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -49,6 +52,10 @@ Global
{3EF2A004-2823-4C13-AB04-8A7B415B49C7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3EF2A004-2823-4C13-AB04-8A7B415B49C7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3EF2A004-2823-4C13-AB04-8A7B415B49C7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {66C9F893-5C13-4B14-B870-594459EB739F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {66C9F893-5C13-4B14-B870-594459EB739F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {66C9F893-5C13-4B14-B870-594459EB739F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {66C9F893-5C13-4B14-B870-594459EB739F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -59,6 +66,7 @@ Global
{902AFB31-8432-4C34-89AB-2CFF4DD27B93} = {62E4880C-D978-413C-AB12-E74B2E47426E}
{6E9924D5-04AA-4063-AD77-02C68112D612} = {9C922A24-67F8-4E45-B079-130DDAC3B5A7}
{3EF2A004-2823-4C13-AB04-8A7B415B49C7} = {62E4880C-D978-413C-AB12-E74B2E47426E}
+ {66C9F893-5C13-4B14-B870-594459EB739F} = {62E4880C-D978-413C-AB12-E74B2E47426E}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {404E04B4-C30C-452D-8705-DDF6C17AE7D0}
diff --git a/global.json b/global.json
new file mode 100644
index 0000000..680789c
--- /dev/null
+++ b/global.json
@@ -0,0 +1,7 @@
+{
+ "sdk": {
+ "version": "9.0.100",
+ "rollForward": "latestMinor",
+ "allowPrerelease": false
+ }
+}
diff --git a/lgtm.yml b/lgtm.yml
deleted file mode 100644
index 4ccd913..0000000
--- a/lgtm.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-extraction:
- csharp:
- index:
- solution: "src/TimeZoneConverter/TimeZoneConverter.csproj"
- dotnet:
- arguments: "-f netstandard2.0"
diff --git a/nuget.config b/nuget.config
new file mode 100644
index 0000000..fbcef10
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
new file mode 100644
index 0000000..48528f9
--- /dev/null
+++ b/src/Directory.Build.props
@@ -0,0 +1,24 @@
+
+
+
+
+
+ $(MSBuildThisFileDirectory)..\.assets\mattjohnsonpint.snk
+ true
+ true
+ true
+ true
+ snupkg
+ true
+ true
+
+
+
+ latest-Recommended
+
+
+
+
+
+
+
diff --git a/src/TimeZoneConverter.DataBuilder/DataExtractor.cs b/src/TimeZoneConverter.DataBuilder/DataExtractor.cs
index b68eeb6..24fd689 100644
--- a/src/TimeZoneConverter.DataBuilder/DataExtractor.cs
+++ b/src/TimeZoneConverter.DataBuilder/DataExtractor.cs
@@ -1,139 +1,172 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
using System.Xml.Linq;
using System.Xml.XPath;
-namespace TimeZoneConverter.DataBuilder
+namespace TimeZoneConverter.DataBuilder;
+
+public static class DataExtractor
{
- public static class DataExtractor
+ public static List LoadMapping(string cldrDirectoryPath)
{
- public static List LoadMapping(string cldrDirectoryPath)
- {
- var list = new List();
- using FileStream stream = File.OpenRead(Path.Combine(cldrDirectoryPath, "windowsZones.xml"));
- var doc = XDocument.Load(stream);
-
- IEnumerable mapZoneElements = doc.XPathSelectElements("/supplementalData/windowsZones/mapTimezones/mapZone");
+ var list = new List();
+ using var stream = File.OpenRead(Path.Combine(cldrDirectoryPath, "windowsZones.xml"));
+ var doc = XDocument.Load(stream);
- foreach (XElement element in mapZoneElements)
- {
- string windowsZone = element.Attribute("other")?.Value;
- string territory = element.Attribute("territory")?.Value;
- var ianaZones = (element.Attribute("type")?.Value.Split() ?? new string[0]).ToList();
-
- list.Add($"{windowsZone},{territory},{string.Join(" ", ianaZones)}");
- }
+ foreach (var element in doc.XPathSelectElements("/supplementalData/windowsZones/mapTimezones/mapZone"))
+ {
+ var windowsZone = element.Attribute("other")?.Value;
+ var territory = element.Attribute("territory")?.Value;
+ var ianaZones = (element.Attribute("type")?.Value.Trim().Split() ?? []).ToList();
- return list;
+ list.Add($"{windowsZone},{territory},{string.Join(" ", ianaZones)}");
}
- public static List LoadAliases(string cldrDirectoryPath, IDictionary tzdbLinks)
- {
- var data = new Dictionary();
- using (FileStream stream = File.OpenRead(Path.Combine(cldrDirectoryPath, "timezone.xml")))
- {
- var doc = XDocument.Load(stream);
+ return list;
+ }
- IEnumerable typeElements = doc.XPathSelectElements("/ldmlBCP47/keyword/key/type");
+ public static List LoadAliases(string cldrDirectoryPath, IDictionary tzdbLinks)
+ {
+ var data = new Dictionary();
+ using (var stream = File.OpenRead(Path.Combine(cldrDirectoryPath, "timezone.xml")))
+ {
+ var doc = XDocument.Load(stream);
- foreach (XElement element in typeElements)
+ foreach (var element in doc.XPathSelectElements("/ldmlBCP47/keyword/key/type"))
+ {
+ var aliasAttribute = element.Attribute("alias");
+ if (aliasAttribute == null)
{
- XAttribute aliasAttribute = element.Attribute("alias");
- if (aliasAttribute == null)
- continue;
+ continue;
+ }
- string[] zones = aliasAttribute.Value.Split();
- if (zones.Length <= 1)
- continue;
+ var zones = aliasAttribute.Value.Trim().Split();
+ if (zones.Length <= 1)
+ {
+ continue;
+ }
- string target = zones[0];
- string[] aliases = zones.Skip(1).ToArray();
+ var target = zones[0];
+ var aliases = zones.Skip(1).ToArray();
- if (tzdbLinks.TryGetValue(target, out string ianaCanonicalZone))
+ if (tzdbLinks.TryGetValue(target, out var ianaCanonicalZone))
+ {
+ for (var i = 0; i < aliases.Length; i++)
{
- for (var i = 0; i < aliases.Length; i++)
+ if (aliases[i] == ianaCanonicalZone)
{
- if (aliases[i] == ianaCanonicalZone)
- aliases[i] = target;
+ aliases[i] = target;
}
- target = ianaCanonicalZone;
}
- if (data.ContainsKey(target))
- data[target] += " " + string.Join(" ", aliases);
- else
- data.Add(target, string.Join(" ", aliases));
+ target = ianaCanonicalZone;
}
- }
- foreach (KeyValuePair link in tzdbLinks)
- {
- if (!data.ContainsKey(link.Value))
+ if (data.ContainsKey(target))
{
- data.Add(link.Value, link.Key);
- continue;
+ data[target] += " " + string.Join(" ", aliases);
+ }
+ else
+ {
+ data.Add(target, string.Join(" ", aliases));
}
+ }
+ }
- if (data[link.Value].Split().Contains(link.Key))
- continue;
+ foreach (var link in tzdbLinks)
+ {
+ if (!data.TryGetValue(link.Value, out string? value))
+ {
+ value = link.Key;
+ data.Add(link.Value, value);
+ continue;
+ }
- data[link.Value] += " " + link.Key;
+ if (value.Trim().Split().Contains(link.Key))
+ {
+ continue;
}
- return data
- .OrderBy(x => x.Key)
- .Select(x => $"{x.Key},{x.Value}")
- .ToList();
+ data[link.Value] += " " + link.Key;
}
- public static IDictionary LoadTzdbLinks(string tzdbDirectoryPath)
+ return [.. data
+ .OrderBy(x => x.Key)
+ .Select(x => $"{x.Key},{x.Value}")];
+ }
+
+ public static IDictionary LoadTzdbLinks(string tzdbDirectoryPath)
+ {
+ string[] dataFiles =
+ [
+ "africa", "antarctica", "asia", "australasia", "backward",
+ "etcetera", "europe", "northamerica", "southamerica"
+ ];
+
+ var data = new Dictionary();
+ foreach (var file in dataFiles)
{
- string[] dataFiles =
+ var lines = File.ReadLines(Path.Combine(tzdbDirectoryPath, file));
+ foreach (var line in lines.Where(x => x.StartsWith("Link", StringComparison.Ordinal)))
{
- "africa", "antarctica", "asia", "australasia", "backward",
- "etcetera", "europe", "northamerica", "southamerica"
- };
+ var parts = line.Trim().Split(Array.Empty(), StringSplitOptions.RemoveEmptyEntries);
+ var target = parts[1];
+ var link = parts[2];
+ data.Add(link, target);
+ }
+ }
+
+ return data;
+ }
+
+ public static IList LoadTzdbTerritories(string tzdbDirectoryPath)
+ {
+ var data = new Dictionary>();
+ var lines = File.ReadLines(Path.Combine(tzdbDirectoryPath, "zone.tab"));
+ foreach (var line in lines.Where(x => !x.StartsWith('#')))
+ {
+ var parts = line.Trim().Split('\t');
+ var territory = parts[0];
+ var zone = parts[2];
- var data = new Dictionary();
- foreach (string file in dataFiles)
+ if (data.TryGetValue(territory, out var zones))
{
- IEnumerable lines = File.ReadLines(Path.Combine(tzdbDirectoryPath, file));
- foreach (string line in lines.Where(x => x.StartsWith("Link")))
- {
- string[] parts = line.Split(new char[0], StringSplitOptions.RemoveEmptyEntries);
- string target = parts[1];
- string link = parts[2];
- data.Add(link, target);
- }
+ zones.Add(zone);
+ }
+ else
+ {
+ data.Add(territory, [zone]);
}
-
- return data;
}
- public static IList LoadRailsMapping(string railsPath)
+ return [.. data
+ .OrderBy(x => x.Key)
+ .Select(x => x.Key + "," + string.Join(' ', x.Value.Order()))];
+ }
+
+ public static IList LoadRailsMapping(string railsPath)
+ {
+ var data = new List();
+ using var stream = File.OpenRead(Path.Combine(railsPath, "time_zone.rb"));
+ using var reader = new StreamReader(stream);
+ var inMappingSection = false;
+ while (!reader.EndOfStream)
{
- var data = new List();
- using FileStream stream = File.OpenRead(Path.Combine(railsPath, "time_zone.rb"));
- using var reader = new StreamReader(stream);
- var inMappingSection = false;
- while (!reader.EndOfStream)
+ var line = reader.ReadLine()!.Trim();
+ if (inMappingSection)
{
- string line = reader.ReadLine()!.Trim();
- if (inMappingSection)
+ if (line == "}")
{
- if (line == "}")
- break;
-
- string[] parts = line.Split("=>");
- data.Add(parts[0].Trim(' ', '"') + "," + parts[1].TrimEnd(',').Trim(' ', '"'));
+ break;
}
- else if (line == "MAPPING = {")
- inMappingSection = true;
- }
- return data;
+ var parts = line.Trim().Split("=>");
+ data.Add(parts[0].Trim(' ', '"') + "," + parts[1].TrimEnd(',').Trim(' ', '"'));
+ }
+ else if (line == "MAPPING = {")
+ {
+ inMappingSection = true;
+ }
}
+
+ return data;
}
}
diff --git a/src/TimeZoneConverter.DataBuilder/Downloader.cs b/src/TimeZoneConverter.DataBuilder/Downloader.cs
index 28ccc88..4bb13ed 100644
--- a/src/TimeZoneConverter.DataBuilder/Downloader.cs
+++ b/src/TimeZoneConverter.DataBuilder/Downloader.cs
@@ -1,79 +1,79 @@
-using System;
-using System.IO;
using System.Net.Http;
-using System.Threading.Tasks;
-using SharpCompress.Common;
using SharpCompress.Readers;
-namespace TimeZoneConverter.DataBuilder
+namespace TimeZoneConverter.DataBuilder;
+
+public static class Downloader
{
- public static class Downloader
+ private static readonly HttpClient HttpClientInstance = new();
+
+ public static async Task DownloadCldrAsync(string dir)
{
- private static readonly HttpClient HttpClientInstance = new HttpClient();
+ const string url1 = "https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml";
+ const string url2 = "https://raw.githubusercontent.com/unicode-org/cldr/master/common/bcp47/timezone.xml";
- public static async Task DownloadCldrAsync(string dir)
- {
- const string url1 = "https://raw.githubusercontent.com/unicode-org/cldr/master/common/supplemental/windowsZones.xml";
- const string url2 = "https://raw.githubusercontent.com/unicode-org/cldr/master/common/bcp47/timezone.xml";
+ var t1 = DownloadAsync(url1, dir);
+ var t2 = DownloadAsync(url2, dir);
+ await Task.WhenAll(t1, t2);
+ }
- Task t1 = DownloadAsync(url1, dir);
- Task t2 = DownloadAsync(url2, dir);
- await Task.WhenAll(t1, t2);
- }
+ public static async Task DownloadTzdbAsync(string dir)
+ {
+ const string url = "https://data.iana.org/time-zones/tzdata-latest.tar.gz";
+ await DownloadAndExtractAsync(url, dir);
+ }
- public static async Task DownloadTzdbAsync(string dir)
- {
- const string url = "https://data.iana.org/time-zones/tzdata-latest.tar.gz";
- await DownloadAndExtractAsync(url, dir);
- }
+ public static async Task DownloadRailsTzMappingAsync(string dir)
+ {
+ const string url = "https://raw.githubusercontent.com/rails/rails/master/activesupport/lib/active_support/values/time_zone.rb";
+ await DownloadAsync(url, dir);
+ }
- public static async Task DownloadRailsTzMappingAsync(string dir)
- {
- const string url = "https://raw.githubusercontent.com/rails/rails/master/activesupport/lib/active_support/values/time_zone.rb";
- await DownloadAsync(url, dir);
- }
+ public static string GetTempDir()
+ {
+ return string.Concat(Path.GetTempPath(), Path.GetRandomFileName().AsSpan(0, 8));
+ }
- public static string GetTempDir()
+ private static async Task DownloadAsync(string url, string dir)
+ {
+ if (!Directory.Exists(dir))
{
- return Path.GetTempPath() + Path.GetRandomFileName().Substring(0, 8);
+ Directory.CreateDirectory(dir);
}
- private static async Task DownloadAsync(string url, string dir)
- {
- if (!Directory.Exists(dir))
- Directory.CreateDirectory(dir);
+ var filename = url[(url.LastIndexOf('/') + 1)..];
+ using var result = await HttpClientInstance.GetAsync(url);
+ await using var fs = File.Create(Path.Combine(dir, filename));
+ await result.Content.CopyToAsync(fs);
+ }
- string filename = url.Substring(url.LastIndexOf('/') + 1);
- using HttpResponseMessage result = await HttpClientInstance.GetAsync(url);
- await using FileStream fs = File.Create(Path.Combine(dir, filename));
- await result.Content.CopyToAsync(fs);
+ private static async Task DownloadAndExtractAsync(string url, string dir)
+ {
+ await using var httpStream = await HttpClientInstance.GetStreamAsync(url);
+ using var reader = ReaderFactory.Open(httpStream);
+ if (!Directory.Exists(dir))
+ {
+ Directory.CreateDirectory(dir);
}
- private static async Task DownloadAndExtractAsync(string url, string dir)
+ while (reader.MoveToNextEntry())
{
- await using Stream httpStream = await HttpClientInstance.GetStreamAsync(url);
- using IReader reader = ReaderFactory.Open(httpStream);
- if (!Directory.Exists(dir))
- Directory.CreateDirectory(dir);
-
- while (reader.MoveToNextEntry())
+ var entry = reader.Entry;
+ if (entry.IsDirectory || entry.Key == null)
{
- IEntry entry = reader.Entry;
- if (entry.IsDirectory)
- continue;
-
- string targetPath = Path.Combine(dir, entry.Key.Replace('/', '\\'));
- string targetDir = Path.GetDirectoryName(targetPath);
- if (targetDir == null)
- throw new InvalidOperationException();
-
- if (!Directory.Exists(targetDir))
- Directory.CreateDirectory(targetDir);
+ continue;
+ }
- await using EntryStream stream = reader.OpenEntryStream();
- await using FileStream fs = File.Create(targetPath);
- await stream.CopyToAsync(fs);
+ var targetPath = Path.Combine(dir, entry.Key.Replace('/', '\\'));
+ var targetDir = Path.GetDirectoryName(targetPath) ?? throw new InvalidOperationException();
+ if (!Directory.Exists(targetDir))
+ {
+ Directory.CreateDirectory(targetDir);
}
+
+ await using var stream = reader.OpenEntryStream();
+ await using var fs = File.Create(targetPath);
+ await stream.CopyToAsync(fs);
}
}
}
diff --git a/src/TimeZoneConverter.DataBuilder/Program.cs b/src/TimeZoneConverter.DataBuilder/Program.cs
index 811b417..b56f4c1 100644
--- a/src/TimeZoneConverter.DataBuilder/Program.cs
+++ b/src/TimeZoneConverter.DataBuilder/Program.cs
@@ -1,102 +1,98 @@
-using System;
-using System.Collections.Generic;
-using System.IO;
using System.IO.Compression;
-using System.Linq;
-using System.Threading.Tasks;
-namespace TimeZoneConverter.DataBuilder
+namespace TimeZoneConverter.DataBuilder;
+
+internal static class Program
{
- public class Program
+ public static void Main(string[] args)
{
- public static void Main(string[] args)
+ var tempDir = Downloader.GetTempDir();
+
+ try
{
- string tempDir = Downloader.GetTempDir();
+ var cldrPath = Path.Combine(tempDir, "cldr");
+ var tzdbPath = Path.Combine(tempDir, "tzdb");
+ var railsPath = Path.Combine(tempDir, "rails");
- try
+ // Download Data
+ if (!Directory.Exists(tempDir))
{
- string cldrPath = Path.Combine(tempDir, "cldr");
- string tzdbPath = Path.Combine(tempDir, "tzdb");
- string railsPath = Path.Combine(tempDir, "rails");
+ var t1 = Downloader.DownloadCldrAsync(cldrPath);
+ var t2 = Downloader.DownloadTzdbAsync(tzdbPath);
+ var t3 = Downloader.DownloadRailsTzMappingAsync(railsPath);
+ Task.WaitAll(t1, t2, t3);
+ }
- // Download Data
- if (!Directory.Exists(tempDir))
+ // Extract links and territories from TZDB
+ var links = DataExtractor.LoadTzdbLinks(tzdbPath);
+ var territories = DataExtractor.LoadTzdbTerritories(tzdbPath);
+
+ // Fixup UTC equivalencies. Prefer Etc/UTC.
+ links.Add("Etc/GMT", "Etc/UTC");
+ foreach (var tzdbLink in links.ToList())
+ {
+ if (tzdbLink.Value == "Etc/GMT")
{
- Task t1 = Downloader.DownloadCldrAsync(cldrPath);
- Task t2 = Downloader.DownloadTzdbAsync(tzdbPath);
- Task t3 = Downloader.DownloadRailsTzMappingAsync(railsPath);
- Task.WaitAll(t1, t2, t3);
+ links[tzdbLink.Key] = "Etc/UTC";
}
+ }
- // Extract links from TZDB
- IDictionary links = DataExtractor.LoadTzdbLinks(tzdbPath);
+ // Extract mappings and aliases from CLDR
+ var mapping = DataExtractor.LoadMapping(cldrPath);
+ var aliases = DataExtractor.LoadAliases(cldrPath, links);
- // Fixup UTC equivalencies. Prefer Etc/UTC.
- links.Add("Etc/GMT", "Etc/UTC");
- foreach (KeyValuePair tzdbLink in links.ToList())
- {
- if (tzdbLink.Value == "Etc/GMT")
- links[tzdbLink.Key] = "Etc/UTC";
- }
+ // Extract Rails mappings and aliases from Rails data
+ var railsMapping = DataExtractor.LoadRailsMapping(railsPath);
- // Extract mappings and aliases from CLDR
- List mapping = DataExtractor.LoadMapping(cldrPath);
- List aliases = DataExtractor.LoadAliases(cldrPath, links);
-
- // Extract Rails mappings and aliases from Rails data
- IList railsMapping = DataExtractor.LoadRailsMapping(railsPath);
-
- // Apply override mappings for zones not yet in the CLDR trunk we pulled in
- // (NONE PRESENTLY)
-
- // Add missing Rails mappings where they make sense
- railsMapping.Remove("Arizona,America/Phoenix");
- railsMapping.Add("Arizona,America/Phoenix America/Whitehorse");
-
- // Add mappings for ISO country codes that aren't used in CLDR
- mapping.Add("Romance Standard Time,EA,Africa/Ceuta");
- mapping.Add("GMT Standard Time,IC,Atlantic/Canary");
- mapping.Add("Greenwich Standard Time,AC,Atlantic/St_Helena");
- mapping.Add("Greenwich Standard Time,TA,Atlantic/St_Helena");
- mapping.Add("Central Europe Standard Time,XK,Europe/Belgrade");
- mapping.Add("Central Asia Standard Time,DG,Indian/Chagos");
-
- // Add a few aliases for IANA abbreviated zones not tracked by CLDR
- aliases.Add("Europe/Paris,CET");
- aliases.Add("Europe/Bucharest,EET");
- aliases.Add("Europe/Berlin,MET");
- aliases.Add("Atlantic/Canary,WET");
-
- mapping.Sort(StringComparer.Ordinal);
- aliases.Sort(StringComparer.Ordinal);
-
- // Support mapping deprecated Windows zones, but after sorting so they are not used as primary results
- mapping.Add("Kamchatka Standard Time,001,Asia/Kamchatka");
- mapping.Add("Mid-Atlantic Standard Time,001,Etc/GMT+2");
-
- // Write to source files in the main library
- string projectPath = Path.GetFullPath(".");
- while (!File.Exists(Path.Combine(projectPath, "TimeZoneConverter.sln")))
- projectPath = Path.GetFullPath(Path.Combine(projectPath, ".."));
- string dataPath = Path.Combine(projectPath, "src", "TimeZoneConverter", "Data");
- WriteAllLinesToCompressedFile(Path.Combine(dataPath, "Mapping.csv.gz"), mapping);
- WriteAllLinesToCompressedFile(Path.Combine(dataPath, "Aliases.csv.gz"), aliases);
- WriteAllLinesToCompressedFile(Path.Combine(dataPath, "RailsMapping.csv.gz"), railsMapping);
- }
- finally
+ // Apply override mappings for zones not yet in the CLDR trunk we pulled in
+ // (None presently)
+
+ // Remove the alias for "Etc/Unknown Factory" as it's not a valid zone.
+ aliases.Remove("Etc/Unknown,Factory");
+
+ // Add mappings for ISO country codes that aren't used in CLDR
+ mapping.Add("Romance Standard Time,EA,Africa/Ceuta");
+ mapping.Add("GMT Standard Time,IC,Atlantic/Canary");
+ mapping.Add("Greenwich Standard Time,AC,Atlantic/St_Helena");
+ mapping.Add("Greenwich Standard Time,TA,Atlantic/St_Helena");
+ mapping.Add("Central Europe Standard Time,XK,Europe/Belgrade");
+ mapping.Add("Central Asia Standard Time,DG,Indian/Chagos");
+
+ mapping.Sort(StringComparer.Ordinal);
+ aliases.Sort(StringComparer.Ordinal);
+
+ // Support mapping deprecated Windows zones, but after sorting so they are not used as primary results
+ mapping.Add("Kamchatka Standard Time,001,Asia/Kamchatka");
+ mapping.Add("Mid-Atlantic Standard Time,001,Etc/GMT+2");
+
+ // Write to source files in the main library
+ var projectPath = Path.GetFullPath(".");
+ while (!File.Exists(Path.Combine(projectPath, "TimeZoneConverter.sln")))
{
- // Cleanup Data
- Directory.Delete(tempDir, true);
+ projectPath = Path.GetFullPath(Path.Combine(projectPath, ".."));
}
+
+ var dataPath = Path.Combine(projectPath, "src", "TimeZoneConverter", "Data");
+ WriteAllLinesToCompressedFile(Path.Combine(dataPath, "Mapping.csv.gz"), mapping);
+ WriteAllLinesToCompressedFile(Path.Combine(dataPath, "Aliases.csv.gz"), aliases);
+ WriteAllLinesToCompressedFile(Path.Combine(dataPath, "Territories.csv.gz"), territories);
+ WriteAllLinesToCompressedFile(Path.Combine(dataPath, "RailsMapping.csv.gz"), railsMapping);
}
+ finally
+ {
+ // Cleanup Data
+ Directory.Delete(tempDir, true);
+ }
+ }
- private static void WriteAllLinesToCompressedFile(string path, IEnumerable lines)
+ private static void WriteAllLinesToCompressedFile(string path, IEnumerable lines)
+ {
+ using var stream = File.Create(path);
+ using var compressedStream = new GZipStream(stream, CompressionLevel.Optimal);
+ using var writer = new StreamWriter(compressedStream);
+ foreach (var line in lines)
{
- using FileStream stream = File.Create(path);
- using var compressedStream = new GZipStream(stream, CompressionLevel.Optimal);
- using var writer = new StreamWriter(compressedStream);
- foreach (string line in lines)
- writer.WriteLine(line);
+ writer.WriteLine(line);
}
}
}
diff --git a/src/TimeZoneConverter.DataBuilder/TimeZoneConverter.DataBuilder.csproj b/src/TimeZoneConverter.DataBuilder/TimeZoneConverter.DataBuilder.csproj
index f8d0767..7e18cf8 100644
--- a/src/TimeZoneConverter.DataBuilder/TimeZoneConverter.DataBuilder.csproj
+++ b/src/TimeZoneConverter.DataBuilder/TimeZoneConverter.DataBuilder.csproj
@@ -1,12 +1,14 @@
-
+
- net6.0
+ net9.0
Exe
+ false
+ false
-
+
diff --git a/src/TimeZoneConverter.Posix/PosixTimeZone.cs b/src/TimeZoneConverter.Posix/PosixTimeZone.cs
index 4cf086a..c425bcf 100644
--- a/src/TimeZoneConverter.Posix/PosixTimeZone.cs
+++ b/src/TimeZoneConverter.Posix/PosixTimeZone.cs
@@ -1,179 +1,194 @@
-using System;
using System.Globalization;
using System.Text;
using NodaTime;
using NodaTime.Extensions;
using NodaTime.TimeZones;
-namespace TimeZoneConverter.Posix
+namespace TimeZoneConverter.Posix;
+
+///
+/// Provides methods to generate POSIX time zone strings.
+///
+public static class PosixTimeZone
{
+ private static readonly char[] PosixAbbreviationSplitChars = ['+', '-'];
+
///
- /// Provides methods to generate POSIX time zone strings.
+ /// Generates a POSIX time zone string from a object, for the current year.
+ /// Note - only uses only the property from the object.
///
- public static class PosixTimeZone
+ /// The object.
+ /// A POSIX time zone string.
+ public static string FromTimeZoneInfo(TimeZoneInfo timeZoneInfo)
{
- ///
- /// Generates a POSIX time zone string from a object, for the current year.
- /// Note - only uses only the property from the object.
- ///
- /// The object.
- /// A POSIX time zone string.
- public static string FromTimeZoneInfo(TimeZoneInfo timeZoneInfo)
- {
- return TZConvert.KnownIanaTimeZoneNames.Contains(timeZoneInfo.Id)
- ? FromIanaTimeZoneName(timeZoneInfo.Id)
- : FromWindowsTimeZoneId(timeZoneInfo.Id);
- }
+ return TZConvert.KnownIanaTimeZoneNames.Contains(timeZoneInfo.Id)
+ ? FromIanaTimeZoneName(timeZoneInfo.Id)
+ : FromWindowsTimeZoneId(timeZoneInfo.Id);
+ }
- ///
- /// Generates a POSIX time zone string from a object, for the given year.
- /// Note - only uses only the property from the object.
- ///
- /// The object.
- /// The reference year.
- /// A POSIX time zone string.
- public static string FromTimeZoneInfo(TimeZoneInfo timeZoneInfo, int year)
- {
- return TZConvert.KnownIanaTimeZoneNames.Contains(timeZoneInfo.Id)
- ? FromIanaTimeZoneName(timeZoneInfo.Id, year)
- : FromWindowsTimeZoneId(timeZoneInfo.Id, year);
- }
+ ///
+ /// Generates a POSIX time zone string from a object, for the given year.
+ /// Note - only uses only the property from the object.
+ ///
+ /// The object.
+ /// The reference year.
+ /// A POSIX time zone string.
+ public static string FromTimeZoneInfo(TimeZoneInfo timeZoneInfo, int year)
+ {
+ return TZConvert.KnownIanaTimeZoneNames.Contains(timeZoneInfo.Id)
+ ? FromIanaTimeZoneName(timeZoneInfo.Id, year)
+ : FromWindowsTimeZoneId(timeZoneInfo.Id, year);
+ }
- ///
- /// Generates a POSIX time zone string from a Windows time zone ID, for the current year.
- ///
- /// The Windows time zone ID.
- /// A POSIX time zone string.
- public static string FromWindowsTimeZoneId(string timeZoneId)
- {
- string tzName = TZConvert.WindowsToIana(timeZoneId);
- return FromIanaTimeZoneName(tzName);
- }
+ ///
+ /// Generates a POSIX time zone string from a Windows time zone ID, for the current year.
+ ///
+ /// The Windows time zone ID.
+ /// A POSIX time zone string.
+ public static string FromWindowsTimeZoneId(string timeZoneId)
+ {
+ var tzName = TZConvert.WindowsToIana(timeZoneId);
+ return FromIanaTimeZoneName(tzName);
+ }
- ///
- /// Generates a POSIX time zone string from a Windows time zone ID, for the given year.
- ///
- /// The Windows time zone ID.
- /// The reference year.
- /// A POSIX time zone string.
- public static string FromWindowsTimeZoneId(string timeZoneId, int year)
- {
- string tzName = TZConvert.WindowsToIana(timeZoneId);
- return FromIanaTimeZoneName(tzName, year);
- }
+ ///
+ /// Generates a POSIX time zone string from a Windows time zone ID, for the given year.
+ ///
+ /// The Windows time zone ID.
+ /// The reference year.
+ /// A POSIX time zone string.
+ public static string FromWindowsTimeZoneId(string timeZoneId, int year)
+ {
+ var tzName = TZConvert.WindowsToIana(timeZoneId);
+ return FromIanaTimeZoneName(tzName, year);
+ }
- ///
- /// Generates a POSIX time zone string from an IANA time zone name, for the current year.
- ///
- /// The IANA time zone name.
- /// A POSIX time zone string.
- public static string FromIanaTimeZoneName(string timeZoneName)
- {
- DateTimeZone tz = DateTimeZoneProviders.Tzdb[timeZoneName];
- LocalDate today = SystemClock.Instance.InZone(tz).GetCurrentDate();
- return FromIanaTimeZoneName(timeZoneName, today.Year);
- }
+ ///
+ /// Generates a POSIX time zone string from an IANA time zone name, for the current year.
+ ///
+ /// The IANA time zone name.
+ /// A POSIX time zone string.
+ public static string FromIanaTimeZoneName(string timeZoneName)
+ {
+ var tz = DateTimeZoneProviders.Tzdb[timeZoneName];
+ var today = SystemClock.Instance.InZone(tz).GetCurrentDate();
+ return FromIanaTimeZoneName(timeZoneName, today.Year);
+ }
- ///
- /// Generates a POSIX time zone string from an IANA time zone name, for the given year.
- ///
- /// The IANA time zone name.
- /// The reference year.
- /// A POSIX time zone string.
- public static string FromIanaTimeZoneName(string timeZoneName, int year)
- {
- DateTimeZone tz = DateTimeZoneProviders.Tzdb[timeZoneName];
+ ///
+ /// Generates a POSIX time zone string from an IANA time zone name, for the given year.
+ ///
+ /// The IANA time zone name.
+ /// The reference year.
+ /// A POSIX time zone string.
+ public static string FromIanaTimeZoneName(string timeZoneName, int year)
+ {
+ var tz = DateTimeZoneProviders.Tzdb[timeZoneName];
+
+ var jan = new LocalDate(year, 1, 1).AtStartOfDayInZone(tz);
+ var jul = new LocalDate(year, 7, 1).AtStartOfDayInZone(tz);
- ZonedDateTime jan = new LocalDate(year, 1, 1).AtStartOfDayInZone(tz);
- ZonedDateTime jul = new LocalDate(year, 7, 1).AtStartOfDayInZone(tz);
+ var janInterval = tz.GetZoneInterval(jan.ToInstant());
+ var julInterval = tz.GetZoneInterval(jul.ToInstant());
- ZoneInterval janInterval = tz.GetZoneInterval(jan.ToInstant());
- ZoneInterval julInterval = tz.GetZoneInterval(jul.ToInstant());
+ var stdInterval = janInterval.Savings == Offset.Zero
+ ? janInterval
+ : julInterval;
- ZoneInterval stdInterval = janInterval.Savings == Offset.Zero
- ? janInterval
- : julInterval;
+ var dltInterval = janInterval.Savings != Offset.Zero
+ ? janInterval
+ : julInterval.Savings != Offset.Zero
+ ? julInterval
+ : null;
- ZoneInterval dltInterval = janInterval.Savings != Offset.Zero
- ? janInterval
- : julInterval.Savings != Offset.Zero
- ? julInterval
- : null;
+ var sb = new StringBuilder();
- var sb = new StringBuilder();
+ var stdAbbreviation = GetPosixAbbreviation(stdInterval.Name);
+ sb.Append(stdAbbreviation);
- string stdAbbreviation = GetPosixAbbreviation(stdInterval.Name);
- sb.Append(stdAbbreviation);
+ var stdOffsetString = GetPosixOffsetString(stdInterval.WallOffset);
+ sb.Append(stdOffsetString);
- string stdOffsetString = GetPosixOffsetString(stdInterval.WallOffset);
- sb.Append(stdOffsetString);
+ if (dltInterval != null)
+ {
+ var dltAbbreviation = GetPosixAbbreviation(dltInterval.Name);
+ sb.Append(dltAbbreviation);
- if (dltInterval != null)
+ if (dltInterval.Savings != Offset.FromHours(1))
{
- string dltAbbreviation = GetPosixAbbreviation(dltInterval.Name);
- sb.Append(dltAbbreviation);
+ var dltOffsetString = GetPosixOffsetString(dltInterval.WallOffset);
+ sb.Append(dltOffsetString);
+ }
- if (dltInterval.Savings != Offset.FromHours(1))
- {
- string dltOffsetString = GetPosixOffsetString(dltInterval.WallOffset);
- sb.Append(dltOffsetString);
- }
+ var stdTransitionString = GetPosixTransitionString(stdInterval, tz);
+ sb.Append("," + stdTransitionString);
- string stdTransitionString = GetPosixTransitionString(stdInterval, tz);
- sb.Append("," + stdTransitionString);
+ var dltTransitionString = GetPosixTransitionString(dltInterval, tz);
+ sb.Append("," + dltTransitionString);
+ }
- string dltTransitionString = GetPosixTransitionString(dltInterval, tz);
- sb.Append("," + dltTransitionString);
- }
+ return sb.ToString();
+ }
- return sb.ToString();
- }
+ private static string GetPosixAbbreviation(string abbreviation)
+ {
+ return abbreviation.IndexOfAny(PosixAbbreviationSplitChars) != -1 ? "<" + abbreviation + ">" : abbreviation;
+ }
- private static string GetPosixAbbreviation(string abbreviation)
- {
- return abbreviation.IndexOfAny(new[] { '+', '-' }) != -1 ? "<" + abbreviation + ">" : abbreviation;
- }
+ private static string GetPosixOffsetString(Offset offset)
+ {
+ var negated = -offset;
+ return negated.ToString("-H:mm", CultureInfo.InvariantCulture).Replace(":00", "");
+ }
- private static string GetPosixOffsetString(Offset offset)
+ private static string GetPosixTransitionString(ZoneInterval interval, DateTimeZone tz)
+ {
+ if (!interval.HasEnd)
{
- Offset negated = -offset;
- return negated.ToString("-H:mm", CultureInfo.InvariantCulture).Replace(":00", "");
+ return "J365/25";
}
- private static string GetPosixTransitionString(ZoneInterval interval, DateTimeZone tz)
- {
- if (!interval.HasEnd) return "J365/25";
-
- LocalDateTime transition = interval.IsoLocalEnd;
- int transitionOccurrence = (transition.Day - 1) / 7 + 1;
+ var transition = interval.IsoLocalEnd;
+ var transitionOccurrence = (transition.Day - 1) / 7 + 1;
- // return "last occurrence" (5) when appropriate
- if (transitionOccurrence == 4)
+ // return "last occurrence" (5) when appropriate
+ if (transitionOccurrence == 4)
+ {
+ for (var i = 1; i <= 7; i++)
{
- for (var i = 1; i <= 7; i++)
+ var futureInstant = interval.IsoLocalEnd.PlusYears(i).InZoneLeniently(tz).ToInstant();
+ var futureInterval = tz.GetZoneInterval(futureInstant);
+ var occurrence = (futureInterval.IsoLocalEnd.Day - 1) / 7 + 1;
+ if (occurrence < 4)
{
- var futureInstant = interval.IsoLocalEnd.PlusYears(i).InZoneLeniently(tz).ToInstant();
- ZoneInterval futureInterval = tz.GetZoneInterval(futureInstant);
- int occurrence = (futureInterval.IsoLocalEnd.Day - 1) / 7 + 1;
- if (occurrence < 4)
- {
- transitionOccurrence = 4;
- break;
- }
-
- if (occurrence == 5)
- {
- transitionOccurrence = 5;
- }
+ transitionOccurrence = 4;
+ break;
+ }
+
+ if (occurrence == 5)
+ {
+ transitionOccurrence = 5;
}
}
+ }
- var datePart = $"M{transition.Month}.{transitionOccurrence}.{(int)transition.DayOfWeek.ToDayOfWeek()}";
+ var datePart = $"M{transition.Month}.{transitionOccurrence}.{(int)transition.DayOfWeek.ToDayOfWeek()}";
- if (transition.TimeOfDay == new LocalTime(2, 0)) return datePart;
- if (transition.Minute == 0 && transition.Second == 0) return $"{datePart}/{transition.Hour}";
- if (transition.Second == 0) return $"{datePart}/{transition.ToString("H:mm", CultureInfo.InvariantCulture)}";
- return $"{datePart}/{transition.ToString("H:mm:ss", CultureInfo.InvariantCulture)}";
+ if (transition.TimeOfDay == new LocalTime(2, 0))
+ {
+ return datePart;
+ }
+
+ if (transition.Minute == 0 && transition.Second == 0)
+ {
+ return $"{datePart}/{transition.Hour}";
}
+
+ if (transition.Second == 0)
+ {
+ return $"{datePart}/{transition.ToString("H:mm", CultureInfo.InvariantCulture)}";
+ }
+
+ return $"{datePart}/{transition.ToString("H:mm:ss", CultureInfo.InvariantCulture)}";
}
}
diff --git a/src/TimeZoneConverter.Posix/README.md b/src/TimeZoneConverter.Posix/README.md
new file mode 100644
index 0000000..98f165c
--- /dev/null
+++ b/src/TimeZoneConverter.Posix/README.md
@@ -0,0 +1,54 @@
+## TimeZoneConverter.Posix [](https://www.nuget.org/packages/TimeZoneConverter.Posix/)
+
+--------------------------------
+
+TimeZoneConverter.Posix generates POSIX time zone strings from standard time zone identifiers. POSIX time zones are useful in certain scenarios where time zone data is not present, such as when working with IoT devices.
+
+It is a separate helper library that is maintained in the same repository as `TimeZoneConverter`. You only need it if you require support for POSIX time zones.
+
+Note that `TimeZoneConverter.Posix` is dependendent on both [`TimeZoneConverter`][1] and [Noda Time][2] at run time.
+
+## Installation
+
+- Add the `TimeZoneConverter.Posix` NuGet package to your project.
+- Import the `TimeZoneConverter.Posix` namespace where needed.
+
+## Compatibility
+
+As of version 5.0.0, TimeZoneConverter.Posix works with all of the following:
+
+- .NET 6 or greater
+- .NET Core 2.0 or greater
+- .NET Framework 4.6.2 and greater
+
+.NET Framework versions less than 4.6.2 are no longer supported.
+
+## Example Usage
+
+Generate a POSIX time zone string from a Windows time zone ID.
+
+```csharp
+string posix = PosixTimeZone.FromWindowsTimeZoneId("Eastern Standard Time");
+// Result: "EST5EDT,M3.2.0,M11.1.0"
+```
+
+Generate a POSIX time zone string from an IANA time zone name.
+
+```csharp
+string posix = PosixTimeZone.FromIanaTimeZoneName("Australia/Sydney");
+// Result: "AEST-10AEDT,M10.1.0,M4.1.0/3"
+```
+
+Generate a POSIX time zone string from a `TimeZoneInfo` object.
+
+```csharp
+string posix = PosixTimeZone.FromTimeZoneInfo(TimeZoneInfo.Local);
+```
+
+## License
+
+This library is provided free of charge, under the terms of the [MIT license][3].
+
+[1]: https://github.com/mattjohnsonpint/TimeZoneConverter
+[2]: https://nodatime.org
+[3]: https://github.com/mattjohnsonpint/TimeZoneConverter/blob/main/LICENSE.txt
diff --git a/src/TimeZoneConverter.Posix/TimeZoneConverter.Posix.csproj b/src/TimeZoneConverter.Posix/TimeZoneConverter.Posix.csproj
index e9970a7..5e292d2 100644
--- a/src/TimeZoneConverter.Posix/TimeZoneConverter.Posix.csproj
+++ b/src/TimeZoneConverter.Posix/TimeZoneConverter.Posix.csproj
@@ -1,25 +1,24 @@
-
+
+ netstandard2.0;net462;net8.0;net9.0
Generates a POSIX time zone string from standard time zone identifiers.
Matt Johnson-Pint
- netstandard2.0;net461
TimeZoneConverter.Posix
timezone;time;zone;time zone;iana;tzdb;olson;timezoneinfo,posix
https://github.com/mattjohnsonpint/TimeZoneConverter
MIT
- 3.0.0
+ README.md
+ 5.1.0
-
- true
- true
- mj1856_oss.snk
-
+
+
+
+
-
-
+
diff --git a/src/TimeZoneConverter/CustomTimeZoneFactory.cs b/src/TimeZoneConverter/CustomTimeZoneFactory.cs
new file mode 100644
index 0000000..26cb7a8
--- /dev/null
+++ b/src/TimeZoneConverter/CustomTimeZoneFactory.cs
@@ -0,0 +1,50 @@
+using System.Diagnostics.CodeAnalysis;
+
+namespace TimeZoneConverter;
+
+internal static class CustomTimeZoneFactory
+{
+ private const string TrollTimeZoneId = "Antarctica/Troll";
+ private static readonly Lazy TrollTimeZone = new(CreateTrollTimeZone);
+
+ public static bool TryGetTimeZoneInfo(string timeZoneId, [MaybeNullWhen(false)] out TimeZoneInfo timeZoneInfo)
+ {
+ if (timeZoneId.Equals(TrollTimeZoneId, StringComparison.OrdinalIgnoreCase))
+ {
+ timeZoneInfo = TrollTimeZone.Value;
+ return true;
+ }
+
+ timeZoneInfo = null;
+ return false;
+ }
+
+ private static TimeZoneInfo CreateTrollTimeZone() =>
+ TimeZoneInfo.CreateCustomTimeZone(
+ id: TrollTimeZoneId,
+ baseUtcOffset: TimeSpan.Zero,
+ displayName: "(UTC+00:00) Troll Station, Antarctica",
+ standardDisplayName: "Greenwich Mean Time",
+ daylightDisplayName: "Central European Summer Time",
+ adjustmentRules:
+ [
+ // Like IANA, we will approximate with only UTC and CEST (UTC+2).
+ // Handling the CET (UTC+1) period would require generating adjustment rules for each individual year.
+ TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
+ dateStart: DateTime.MinValue.Date,
+ dateEnd: DateTime.MaxValue.Date,
+ daylightDelta: TimeSpan.FromHours(2), // Two hours DST gap
+ daylightTransitionStart: TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
+ timeOfDay: new DateTime(1, 1, 1, 1, 0, 0), // 01:00 local, 01:00 UTC
+ month: 3, // March
+ week: 5, // the last week of the month
+ DayOfWeek.Sunday),
+ daylightTransitionEnd: TimeZoneInfo.TransitionTime.CreateFloatingDateRule(
+ timeOfDay: new DateTime(1, 1, 1, 3, 0, 0), // 03:00 local, 01:00 UTC
+ month: 10, // October
+ week: 5, // the last week of the month
+ DayOfWeek.Sunday)
+ )
+ ]
+ );
+}
diff --git a/src/TimeZoneConverter/Data/Aliases.csv.gz b/src/TimeZoneConverter/Data/Aliases.csv.gz
index be712ca..056309f 100644
Binary files a/src/TimeZoneConverter/Data/Aliases.csv.gz and b/src/TimeZoneConverter/Data/Aliases.csv.gz differ
diff --git a/src/TimeZoneConverter/Data/Mapping.csv.gz b/src/TimeZoneConverter/Data/Mapping.csv.gz
index 591b33a..27b222b 100644
Binary files a/src/TimeZoneConverter/Data/Mapping.csv.gz and b/src/TimeZoneConverter/Data/Mapping.csv.gz differ
diff --git a/src/TimeZoneConverter/Data/RailsMapping.csv.gz b/src/TimeZoneConverter/Data/RailsMapping.csv.gz
index d1a42a6..4829cf7 100644
Binary files a/src/TimeZoneConverter/Data/RailsMapping.csv.gz and b/src/TimeZoneConverter/Data/RailsMapping.csv.gz differ
diff --git a/src/TimeZoneConverter/Data/Territories.csv.gz b/src/TimeZoneConverter/Data/Territories.csv.gz
new file mode 100644
index 0000000..f209f26
Binary files /dev/null and b/src/TimeZoneConverter/Data/Territories.csv.gz differ
diff --git a/src/TimeZoneConverter/DataLoader.cs b/src/TimeZoneConverter/DataLoader.cs
index a77bbd0..d5f144e 100644
--- a/src/TimeZoneConverter/DataLoader.cs
+++ b/src/TimeZoneConverter/DataLoader.cs
@@ -1,152 +1,196 @@
-using System.Collections.Generic;
-using System.IO;
using System.IO.Compression;
-using System.Linq;
-using System.Reflection;
using System.Resources;
-namespace TimeZoneConverter
+namespace TimeZoneConverter;
+
+internal static class DataLoader
{
- internal static class DataLoader
+ public static void Populate(
+ IDictionary ianaMap,
+ IDictionary windowsMap,
+ IDictionary railsMap,
+ IDictionary> inverseRailsMap,
+ IDictionary links,
+ IDictionary> ianaTerritoryZones)
{
- public static void Populate(IDictionary ianaMap, IDictionary windowsMap, IDictionary railsMap, IDictionary> inverseRailsMap)
- {
- IEnumerable mapping = GetEmbeddedData("TimeZoneConverter.Data.Mapping.csv.gz");
- IEnumerable aliases = GetEmbeddedData("TimeZoneConverter.Data.Aliases.csv.gz");
- IEnumerable railsMapping = GetEmbeddedData("TimeZoneConverter.Data.RailsMapping.csv.gz");
+ var mapping = GetEmbeddedData("TimeZoneConverter.Data.Mapping.csv.gz");
+ var aliases = GetEmbeddedData("TimeZoneConverter.Data.Aliases.csv.gz");
+ var railsMapping = GetEmbeddedData("TimeZoneConverter.Data.RailsMapping.csv.gz");
+ var territories = GetEmbeddedData("TimeZoneConverter.Data.Territories.csv.gz");
- var links = new Dictionary();
- foreach (string link in aliases)
+ foreach (var link in aliases)
+ {
+ var parts = link.Split(',');
+ var value = parts[0];
+ foreach (var key in parts[1].Split())
{
- string[] parts = link.Split(',');
- string value = parts[0];
- foreach (string key in parts[1].Split())
- links.Add(key, value);
+ links.Add(key, value);
}
+ }
- var similarIanaZones = new Dictionary>();
- foreach (string item in mapping)
- {
- string[] parts = item.Split(',');
- string windowsZone = parts[0];
- string territory = parts[1];
- string[] ianaZones = parts[2].Split();
+ foreach (var item in territories)
+ {
+ var parts = item.Split(',');
+ var territory = parts[0];
+ var zones = new List(parts[1].Split(' '));
+ ianaTerritoryZones.Add(territory, zones);
+ }
- // Create the Windows map entry
- if (!links.TryGetValue(ianaZones[0], out string value))
- value = ianaZones[0];
+ var similarIanaZones = new Dictionary>();
+ foreach (var item in mapping)
+ {
+ var parts = item.Split(',');
+ var windowsZone = parts[0]; // e.g. "Pacific Standard Time"
+ var territory = parts[1]; // e.g. "US"
+ var ianaZones = parts[2].Split(); // e.g. "America/Vancouver America/Dawson America/Whitehorse" -> `new String[] { "America/Vancouver", "America/Dawson", "America/Whitehorse" }`
- var key = $"{territory}|{windowsZone}";
- windowsMap.Add(key, value);
+ // Create the Windows map entry
+ var key = $"{territory}|{windowsZone}";
+ windowsMap.Add(key, ianaZones[0]);
- // Create the IANA map entries
- foreach (string ianaZone in ianaZones)
+ // Create the IANA map entries
+ foreach (var ianaZone in ianaZones)
+ {
+ if (!ianaMap.ContainsKey(ianaZone))
{
- if (!ianaMap.ContainsKey(ianaZone))
- ianaMap.Add(ianaZone, windowsZone);
+ ianaMap.Add(ianaZone, windowsZone);
}
+ }
- if (ianaZones.Length > 1)
+ if (ianaZones.Length > 1)
+ {
+ foreach (var ianaZone in ianaZones)
{
- foreach (string ianaZone in ianaZones)
- similarIanaZones.Add(ianaZone, ianaZones.Except(new[] { ianaZone }).ToArray());
+ similarIanaZones.Add(ianaZone, [.. ianaZones.Except([ianaZone])]);
}
}
+ }
- // Expand the IANA map to include all links (both directions)
- foreach (KeyValuePair link in links)
+ // Expand the IANA map to include all links (both directions)
+ var linksToMap = links.ToList();
+ while (linksToMap.Count > 0)
+ {
+ var retry = new List>();
+ foreach (var link in linksToMap)
{
- if (!ianaMap.ContainsKey(link.Key) && ianaMap.ContainsKey(link.Value))
+ var hasMapFromKey = ianaMap.TryGetValue(link.Key, out var mapFromKey);
+ var hasMapFromValue = ianaMap.TryGetValue(link.Value, out var mapFromValue);
+
+ if (hasMapFromKey && hasMapFromValue)
+ {
+ // There are already mappings in both directions
+ continue;
+ }
+
+ if (!hasMapFromKey && hasMapFromValue)
+ {
+ // Forward mapping
+ ianaMap.Add(link.Key, mapFromValue!);
+ }
+ else if (!hasMapFromValue && hasMapFromKey)
{
- ianaMap.Add(link.Key, ianaMap[link.Value]);
+ // Reverse mapping
+ ianaMap.Add(link.Value, mapFromKey!);
}
- else if (!ianaMap.ContainsKey(link.Value) && ianaMap.ContainsKey(link.Key))
+ else
{
- ianaMap.Add(link.Value, ianaMap[link.Key]);
+ // Not found yet, but we can try again
+ retry.Add(link);
}
}
- foreach (string item in railsMapping)
- {
- string[] parts = item.Split(',');
- string railsZone = parts[0];
- string[] ianaZones = parts[1].Split();
+ linksToMap = retry;
+ }
- for (var i = 0; i < ianaZones.Length; i++)
+ foreach (var item in railsMapping)
+ {
+ var parts = item.Split(',');
+ var railsZone = parts[0];
+ var ianaZones = parts[1].Split();
+
+ for (var i = 0; i < ianaZones.Length; i++)
+ {
+ var ianaZone = ianaZones[i];
+ if (i == 0)
{
- string ianaZone = ianaZones[i];
- if (i == 0)
- railsMap.Add(railsZone, ianaZone);
- else
- inverseRailsMap.Add(ianaZone, new[] { railsZone });
+ railsMap.Add(railsZone, ianaZone);
+ }
+ else
+ {
+ inverseRailsMap.Add(ianaZone, [railsZone]);
}
}
+ }
+
+ foreach (var grouping in railsMap.GroupBy(x => x.Value, x => x.Key))
+ {
+ inverseRailsMap.Add(grouping.Key, [.. grouping]);
+ }
- foreach (IGrouping grouping in railsMap.GroupBy(x => x.Value, x => x.Key))
+ // Expand the Inverse Rails map to include similar IANA zones
+ foreach (var ianaZone in ianaMap.Keys)
+ {
+ if (inverseRailsMap.ContainsKey(ianaZone) || links.ContainsKey(ianaZone))
{
- inverseRailsMap.Add(grouping.Key, grouping.ToList());
+ continue;
}
- // Expand the Inverse Rails map to include similar IANA zones
- foreach (string ianaZone in ianaMap.Keys)
+ if (similarIanaZones.TryGetValue(ianaZone, out var similarZones))
{
- if (inverseRailsMap.ContainsKey(ianaZone) || links.ContainsKey(ianaZone))
- continue;
-
- if (similarIanaZones.TryGetValue(ianaZone, out IList similarZones))
+ foreach (var otherZone in similarZones)
{
- foreach (string otherZone in similarZones)
+ if (inverseRailsMap.TryGetValue(otherZone, out var railsZones))
{
- if (inverseRailsMap.TryGetValue(otherZone, out IList railsZones))
- {
- inverseRailsMap.Add(ianaZone, railsZones);
- break;
- }
+ inverseRailsMap.Add(ianaZone, railsZones);
+ break;
}
}
}
+ }
- // Expand the Inverse Rails map to include links (in either direction)
- foreach (KeyValuePair link in links)
+ // Expand the Inverse Rails map to include links (in either direction)
+ foreach (var link in links)
+ {
+ if (!inverseRailsMap.ContainsKey(link.Key))
{
- if (!inverseRailsMap.ContainsKey(link.Key))
+ if (inverseRailsMap.TryGetValue(link.Value, out var railsZone))
{
- if (inverseRailsMap.TryGetValue(link.Value, out IList railsZone))
- inverseRailsMap.Add(link.Key, railsZone);
+ inverseRailsMap.Add(link.Key, railsZone);
}
- else if (!inverseRailsMap.ContainsKey(link.Value))
+ }
+ else if (!inverseRailsMap.ContainsKey(link.Value))
+ {
+ if (inverseRailsMap.TryGetValue(link.Key, out var railsZone))
{
- if (inverseRailsMap.TryGetValue(link.Key, out IList railsZone))
- inverseRailsMap.Add(link.Value, railsZone);
+ inverseRailsMap.Add(link.Value, railsZone);
}
}
+ }
- // Expand the Inverse Rails map to use CLDR golden zones
- foreach (string ianaZone in ianaMap.Keys)
+ // Expand the Inverse Rails map to use CLDR golden zones
+ foreach (var ianaZone in ianaMap.Keys)
+ {
+ if (!inverseRailsMap.ContainsKey(ianaZone) &&
+ ianaMap.TryGetValue(ianaZone, out var windowsZone) &&
+ windowsMap.TryGetValue("001|" + windowsZone, out var goldenZone) &&
+ inverseRailsMap.TryGetValue(goldenZone, out var railsZones))
{
- if (!inverseRailsMap.ContainsKey(ianaZone))
- if (ianaMap.TryGetValue(ianaZone, out string windowsZone))
- if (windowsMap.TryGetValue("001|" + windowsZone, out string goldenZone))
- if (inverseRailsMap.TryGetValue(goldenZone, out IList railsZones))
- inverseRailsMap.Add(ianaZone, railsZones);
+ inverseRailsMap.Add(ianaZone, railsZones);
}
-
-
}
+ }
- private static IEnumerable GetEmbeddedData(string resourceName)
+ private static IEnumerable GetEmbeddedData(string resourceName)
+ {
+ var assembly = typeof(DataLoader).Assembly;
+ using var compressedStream = assembly.GetManifestResourceStream(resourceName) ??
+ throw new MissingManifestResourceException();
+ using var stream = new GZipStream(compressedStream, CompressionMode.Decompress);
+ using var reader = new StreamReader(stream);
+
+ while (reader.ReadLine() is { } line)
{
- Assembly assembly = typeof(DataLoader).GetTypeInfo().Assembly;
- using (Stream compressedStream = assembly.GetManifestResourceStream(resourceName) ?? throw new MissingManifestResourceException())
- using (var stream = new GZipStream(compressedStream, CompressionMode.Decompress))
- using (var reader = new StreamReader(stream))
- {
- string line;
- while ((line = reader.ReadLine()) != null)
- {
- yield return line;
- }
- }
+ yield return line;
}
}
}
diff --git a/src/TimeZoneConverter/LinkResolution.cs b/src/TimeZoneConverter/LinkResolution.cs
new file mode 100644
index 0000000..d7d5bb3
--- /dev/null
+++ b/src/TimeZoneConverter/LinkResolution.cs
@@ -0,0 +1,38 @@
+namespace TimeZoneConverter;
+
+///
+/// Provides options for how links are resolved when returning results from
+/// converting from a Windows zone to an IANA zone.
+///
+public enum LinkResolution
+{
+ ///
+ /// Return an IANA canonical value for the conversion, except for the case
+ /// when an alias is more regionally appropriate for the conversion.
+ ///
+ ///
+ /// Ex: "India Standard Time" => "Asia/Kolkata"
+ /// "SA Western Standard Time" (AG) => "America/Antigua"
+ ///
+ Default = 0,
+
+ ///
+ /// Always return an IANA canonical value.
+ ///
+ ///
+ /// This was the default behavior prior to version 6.0.
+ /// Ex: "India Standard Time" => "Asia/Kolkata"
+ /// "SA Western Standard Time" (AG) => "America/Puerto_Rico"
+ ///
+ Canonical,
+
+ ///
+ /// Always return the original value from the CLDR mapping, without attempting
+ /// to resolve it to the IANA canonical form.
+ ///
+ ///
+ /// Ex: "India Standard Time" => "Asia/Calcutta"
+ /// "SA Western Standard Time" (AG) => "America/Antigua"
+ ///
+ Original
+}
diff --git a/src/TimeZoneConverter/README.md b/src/TimeZoneConverter/README.md
new file mode 100644
index 0000000..a2a681f
--- /dev/null
+++ b/src/TimeZoneConverter/README.md
@@ -0,0 +1 @@
+See the root-level [README.md](../../README.md).
\ No newline at end of file
diff --git a/src/TimeZoneConverter/TZConvert.cs b/src/TimeZoneConverter/TZConvert.cs
index f577bad..315c23f 100644
--- a/src/TimeZoneConverter/TZConvert.cs
+++ b/src/TimeZoneConverter/TZConvert.cs
@@ -1,362 +1,701 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
-#if NETSTANDARD
+using System.Collections.ObjectModel;
+using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
-#endif
-namespace TimeZoneConverter
+namespace TimeZoneConverter;
+
+///
+/// Converts time zone identifiers from various sources.
+///
+public static class TZConvert
{
- ///
- /// Converts time zone identifiers from various sources.
- ///
- public static class TZConvert
+ private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+ private static readonly Dictionary IanaMap = new(StringComparer.OrdinalIgnoreCase);
+ private static readonly Dictionary WindowsMap = new(StringComparer.OrdinalIgnoreCase);
+ private static readonly Dictionary RailsMap = new(StringComparer.OrdinalIgnoreCase);
+ private static readonly Dictionary> InverseRailsMap = new(StringComparer.OrdinalIgnoreCase);
+ private static readonly Dictionary Links = new(StringComparer.OrdinalIgnoreCase);
+ private static readonly Dictionary SystemTimeZones;
+
+ private static readonly IDictionary> IanaTerritoryZones =
+ new Dictionary>(StringComparer.OrdinalIgnoreCase);
+
+ static TZConvert()
{
- private static readonly IDictionary IanaMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
- private static readonly IDictionary WindowsMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
- private static readonly IDictionary RailsMap = new Dictionary(StringComparer.OrdinalIgnoreCase);
- private static readonly IDictionary> InverseRailsMap = new Dictionary>(StringComparer.OrdinalIgnoreCase);
+ DataLoader.Populate(IanaMap, WindowsMap, RailsMap, InverseRailsMap, Links, IanaTerritoryZones);
-#if NETSTANDARD
- private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
-#else
- private const bool IsWindows = true;
-#endif
+ var knownIanaTimeZoneNames = new HashSet(IanaMap.Select(x => x.Key));
+ var knownWindowsTimeZoneIds = new HashSet(WindowsMap.Keys.Select(x => x.Split('|')[1]).Distinct());
+ var knownRailsTimeZoneNames = new HashSet(RailsMap.Select(x => x.Key));
- private static readonly Dictionary SystemTimeZones;
+ // Special case - not in any map.
+ knownIanaTimeZoneNames.Add("Antarctica/Troll");
- static TZConvert()
- {
- DataLoader.Populate(IanaMap, WindowsMap, RailsMap, InverseRailsMap);
+ // Remove zones from KnownIanaTimeZoneNames that have been removed from IANA data.
+ // (They should still map to Windows zones correctly.)
+ knownIanaTimeZoneNames.Remove("Canada/East-Saskatchewan"); // Removed in 2017c
+ knownIanaTimeZoneNames.Remove("US/Pacific-New"); // Removed in 2018a
+
+ // Remove zones from KnownWindowsTimeZoneIds that are marked obsolete in the Windows Registry.
+ // (They should still map to IANA zones correctly.)
+ knownWindowsTimeZoneIds.Remove("Kamchatka Standard Time");
+ knownWindowsTimeZoneIds.Remove("Mid-Atlantic Standard Time");
+
+ var knownIanaCanonicalNames = knownIanaTimeZoneNames.Except(Links.Keys).ToHashSet();
- KnownIanaTimeZoneNames = new HashSet(IanaMap.Select(x => x.Key));
- KnownWindowsTimeZoneIds = new HashSet(WindowsMap.Keys.Select(x => x.Split('|')[1]).Distinct());
- KnownRailsTimeZoneNames = new HashSet(RailsMap.Select(x => x.Key));
+ KnownIanaTimeZoneNames = knownIanaTimeZoneNames;
+ KnownWindowsTimeZoneIds = knownWindowsTimeZoneIds;
+ KnownRailsTimeZoneNames = knownRailsTimeZoneNames;
+ KnownIanaCanonicalNames = knownIanaCanonicalNames;
- // Special case - not in any map.
- KnownIanaTimeZoneNames.Add("Antarctica/Troll");
+ SystemTimeZones = GetSystemTimeZones();
+ }
- // Remove zones from KnownIanaTimeZoneNames that have been removed from IANA data.
- // (They should still map to Windows zones correctly.)
- KnownIanaTimeZoneNames.Remove("Canada/East-Saskatchewan"); // Removed in 2017c
- KnownIanaTimeZoneNames.Remove("US/Pacific-New"); // Removed in 2018a
+ ///
+ /// Gets a collection of all IANA time zone names known to this library.
+ ///
+ public static IReadOnlyCollection KnownIanaTimeZoneNames { get; }
- // Remove zones from KnownWindowsTimeZoneIds that are marked obsolete in the Windows Registry.
- // (They should still map to IANA zones correctly.)
- KnownWindowsTimeZoneIds.Remove("Kamchatka Standard Time");
- KnownWindowsTimeZoneIds.Remove("Mid-Atlantic Standard Time");
+ ///
+ /// Gets a collection of all Windows time zone IDs known to this library.
+ ///
+ public static IReadOnlyCollection KnownWindowsTimeZoneIds { get; }
- SystemTimeZones = GetSystemTimeZones();
+ ///
+ /// Gets a collection of all Rails time zone names known to this library.
+ ///
+ public static IReadOnlyCollection KnownRailsTimeZoneNames { get; }
+
+ ///
+ /// Gets a collection of all IANA canonical time zone names known to this library.
+ ///
+ public static IReadOnlyCollection KnownIanaCanonicalNames { get; }
+
+ ///
+ /// Gets a dictionary that has an sorted collection of IANA time zone names keyed by territory code.
+ ///
+ ///
+ /// When set true, each territory contains the full list zones applicable to that territory.
+ /// Otherwise, the list is condensed to only those typically needed for selecting a time zone.
+ ///
+ /// The dictionary of territories and time zone names.
+ public static IReadOnlyDictionary> GetIanaTimeZoneNamesByTerritory(bool fullList = false)
+ {
+ if (fullList)
+ {
+ return new ReadOnlyDictionary>(
+ IanaTerritoryZones.ToDictionary(
+ x => x.Key,
+ x => (IReadOnlyCollection)x.Value
+ .Order()
+ .ToList().AsReadOnly()));
}
- ///
- /// Gets a collection of all IANA time zone names known to this library.
- ///
- public static ICollection KnownIanaTimeZoneNames { get; }
-
- ///
- /// Gets a collection of all Windows time zone IDs known to this library.
- ///
- public static ICollection KnownWindowsTimeZoneIds { get; }
-
- ///
- /// Gets a collection of all Rails time zone names known to this library.
- ///
- public static ICollection KnownRailsTimeZoneNames { get; }
-
- ///
- /// Converts an IANA time zone name to the equivalent Windows time zone ID.
- ///
- /// The IANA time zone name to convert.
- /// A Windows time zone ID.
- /// Thrown if the input string was not recognized or has no equivalent Windows zone.
- public static string IanaToWindows(string ianaTimeZoneName)
+ // Converting to windows and back has the reduction effect we are looking for
+ return new ReadOnlyDictionary>(
+ IanaTerritoryZones.ToDictionary(
+ x => x.Key,
+ x => (IReadOnlyCollection)x.Value
+ .Select(zone => TryIanaToWindows(zone, out var winId)
+ ? WindowsToIana(winId, x.Key)
+ : zone)
+ .Order()
+ .Distinct()
+ .ToList().AsReadOnly()));
+ }
+
+ ///
+ /// Converts an IANA time zone name to the equivalent Windows time zone ID.
+ ///
+ /// The IANA time zone name to convert.
+ /// A Windows time zone ID.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent Windows
+ /// zone.
+ ///
+ public static string IanaToWindows(string ianaTimeZoneName)
+ {
+ if (TryIanaToWindows(ianaTimeZoneName, out var windowsTimeZoneId))
{
- if (TryIanaToWindows(ianaTimeZoneName, out string windowsTimeZoneId))
- return windowsTimeZoneId;
+ return windowsTimeZoneId;
+ }
+
+ throw new InvalidTimeZoneException(
+ $"\"{ianaTimeZoneName}\" was not recognized as a valid IANA time zone name, or has no equivalent Windows time zone.");
+ }
- throw new InvalidTimeZoneException($"\"{ianaTimeZoneName}\" was not recognized as a valid IANA time zone name, or has no equivalent Windows time zone.");
+ ///
+ /// Attempts to convert an IANA time zone name to the equivalent Windows time zone ID.
+ ///
+ /// The IANA time zone name to convert.
+ /// A Windows time zone ID.
+ /// true if successful, false otherwise.
+ public static bool TryIanaToWindows(string ianaTimeZoneName, [MaybeNullWhen(false)] out string windowsTimeZoneId)
+ {
+ if (string.IsNullOrWhiteSpace(ianaTimeZoneName))
+ {
+ windowsTimeZoneId = null;
+ return false;
}
- ///
- /// Attempts to convert an IANA time zone name to the equivalent Windows time zone ID.
- ///
- /// The IANA time zone name to convert.
- /// A Windows time zone ID.
- /// true if successful, false otherwise.
- public static bool TryIanaToWindows(string ianaTimeZoneName, out string windowsTimeZoneId)
+ return IanaMap.TryGetValue(ianaTimeZoneName, out windowsTimeZoneId!);
+ }
+
+ ///
+ /// Converts a Windows time zone ID to an equivalent IANA time zone name.
+ ///
+ /// The Windows time zone ID to convert.
+ ///
+ /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
+ /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
+ ///
+ /// An IANA time zone name.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent IANA
+ /// zone.
+ ///
+ public static string WindowsToIana(string windowsTimeZoneId, string territoryCode = "001")
+ {
+ return WindowsToIana(windowsTimeZoneId, territoryCode, LinkResolution.Default);
+ }
+
+ ///
+ /// Converts a Windows time zone ID to an equivalent IANA time zone name.
+ ///
+ /// The Windows time zone ID to convert.
+ /// The mode of resolving links for the result.
+ /// An IANA time zone name.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent IANA
+ /// zone.
+ ///
+ public static string WindowsToIana(string windowsTimeZoneId, LinkResolution linkResolutionMode)
+ {
+ return WindowsToIana(windowsTimeZoneId, "001", linkResolutionMode);
+ }
+
+ ///
+ /// Converts a Windows time zone ID to an equivalent IANA time zone name.
+ ///
+ /// The Windows time zone ID to convert.
+ ///
+ /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
+ /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
+ ///
+ /// The mode of resolving links for the result.
+ /// An IANA time zone name.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent IANA
+ /// zone.
+ ///
+ public static string WindowsToIana(string windowsTimeZoneId, string territoryCode, LinkResolution linkResolutionMode)
+ {
+ if (TryWindowsToIana(windowsTimeZoneId, territoryCode, out var ianaTimeZoneName, linkResolutionMode))
{
- return IanaMap.TryGetValue(ianaTimeZoneName, out windowsTimeZoneId);
+ return ianaTimeZoneName;
}
- ///
- /// Converts a Windows time zone ID to an equivalent IANA time zone name.
- ///
- /// The Windows time zone ID to convert.
- ///
- /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
- /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
- ///
- /// An IANA time zone name.
- /// Thrown if the input string was not recognized or has no equivalent IANA zone.
- public static string WindowsToIana(string windowsTimeZoneId, string territoryCode = "001")
+ throw new InvalidTimeZoneException(
+ $"\"{windowsTimeZoneId}\" was not recognized as a valid Windows time zone ID.");
+ }
+
+ ///
+ /// Attempts to convert a Windows time zone ID to an equivalent IANA time zone name.
+ /// Uses the "golden zone" - the one that is the most prevalent.
+ ///
+ /// The Windows time zone ID to convert.
+ /// An IANA time zone name.
+ /// true if successful, false otherwise.
+ public static bool TryWindowsToIana(
+ string windowsTimeZoneId,
+ [MaybeNullWhen(false)] out string ianaTimeZoneName)
+ {
+ return TryWindowsToIana(windowsTimeZoneId, "001", out ianaTimeZoneName, LinkResolution.Default);
+ }
+
+ ///
+ /// Attempts to convert a Windows time zone ID to an equivalent IANA time zone name.
+ /// Uses the "golden zone" - the one that is the most prevalent.
+ ///
+ /// The Windows time zone ID to convert.
+ /// An IANA time zone name.
+ /// The mode of resolving links for the result.
+ /// true if successful, false otherwise.
+ public static bool TryWindowsToIana(
+ string windowsTimeZoneId,
+ [MaybeNullWhen(false)] out string ianaTimeZoneName,
+ LinkResolution linkResolutionMode)
+ {
+ return TryWindowsToIana(windowsTimeZoneId, "001", out ianaTimeZoneName, linkResolutionMode);
+ }
+
+ ///
+ /// Attempts to convert a Windows time zone ID to an equivalent IANA time zone name.
+ ///
+ /// The Windows time zone ID to convert.
+ ///
+ /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
+ /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
+ ///
+ /// An IANA time zone name.
+ /// true if successful, false otherwise.
+ public static bool TryWindowsToIana(
+ string windowsTimeZoneId,
+ string territoryCode,
+ [MaybeNullWhen(false)] out string ianaTimeZoneName)
+ {
+ return TryWindowsToIana(windowsTimeZoneId, territoryCode, out ianaTimeZoneName, LinkResolution.Default);
+ }
+
+ ///
+ /// Attempts to convert a Windows time zone ID to an equivalent IANA time zone name.
+ ///
+ /// The Windows time zone ID to convert.
+ ///
+ /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
+ /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
+ ///
+ /// An IANA time zone name.
+ /// The mode of resolving links for the result.
+ /// true if successful, false otherwise.
+ public static bool TryWindowsToIana(
+ string windowsTimeZoneId,
+ string territoryCode,
+ [MaybeNullWhen(false)] out string ianaTimeZoneName,
+ LinkResolution linkResolutionMode)
+ {
+ // try first with the given region
+ var found = WindowsMap.TryGetValue($"{territoryCode}|{windowsTimeZoneId}", out var ianaId);
+
+ string? goldenIanaId = null;
+ if (territoryCode != "001" && (linkResolutionMode == LinkResolution.Default || !found))
{
- if (TryWindowsToIana(windowsTimeZoneId, territoryCode, out string ianaTimeZoneName))
- return ianaTimeZoneName;
+ // we need to look up the golden zone also
+ var goldenFound = WindowsMap.TryGetValue($"001|{windowsTimeZoneId}", out goldenIanaId);
- throw new InvalidTimeZoneException($"\"{windowsTimeZoneId}\" was not recognized as a valid Windows time zone ID.");
+ if (!found)
+ {
+ found = goldenFound;
+ ianaId = goldenIanaId;
+ }
}
- ///
- /// Attempts to convert a Windows time zone ID to an equivalent IANA time zone name.
- /// Uses the "golden zone" - the one that is the most prevalent.
- ///
- /// The Windows time zone ID to convert.
- /// An IANA time zone name.
- /// true if successful, false otherwise.
- public static bool TryWindowsToIana(string windowsTimeZoneId, out string ianaTimeZoneName)
+ if (!found)
{
- return TryWindowsToIana(windowsTimeZoneId, "001", out ianaTimeZoneName);
+ ianaTimeZoneName = null;
+ return false;
}
- ///
- /// Attempts to convert a Windows time zone ID to an equivalent IANA time zone name.
- ///
- /// The Windows time zone ID to convert.
- ///
- /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
- /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
- ///
- /// An IANA time zone name.
- /// true if successful, false otherwise.
- public static bool TryWindowsToIana(string windowsTimeZoneId, string territoryCode, out string ianaTimeZoneName)
+ ianaTimeZoneName = ianaId!;
+
+ // resolve links
+ switch (linkResolutionMode)
{
- if (WindowsMap.TryGetValue($"{territoryCode}|{windowsTimeZoneId}", out ianaTimeZoneName))
+ case LinkResolution.Default:
+ if (goldenIanaId == null || ianaId == goldenIanaId)
+ {
+ ianaTimeZoneName = ResolveLink(ianaId!);
+ }
+ else
+ {
+ var goldenResolved = ResolveLink(goldenIanaId);
+ var specificResolved = ResolveLink(ianaId!);
+ if (goldenResolved != specificResolved && !WindowsMap.ContainsValue(specificResolved))
+ {
+ ianaTimeZoneName = specificResolved;
+ }
+ }
+
+ return true;
+
+ case LinkResolution.Canonical:
+ ianaTimeZoneName = ResolveLink(ianaId!);
return true;
- // use the golden zone when not found with a particular region
- return territoryCode != "001" && WindowsMap.TryGetValue($"001|{windowsTimeZoneId}", out ianaTimeZoneName);
+ case LinkResolution.Original:
+ return true;
+
+ default:
+ throw new ArgumentOutOfRangeException(nameof(linkResolutionMode), linkResolutionMode, null);
+ }
+ }
+
+ private static string ResolveLink(string linkOrZone)
+ {
+ return Links.TryGetValue(linkOrZone, out var zone) ? zone : linkOrZone;
+ }
+
+ ///
+ /// Retrieves a object given a valid Windows or IANA time zone identifier,
+ /// regardless of which platform the application is running on.
+ ///
+ /// A valid Windows or IANA time zone identifier.
+ /// A object.
+ public static TimeZoneInfo GetTimeZoneInfo(string windowsOrIanaTimeZoneId)
+ {
+ if (TryGetTimeZoneInfo(windowsOrIanaTimeZoneId, out var timeZoneInfo))
+ {
+ return timeZoneInfo;
+ }
+
+ throw new TimeZoneNotFoundException($"\"{windowsOrIanaTimeZoneId}\" was not found.");
+ }
+
+ ///
+ /// Attempts to retrieve a object given a valid Windows or IANA time zone identifier,
+ /// regardless of which platform the application is running on.
+ ///
+ /// A valid Windows or IANA time zone identifier.
+ /// A object.
+ /// true if successful, false otherwise.
+ public static bool TryGetTimeZoneInfo(string windowsOrIanaTimeZoneId,
+ [MaybeNullWhen(false)] out TimeZoneInfo timeZoneInfo)
+ {
+ if (string.IsNullOrWhiteSpace(windowsOrIanaTimeZoneId))
+ {
+ timeZoneInfo = null;
+ return false;
}
- ///
- /// Retrieves a object given a valid Windows or IANA time zone identifier,
- /// regardless of which platform the application is running on.
- ///
- /// A valid Windows or IANA time zone identifier.
- /// A object.
- public static TimeZoneInfo GetTimeZoneInfo(string windowsOrIanaTimeZoneId)
+ if (string.Equals(windowsOrIanaTimeZoneId, "UTC", StringComparison.OrdinalIgnoreCase))
{
- if (TryGetTimeZoneInfo(windowsOrIanaTimeZoneId, out TimeZoneInfo timeZoneInfo))
- return timeZoneInfo;
+ timeZoneInfo = TimeZoneInfo.Utc;
+ return true;
+ }
- throw new TimeZoneNotFoundException();
+ // Try a direct approach
+ if (SystemTimeZones.TryGetValue(windowsOrIanaTimeZoneId, out timeZoneInfo))
+ {
+ return true;
}
- ///
- /// Attempts to retrieve a object given a valid Windows or IANA time zone identifier,
- /// regardless of which platform the application is running on.
- ///
- /// A valid Windows or IANA time zone identifier.
- /// A object.
- /// true if successful, false otherwise.
- public static bool TryGetTimeZoneInfo(string windowsOrIanaTimeZoneId, out TimeZoneInfo timeZoneInfo)
+ if (IsWindows)
{
- if (string.Equals(windowsOrIanaTimeZoneId, "UTC", StringComparison.OrdinalIgnoreCase))
+ // Convert to IANA and try again.
+ if (TryIanaToWindows(windowsOrIanaTimeZoneId, out var tzid) &&
+ SystemTimeZones.TryGetValue(tzid, out timeZoneInfo))
{
- timeZoneInfo = TimeZoneInfo.Utc;
return true;
}
-
- // Try a direct approach
- if (SystemTimeZones.TryGetValue(windowsOrIanaTimeZoneId, out timeZoneInfo))
- return true;
-
- // Convert to the opposite platform and try again
- return (IsWindows && TryIanaToWindows(windowsOrIanaTimeZoneId, out string tzid) ||
- TryWindowsToIana(windowsOrIanaTimeZoneId, out tzid)) &&
- SystemTimeZones.TryGetValue(tzid, out timeZoneInfo);
}
-
- ///
- /// Converts an IANA time zone name to one or more equivalent Rails time zone names.
- ///
- /// The IANA time zone name to convert.
- /// One or more equivalent Rails time zone names.
- /// Thrown if the input string was not recognized or has no equivalent Rails zone.
- public static IList IanaToRails(string ianaTimeZoneName)
+ else
{
- if (TryIanaToRails(ianaTimeZoneName, out IList railsTimeZoneNames))
- return railsTimeZoneNames;
+ // If it's IANA, try resolving links first.
+ if (KnownIanaTimeZoneNames.Contains(windowsOrIanaTimeZoneId))
+ {
+ var canonicalId = ResolveLink(windowsOrIanaTimeZoneId);
+ if (SystemTimeZones.TryGetValue(canonicalId, out timeZoneInfo))
+ {
+ return true;
+ }
+ }
+ else
+ {
+ // Convert from Windows and try again.
+ // Note, we use LinkResolution.Original here for some minor perf gain.
+ if (TryWindowsToIana(windowsOrIanaTimeZoneId, out var tzid, LinkResolution.Original))
+ {
+ if (SystemTimeZones.TryGetValue(tzid, out timeZoneInfo))
+ {
+ return true;
+ }
+
+ // Try again with link resolution.
+ if (SystemTimeZones.TryGetValue(ResolveLink(tzid), out timeZoneInfo))
+ {
+ return true;
+ }
+ }
+ }
+ }
- throw new InvalidTimeZoneException($"\"{ianaTimeZoneName}\" was not recognized as a valid IANA time zone name, or has no equivalent Rails time zone.");
+ // See if we know how to create an equivalent custom time zone.
+ if (CustomTimeZoneFactory.TryGetTimeZoneInfo(windowsOrIanaTimeZoneId, out timeZoneInfo))
+ {
+ return true;
}
- ///
- /// Attempts to convert an IANA time zone name to one or more equivalent Rails time zone names.
- ///
- /// The IANA time zone name to convert.
- /// One or more equivalent Rails time zone names.
- /// true if successful, false otherwise.
- public static bool TryIanaToRails(string ianaTimeZoneName, out IList railsTimeZoneNames)
+ return false;
+ }
+
+ ///
+ /// Attempts to resolve the IANA canonical name given an IANA time zone name.
+ ///
+ /// The IANA time zone name to resolve.
+ /// The resolved IANA canonical time zone name.
+ /// true if successful, false otherwise.
+ ///
+ /// The resolving will succeed whether the input name is an alias or a canonical name.
+ ///
+ public static bool TryGetIanaCanonicalName(
+ string ianaTimeZoneName,
+ [MaybeNullWhen(false)] out string ianaCanonicalName)
+ {
+ if (ianaTimeZoneName == null || !KnownIanaTimeZoneNames.Contains(ianaTimeZoneName))
{
- // try directly first
- if (InverseRailsMap.TryGetValue(ianaTimeZoneName, out railsTimeZoneNames))
- return true;
+ ianaCanonicalName = null;
+ return false;
+ }
+
+ ianaCanonicalName = Links.TryGetValue(ianaTimeZoneName, out ianaCanonicalName)
+ ? ianaCanonicalName
+ : ianaTimeZoneName;
- // try again with the golden zone
- return TryIanaToWindows(ianaTimeZoneName, out string windowsTimeZoneId) &&
- TryWindowsToIana(windowsTimeZoneId, out string ianaGoldenZone) &&
- InverseRailsMap.TryGetValue(ianaGoldenZone, out railsTimeZoneNames);
+ return true;
+ }
+
+ ///
+ /// Converts an IANA time zone name to one or more equivalent Rails time zone names.
+ ///
+ /// The IANA time zone name to convert.
+ /// One or more equivalent Rails time zone names.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent Rails
+ /// zone.
+ ///
+ public static IList IanaToRails(string ianaTimeZoneName)
+ {
+ if (TryIanaToRails(ianaTimeZoneName, out var railsTimeZoneNames))
+ {
+ return railsTimeZoneNames;
}
- ///
- /// Converts a Rails time zone name to an equivalent IANA time zone name.
- ///
- /// The Rails time zone name to convert.
- /// An IANA time zone name.
- /// Thrown if the input string was not recognized or has no equivalent IANA zone.
- public static string RailsToIana(string railsTimeZoneName)
+ throw new InvalidTimeZoneException(
+ $"\"{ianaTimeZoneName}\" was not recognized as a valid IANA time zone name, or has no equivalent Rails time zone.");
+ }
+
+ ///
+ /// Attempts to convert an IANA time zone name to one or more equivalent Rails time zone names.
+ ///
+ /// The IANA time zone name to convert.
+ /// One or more equivalent Rails time zone names.
+ /// true if successful, false otherwise.
+ public static bool TryIanaToRails(string ianaTimeZoneName, out IList railsTimeZoneNames)
+ {
+ if (string.IsNullOrWhiteSpace(ianaTimeZoneName))
{
- if (TryRailsToIana(railsTimeZoneName, out string ianaTimeZoneName))
- return ianaTimeZoneName;
+ railsTimeZoneNames = Array.Empty();
+ return false;
+ }
- throw new InvalidTimeZoneException($"\"{railsTimeZoneName}\" was not recognized as a valid Rails time zone name.");
+ // in the case of an Etc/GMT+/-n zone, use the Rails fixed-offset zone. For example, `Etc/GMT-6` -> `+06:00` or `Etc/GMT+3` -> `-03:00`
+ if (ianaTimeZoneName.StartsWith("Etc/GMT", StringComparison.OrdinalIgnoreCase))
+ {
+ var offsetPart = ianaTimeZoneName[7..];
+ if (offsetPart.Length > 2)
+ {
+ var sign = offsetPart[0];
+ if ((sign == '+' || sign == '-') && int.TryParse(offsetPart[1..], out var hours) && hours is >= 0 and <= 14)
+ {
+ var offsetString = $"{(sign == '+' ? '-' : '+')}{hours:00}:00"; // note the inverted sign
+ railsTimeZoneNames = [offsetString];
+ return true;
+ }
+ }
}
- ///
- /// Attempts to convert a Rails time zone name to an equivalent IANA time zone name.
- ///
- /// The Rails time zone name to convert.
- /// An IANA time zone name.
- /// true if successful, false otherwise.
- public static bool TryRailsToIana(string railsTimeZoneName, out string ianaTimeZoneName)
+ // try directly first
+ if (InverseRailsMap.TryGetValue(ianaTimeZoneName, out railsTimeZoneNames!))
{
- return RailsMap.TryGetValue(railsTimeZoneName, out ianaTimeZoneName);
+ return true;
}
- ///
- /// Converts a Rails time zone name to an equivalent Windows time zone ID.
- ///
- /// The Rails time zone name to convert.
- /// A Windows time zone ID.
- /// Thrown if the input string was not recognized or has no equivalent Windows zone.
- public static string RailsToWindows(string railsTimeZoneName)
+ // try again with the golden zone
+ if (TryIanaToWindows(ianaTimeZoneName, out var windowsTimeZoneId) &&
+ TryWindowsToIana(windowsTimeZoneId, out var ianaGoldenZone) &&
+ InverseRailsMap.TryGetValue(ianaGoldenZone, out railsTimeZoneNames!))
{
- if (TryRailsToWindows(railsTimeZoneName, out string windowsTimeZoneId))
- return windowsTimeZoneId;
+ return true;
+ }
- throw new InvalidTimeZoneException($"\"{railsTimeZoneName}\" was not recognized as a valid Rails time zone name.");
+ // If it's a valid IANA zone, then just return it since Rails will accept it as-is.
+ if (KnownIanaTimeZoneNames.Contains(ianaTimeZoneName))
+ {
+ railsTimeZoneNames = [ianaTimeZoneName];
+ return true;
}
- ///
- /// Attempts to convert a Rails time zone name to an equivalent Windows time zone ID.
- ///
- /// The Rails time zone name to convert.
- /// A Windows time zone ID.
- /// true if successful, false otherwise.
- public static bool TryRailsToWindows(string railsTimeZoneName, out string windowsTimeZoneId)
+ // not found
+ railsTimeZoneNames = Array.Empty();
+ return false;
+ }
+
+ ///
+ /// Converts a Rails time zone name to an equivalent IANA time zone name.
+ ///
+ /// The Rails time zone name to convert.
+ /// An IANA time zone name.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent IANA
+ /// zone.
+ ///
+ public static string RailsToIana(string railsTimeZoneName)
+ {
+ if (TryRailsToIana(railsTimeZoneName, out var ianaTimeZoneName))
{
- if (TryRailsToIana(railsTimeZoneName, out string ianaTimeZoneName) &&
- TryIanaToWindows(ianaTimeZoneName, out windowsTimeZoneId))
- return true;
+ return ianaTimeZoneName;
+ }
- windowsTimeZoneId = null;
+ throw new InvalidTimeZoneException(
+ $"\"{railsTimeZoneName}\" was not recognized as a valid Rails time zone name.");
+ }
+
+ ///
+ /// Attempts to convert a Rails time zone name to an equivalent IANA time zone name.
+ ///
+ /// The Rails time zone name to convert.
+ /// An IANA time zone name.
+ /// true if successful, false otherwise.
+ public static bool TryRailsToIana(string railsTimeZoneName, [MaybeNullWhen(false)] out string ianaTimeZoneName)
+ {
+ if (string.IsNullOrWhiteSpace(railsTimeZoneName))
+ {
+ ianaTimeZoneName = null;
return false;
}
- ///
- /// Converts a Windows time zone ID to one ore more equivalent Rails time zone names.
- ///
- /// The Windows time zone ID to convert.
- ///
- /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
- /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
- ///
- /// One or more equivalent Rails time zone names.
- /// Thrown if the input string was not recognized or has no equivalent Rails zone.
- public static IList WindowsToRails(string windowsTimeZoneId, string territoryCode = "001")
- {
- if (TryWindowsToRails(windowsTimeZoneId, territoryCode, out IList railsTimeZoneNames))
- return railsTimeZoneNames;
+ return RailsMap.TryGetValue(railsTimeZoneName, out ianaTimeZoneName);
+ }
- throw new InvalidTimeZoneException($"\"{windowsTimeZoneId}\" was not recognized as a valid Windows time zone ID, or has no equivalent Rails time zone.");
+ ///
+ /// Converts a Rails time zone name to an equivalent Windows time zone ID.
+ ///
+ /// The Rails time zone name to convert.
+ /// A Windows time zone ID.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent Windows
+ /// zone.
+ ///
+ public static string RailsToWindows(string railsTimeZoneName)
+ {
+ if (TryRailsToWindows(railsTimeZoneName, out var windowsTimeZoneId))
+ {
+ return windowsTimeZoneId;
}
- ///
- /// Attempts to convert a Windows time zone ID to one ore more equivalent Rails time zone names.
- /// Uses the "golden zone" - the one that is the most prevalent.
- ///
- /// The Windows time zone ID to convert.
- /// One or more equivalent Rails time zone names.
- /// true if successful, false otherwise.
- public static bool TryWindowsToRails(string windowsTimeZoneId, out IList railsTimeZoneNames)
+ throw new InvalidTimeZoneException(
+ $"\"{railsTimeZoneName}\" was not recognized as a valid Rails time zone name.");
+ }
+
+ ///
+ /// Attempts to convert a Rails time zone name to an equivalent Windows time zone ID.
+ ///
+ /// The Rails time zone name to convert.
+ /// A Windows time zone ID.
+ /// true if successful, false otherwise.
+ public static bool TryRailsToWindows(string railsTimeZoneName, [MaybeNullWhen(false)] out string windowsTimeZoneId)
+ {
+ if (TryRailsToIana(railsTimeZoneName, out var ianaTimeZoneName) &&
+ TryIanaToWindows(ianaTimeZoneName, out windowsTimeZoneId))
{
- return TryWindowsToRails(windowsTimeZoneId, "001", out railsTimeZoneNames);
+ return true;
}
- ///
- /// Attempts to convert a Windows time zone ID to one ore more equivalent Rails time zone names.
- ///
- /// The Windows time zone ID to convert.
- ///
- /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
- /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
- ///
- /// One or more equivalent Rails time zone names.
- /// true if successful, false otherwise.
- public static bool TryWindowsToRails(string windowsTimeZoneId, string territoryCode, out IList railsTimeZoneNames)
+ windowsTimeZoneId = null!;
+ return false;
+ }
+
+ ///
+ /// Converts a Windows time zone ID to one ore more equivalent Rails time zone names.
+ ///
+ /// The Windows time zone ID to convert.
+ ///
+ /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
+ /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
+ ///
+ /// One or more equivalent Rails time zone names.
+ ///
+ /// Thrown if the input string was not recognized or has no equivalent Rails
+ /// zone.
+ ///
+ public static IList WindowsToRails(string windowsTimeZoneId, string territoryCode = "001")
+ {
+ if (TryWindowsToRails(windowsTimeZoneId, territoryCode, out var railsTimeZoneNames))
{
- if (TryWindowsToIana(windowsTimeZoneId, territoryCode, out string ianaTimeZoneName) &&
- TryIanaToRails(ianaTimeZoneName, out railsTimeZoneNames))
- return true;
+ return railsTimeZoneNames;
+ }
- railsTimeZoneNames = new string[0];
- return false;
+ throw new InvalidTimeZoneException(
+ $"\"{windowsTimeZoneId}\" was not recognized as a valid Windows time zone ID, or has no equivalent Rails time zone.");
+ }
+
+ ///
+ /// Attempts to convert a Windows time zone ID to one ore more equivalent Rails time zone names.
+ /// Uses the "golden zone" - the one that is the most prevalent.
+ ///
+ /// The Windows time zone ID to convert.
+ /// One or more equivalent Rails time zone names.
+ /// true if successful, false otherwise.
+ public static bool TryWindowsToRails(string windowsTimeZoneId, out IList railsTimeZoneNames)
+ {
+ return TryWindowsToRails(windowsTimeZoneId, "001", out railsTimeZoneNames);
+ }
+
+ ///
+ /// Attempts to convert a Windows time zone ID to one ore more equivalent Rails time zone names.
+ ///
+ /// The Windows time zone ID to convert.
+ ///
+ /// An optional two-letter ISO Country/Region code, used to get a a specific mapping.
+ /// Defaults to "001" if not specified, which means to get the "golden zone" - the one that is most prevalent.
+ ///
+ /// One or more equivalent Rails time zone names.
+ /// true if successful, false otherwise.
+ public static bool TryWindowsToRails(string windowsTimeZoneId, string territoryCode,
+ out IList railsTimeZoneNames)
+ {
+ // edge case "Dateline Standard Time" -> "International Date Line West"
+ if (string.Equals(windowsTimeZoneId, "Dateline Standard Time", StringComparison.OrdinalIgnoreCase))
+ {
+ railsTimeZoneNames = ["International Date Line West"];
+ return true;
}
- private static Dictionary GetSystemTimeZones()
+ if (TryWindowsToIana(windowsTimeZoneId, territoryCode, out var ianaTimeZoneName) &&
+ TryIanaToRails(ianaTimeZoneName, out railsTimeZoneNames))
{
- IEnumerable systemTimeZones;
-#if NETFRAMEWORK
- systemTimeZones = TimeZoneInfo.GetSystemTimeZones();
-#else
-#endif
-
-#if NETSTANDARD
- if (IsWindows)
- systemTimeZones = TimeZoneInfo.GetSystemTimeZones();
-
- systemTimeZones = GetSystemTimeZonesLinux();
-#else
- systemTimeZones = TimeZoneInfo.GetSystemTimeZones();
-#endif
- return systemTimeZones.ToDictionary(x => x.Id, x => x, StringComparer.OrdinalIgnoreCase);
+ return true;
}
-#if NETSTANDARD
- private static IEnumerable GetSystemTimeZonesLinux()
+ railsTimeZoneNames = Array.Empty();
+ return false;
+ }
+
+ private static Dictionary GetSystemTimeZones()
+ {
+ // Clear the TZI cache to ensure we have as pristine data as possible
+ TimeZoneInfo.ClearCachedData();
+
+ // Get the system time zones, grouped to remove duplicates with casing (though this should be very rare since we cleared cache)
+ var zones = TimeZoneInfo.GetSystemTimeZones()
+ .GroupBy(x => x.Id, StringComparer.OrdinalIgnoreCase)
+ .ToDictionary(x => x.Key, x => x.First(), StringComparer.OrdinalIgnoreCase);
+
+ if (IsWindows)
{
- // Don't trust TimeZoneInfo.GetSystemTimeZones on Non-Windows
- // Because it doesn't return any links, or any Etc zones
+ return zones;
+ }
- foreach (string name in KnownIanaTimeZoneNames)
+ // On non-Windows systems, expand to include any known IANA time zone names that weren't returned by the
+ // GetSystemTimeZones call. Specifically, links and Etc zones.
+ foreach (var name in KnownIanaTimeZoneNames)
+ {
+ if (zones.ContainsKey(name))
{
- TimeZoneInfo tzi = null;
-
- try
- {
- tzi = TimeZoneInfo.FindSystemTimeZoneById(name);
- }
- catch
- {
- // ignored
- }
+ continue;
+ }
- if (tzi != null)
- yield return tzi;
+ try
+ {
+ var tzi = TimeZoneInfo.FindSystemTimeZoneById(name);
+ zones.Add(tzi.Id, tzi);
+ }
+ catch
+ {
+ // ignored
}
}
-#endif
+
+ return zones;
}
}
diff --git a/src/TimeZoneConverter/TimeZoneConverter.csproj b/src/TimeZoneConverter/TimeZoneConverter.csproj
index 140ecbf..c5a7366 100644
--- a/src/TimeZoneConverter/TimeZoneConverter.csproj
+++ b/src/TimeZoneConverter/TimeZoneConverter.csproj
@@ -1,24 +1,29 @@
-
+
+ netstandard2.0;net462;net8.0;net9.0
Lightweight library to convert quickly between IANA, Windows, and Rails time zone names.
Matt Johnson-Pint
- netstandard2.0;net461
TimeZoneConverter
timezone;time;zone;time zone;iana;tzdb;olson;timezoneinfo,rails
https://github.com/mattjohnsonpint/TimeZoneConverter
MIT
- 4.0.0
-
-
-
- true
- true
- mj1856_oss.snk
+ README.md
+ 7.2.0
+
+
+
+
+
+
+
+
+
+
diff --git a/src/TimeZoneConverter/mj1856_oss.snk b/src/TimeZoneConverter/mj1856_oss.snk
deleted file mode 100644
index 7915c2c..0000000
Binary files a/src/TimeZoneConverter/mj1856_oss.snk and /dev/null differ
diff --git a/test/Directory.Build.props b/test/Directory.Build.props
new file mode 100644
index 0000000..2ee1918
--- /dev/null
+++ b/test/Directory.Build.props
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/TimeZoneConverter.Benchmarks/DataLoaderBenchmark.cs b/test/TimeZoneConverter.Benchmarks/DataLoaderBenchmark.cs
new file mode 100644
index 0000000..4540eb9
--- /dev/null
+++ b/test/TimeZoneConverter.Benchmarks/DataLoaderBenchmark.cs
@@ -0,0 +1,31 @@
+using BenchmarkDotNet.Attributes;
+
+namespace TimeZoneConverter.Benchmarks;
+
+[MemoryDiagnoser]
+public class DataLoaderBenchmark
+{
+ private static readonly Dictionary IanaMap = [];
+ private static readonly Dictionary WindowsMap = [];
+ private static readonly Dictionary RailsMap = [];
+ private static readonly Dictionary> InverseRailsMap = [];
+ private static readonly Dictionary Links = [];
+ private static readonly Dictionary> IanaTerritoryZones = [];
+
+ [IterationSetup]
+ public void IterationSetup()
+ {
+ IanaMap.Clear();
+ WindowsMap.Clear();
+ RailsMap.Clear();
+ InverseRailsMap.Clear();
+ Links.Clear();
+ IanaTerritoryZones.Clear();
+ }
+
+ [Benchmark]
+ public void Load()
+ {
+ DataLoader.Populate(IanaMap, WindowsMap, RailsMap, InverseRailsMap, Links, IanaTerritoryZones);
+ }
+}
diff --git a/test/TimeZoneConverter.Benchmarks/Directory.Build.props b/test/TimeZoneConverter.Benchmarks/Directory.Build.props
new file mode 100644
index 0000000..59b389e
--- /dev/null
+++ b/test/TimeZoneConverter.Benchmarks/Directory.Build.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/test/TimeZoneConverter.Benchmarks/Program.cs b/test/TimeZoneConverter.Benchmarks/Program.cs
new file mode 100644
index 0000000..3af3c91
--- /dev/null
+++ b/test/TimeZoneConverter.Benchmarks/Program.cs
@@ -0,0 +1,11 @@
+using BenchmarkDotNet.Running;
+
+namespace TimeZoneConverter.Benchmarks;
+
+public static class Program
+{
+ public static void Main(string[]? args)
+ {
+ BenchmarkSwitcher.FromAssembly(typeof(DataLoaderBenchmark).Assembly).Run(args);
+ }
+}
diff --git a/test/TimeZoneConverter.Benchmarks/TimeZoneConverter.Benchmarks.csproj b/test/TimeZoneConverter.Benchmarks/TimeZoneConverter.Benchmarks.csproj
new file mode 100644
index 0000000..9e3b0f3
--- /dev/null
+++ b/test/TimeZoneConverter.Benchmarks/TimeZoneConverter.Benchmarks.csproj
@@ -0,0 +1,18 @@
+
+
+
+ net8.0
+ $(MSBuildThisFileDirectory)..\..\.assets\mattjohnsonpint.snk
+ true
+ exe
+
+
+
+
+
+
+
+
+
+
+
diff --git a/test/TimeZoneConverter.Posix.Tests/PosixTests.cs b/test/TimeZoneConverter.Posix.Tests/PosixTests.cs
index c5312a1..b98e7c7 100644
--- a/test/TimeZoneConverter.Posix.Tests/PosixTests.cs
+++ b/test/TimeZoneConverter.Posix.Tests/PosixTests.cs
@@ -1,30 +1,27 @@
-using Xunit;
+namespace TimeZoneConverter.Posix.Tests;
-namespace TimeZoneConverter.Posix.Tests
+public class PosixTests
{
- public class PosixTests
+ [Theory]
+ [InlineData("America/New_York", "EST5EDT,M3.2.0,M11.1.0")]
+ [InlineData("Australia/Sydney", "AEST-10AEDT,M10.1.0,M4.1.0/3")]
+ [InlineData("America/Havana", "CST5CDT,M3.2.0/0,M11.1.0/1")]
+ [InlineData("Europe/London", "GMT0BST,M3.5.0/1,M10.5.0")]
+ [InlineData("Australia/Lord_Howe", "<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")]
+ [InlineData("Pacific/Chatham", "<+1245>-12:45<+1345>,M9.4.0/2:45,M4.1.0/3:45")]
+ [InlineData("Europe/Astrakhan", "<+04>-4")]
+ public void Test_Posix_From_IANA(string input, string expected)
{
- [Theory]
- [InlineData("America/New_York", "EST5EDT,M3.2.0,M11.1.0")]
- [InlineData("Australia/Sydney", "AEST-10AEDT,M10.1.0,M4.1.0/3")]
- [InlineData("America/Havana", "CST5CDT,M3.2.0/0,M11.1.0/1")]
- [InlineData("Europe/London", "GMT0BST,M3.5.0/1,M10.5.0")]
- [InlineData("Australia/Lord_Howe", "<+1030>-10:30<+11>-11,M10.1.0,M4.1.0")]
- [InlineData("Pacific/Chatham", "<+1245>-12:45<+1345>,M9.4.0/2:45,M4.1.0/3:45")]
- [InlineData("Europe/Astrakhan", "<+04>-4")]
- public void Test_Posix_From_IANA(string input, string expected)
- {
- string actual = PosixTimeZone.FromIanaTimeZoneName(input);
- Assert.Equal(expected, actual);
- }
+ var actual = PosixTimeZone.FromIanaTimeZoneName(input);
+ Assert.Equal(expected, actual);
+ }
- [Theory]
- [InlineData("Europe/London", 2018, "GMT0BST,M3.5.0/1,M10.5.0")]
- [InlineData("Europe/London", 2019, "GMT0BST,M3.5.0/1,M10.5.0")]
- public void Test_Posix_From_IANA_At_End_Of_Month(string input, int year, string expected)
- {
- string actual = PosixTimeZone.FromIanaTimeZoneName(input, year);
- Assert.Equal(expected, actual);
- }
+ [Theory]
+ [InlineData("Europe/London", 2018, "GMT0BST,M3.5.0/1,M10.5.0")]
+ [InlineData("Europe/London", 2019, "GMT0BST,M3.5.0/1,M10.5.0")]
+ public void Test_Posix_From_IANA_At_End_Of_Month(string input, int year, string expected)
+ {
+ var actual = PosixTimeZone.FromIanaTimeZoneName(input, year);
+ Assert.Equal(expected, actual);
}
}
diff --git a/test/TimeZoneConverter.Posix.Tests/TimeZoneConverter.Posix.Tests.csproj b/test/TimeZoneConverter.Posix.Tests/TimeZoneConverter.Posix.Tests.csproj
index a727e6e..675f9eb 100644
--- a/test/TimeZoneConverter.Posix.Tests/TimeZoneConverter.Posix.Tests.csproj
+++ b/test/TimeZoneConverter.Posix.Tests/TimeZoneConverter.Posix.Tests.csproj
@@ -1,20 +1,12 @@
-
+
- net6.0
+ net8.0;net9.0
+ $(TargetFrameworks);net48
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.IANA_To_Windows.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.IANA_To_Windows.verified.txt
new file mode 100644
index 0000000..e1ddf39
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.IANA_To_Windows.verified.txt
@@ -0,0 +1,599 @@
+{
+ Africa/Abidjan: Greenwich Standard Time,
+ Africa/Accra: Greenwich Standard Time,
+ Africa/Addis_Ababa: E. Africa Standard Time,
+ Africa/Algiers: W. Central Africa Standard Time,
+ Africa/Asmara: E. Africa Standard Time,
+ Africa/Asmera: E. Africa Standard Time,
+ Africa/Bamako: Greenwich Standard Time,
+ Africa/Bangui: W. Central Africa Standard Time,
+ Africa/Banjul: Greenwich Standard Time,
+ Africa/Bissau: Greenwich Standard Time,
+ Africa/Blantyre: South Africa Standard Time,
+ Africa/Brazzaville: W. Central Africa Standard Time,
+ Africa/Bujumbura: South Africa Standard Time,
+ Africa/Cairo: Egypt Standard Time,
+ Africa/Casablanca: Morocco Standard Time,
+ Africa/Ceuta: Romance Standard Time,
+ Africa/Conakry: Greenwich Standard Time,
+ Africa/Dakar: Greenwich Standard Time,
+ Africa/Dar_es_Salaam: E. Africa Standard Time,
+ Africa/Djibouti: E. Africa Standard Time,
+ Africa/Douala: W. Central Africa Standard Time,
+ Africa/El_Aaiun: Morocco Standard Time,
+ Africa/Freetown: Greenwich Standard Time,
+ Africa/Gaborone: South Africa Standard Time,
+ Africa/Harare: South Africa Standard Time,
+ Africa/Johannesburg: South Africa Standard Time,
+ Africa/Juba: South Sudan Standard Time,
+ Africa/Kampala: E. Africa Standard Time,
+ Africa/Khartoum: Sudan Standard Time,
+ Africa/Kigali: South Africa Standard Time,
+ Africa/Kinshasa: W. Central Africa Standard Time,
+ Africa/Lagos: W. Central Africa Standard Time,
+ Africa/Libreville: W. Central Africa Standard Time,
+ Africa/Lome: Greenwich Standard Time,
+ Africa/Luanda: W. Central Africa Standard Time,
+ Africa/Lubumbashi: South Africa Standard Time,
+ Africa/Lusaka: South Africa Standard Time,
+ Africa/Malabo: W. Central Africa Standard Time,
+ Africa/Maputo: South Africa Standard Time,
+ Africa/Maseru: South Africa Standard Time,
+ Africa/Mbabane: South Africa Standard Time,
+ Africa/Mogadishu: E. Africa Standard Time,
+ Africa/Monrovia: Greenwich Standard Time,
+ Africa/Nairobi: E. Africa Standard Time,
+ Africa/Ndjamena: W. Central Africa Standard Time,
+ Africa/Niamey: W. Central Africa Standard Time,
+ Africa/Nouakchott: Greenwich Standard Time,
+ Africa/Ouagadougou: Greenwich Standard Time,
+ Africa/Porto-Novo: W. Central Africa Standard Time,
+ Africa/Sao_Tome: Sao Tome Standard Time,
+ Africa/Timbuktu: Greenwich Standard Time,
+ Africa/Tripoli: Libya Standard Time,
+ Africa/Tunis: W. Central Africa Standard Time,
+ Africa/Windhoek: Namibia Standard Time,
+ America/Adak: Aleutian Standard Time,
+ America/Anchorage: Alaskan Standard Time,
+ America/Anguilla: SA Western Standard Time,
+ America/Antigua: SA Western Standard Time,
+ America/Araguaina: Tocantins Standard Time,
+ America/Argentina/Buenos_Aires: Argentina Standard Time,
+ America/Argentina/Catamarca: Argentina Standard Time,
+ America/Argentina/ComodRivadavia: Argentina Standard Time,
+ America/Argentina/Cordoba: Argentina Standard Time,
+ America/Argentina/Jujuy: Argentina Standard Time,
+ America/Argentina/La_Rioja: Argentina Standard Time,
+ America/Argentina/Mendoza: Argentina Standard Time,
+ America/Argentina/Rio_Gallegos: Argentina Standard Time,
+ America/Argentina/Salta: Argentina Standard Time,
+ America/Argentina/San_Juan: Argentina Standard Time,
+ America/Argentina/San_Luis: Argentina Standard Time,
+ America/Argentina/Tucuman: Argentina Standard Time,
+ America/Argentina/Ushuaia: Argentina Standard Time,
+ America/Aruba: SA Western Standard Time,
+ America/Asuncion: Paraguay Standard Time,
+ America/Atikokan: SA Pacific Standard Time,
+ America/Atka: Aleutian Standard Time,
+ America/Bahia: Bahia Standard Time,
+ America/Bahia_Banderas: Central Standard Time (Mexico),
+ America/Barbados: SA Western Standard Time,
+ America/Belem: SA Eastern Standard Time,
+ America/Belize: Central America Standard Time,
+ America/Blanc-Sablon: SA Western Standard Time,
+ America/Boa_Vista: SA Western Standard Time,
+ America/Bogota: SA Pacific Standard Time,
+ America/Boise: Mountain Standard Time,
+ America/Buenos_Aires: Argentina Standard Time,
+ America/Cambridge_Bay: Mountain Standard Time,
+ America/Campo_Grande: Central Brazilian Standard Time,
+ America/Cancun: Eastern Standard Time (Mexico),
+ America/Caracas: Venezuela Standard Time,
+ America/Catamarca: Argentina Standard Time,
+ America/Cayenne: SA Eastern Standard Time,
+ America/Cayman: SA Pacific Standard Time,
+ America/Chicago: Central Standard Time,
+ America/Chihuahua: Central Standard Time (Mexico),
+ America/Ciudad_Juarez: Mountain Standard Time,
+ America/Coral_Harbour: SA Pacific Standard Time,
+ America/Cordoba: Argentina Standard Time,
+ America/Costa_Rica: Central America Standard Time,
+ America/Coyhaique: Magallanes Standard Time,
+ America/Creston: US Mountain Standard Time,
+ America/Cuiaba: Central Brazilian Standard Time,
+ America/Curacao: SA Western Standard Time,
+ America/Danmarkshavn: Greenwich Standard Time,
+ America/Dawson: Yukon Standard Time,
+ America/Dawson_Creek: US Mountain Standard Time,
+ America/Denver: Mountain Standard Time,
+ America/Detroit: Eastern Standard Time,
+ America/Dominica: SA Western Standard Time,
+ America/Edmonton: Mountain Standard Time,
+ America/Eirunepe: SA Pacific Standard Time,
+ America/El_Salvador: Central America Standard Time,
+ America/Ensenada: Pacific Standard Time (Mexico),
+ America/Fort_Nelson: US Mountain Standard Time,
+ America/Fort_Wayne: US Eastern Standard Time,
+ America/Fortaleza: SA Eastern Standard Time,
+ America/Glace_Bay: Atlantic Standard Time,
+ America/Godthab: Greenland Standard Time,
+ America/Goose_Bay: Atlantic Standard Time,
+ America/Grand_Turk: Turks And Caicos Standard Time,
+ America/Grenada: SA Western Standard Time,
+ America/Guadeloupe: SA Western Standard Time,
+ America/Guatemala: Central America Standard Time,
+ America/Guayaquil: SA Pacific Standard Time,
+ America/Guyana: SA Western Standard Time,
+ America/Halifax: Atlantic Standard Time,
+ America/Havana: Cuba Standard Time,
+ America/Hermosillo: US Mountain Standard Time,
+ America/Indiana/Indianapolis: US Eastern Standard Time,
+ America/Indiana/Knox: Central Standard Time,
+ America/Indiana/Marengo: US Eastern Standard Time,
+ America/Indiana/Petersburg: Eastern Standard Time,
+ America/Indiana/Tell_City: Central Standard Time,
+ America/Indiana/Vevay: US Eastern Standard Time,
+ America/Indiana/Vincennes: Eastern Standard Time,
+ America/Indiana/Winamac: Eastern Standard Time,
+ America/Indianapolis: US Eastern Standard Time,
+ America/Inuvik: Mountain Standard Time,
+ America/Iqaluit: Eastern Standard Time,
+ America/Jamaica: SA Pacific Standard Time,
+ America/Jujuy: Argentina Standard Time,
+ America/Juneau: Alaskan Standard Time,
+ America/Kentucky/Louisville: Eastern Standard Time,
+ America/Kentucky/Monticello: Eastern Standard Time,
+ America/Knox_IN: Central Standard Time,
+ America/Kralendijk: SA Western Standard Time,
+ America/La_Paz: SA Western Standard Time,
+ America/Lima: SA Pacific Standard Time,
+ America/Los_Angeles: Pacific Standard Time,
+ America/Louisville: Eastern Standard Time,
+ America/Lower_Princes: SA Western Standard Time,
+ America/Maceio: SA Eastern Standard Time,
+ America/Managua: Central America Standard Time,
+ America/Manaus: SA Western Standard Time,
+ America/Marigot: SA Western Standard Time,
+ America/Martinique: SA Western Standard Time,
+ America/Matamoros: Central Standard Time,
+ America/Mazatlan: Mountain Standard Time (Mexico),
+ America/Mendoza: Argentina Standard Time,
+ America/Menominee: Central Standard Time,
+ America/Merida: Central Standard Time (Mexico),
+ America/Metlakatla: Alaskan Standard Time,
+ America/Mexico_City: Central Standard Time (Mexico),
+ America/Miquelon: Saint Pierre Standard Time,
+ America/Moncton: Atlantic Standard Time,
+ America/Monterrey: Central Standard Time (Mexico),
+ America/Montevideo: Montevideo Standard Time,
+ America/Montreal: Eastern Standard Time,
+ America/Montserrat: SA Western Standard Time,
+ America/Nassau: Eastern Standard Time,
+ America/New_York: Eastern Standard Time,
+ America/Nipigon: Eastern Standard Time,
+ America/Nome: Alaskan Standard Time,
+ America/Noronha: UTC-02,
+ America/North_Dakota/Beulah: Central Standard Time,
+ America/North_Dakota/Center: Central Standard Time,
+ America/North_Dakota/New_Salem: Central Standard Time,
+ America/Nuuk: Greenland Standard Time,
+ America/Ojinaga: Central Standard Time,
+ America/Panama: SA Pacific Standard Time,
+ America/Pangnirtung: Eastern Standard Time,
+ America/Paramaribo: SA Eastern Standard Time,
+ America/Phoenix: US Mountain Standard Time,
+ America/Port-au-Prince: Haiti Standard Time,
+ America/Port_of_Spain: SA Western Standard Time,
+ America/Porto_Acre: SA Pacific Standard Time,
+ America/Porto_Velho: SA Western Standard Time,
+ America/Puerto_Rico: SA Western Standard Time,
+ America/Punta_Arenas: Magallanes Standard Time,
+ America/Rainy_River: Central Standard Time,
+ America/Rankin_Inlet: Central Standard Time,
+ America/Recife: SA Eastern Standard Time,
+ America/Regina: Canada Central Standard Time,
+ America/Resolute: Central Standard Time,
+ America/Rio_Branco: SA Pacific Standard Time,
+ America/Rosario: Argentina Standard Time,
+ America/Santa_Isabel: Pacific Standard Time (Mexico),
+ America/Santarem: SA Eastern Standard Time,
+ America/Santiago: Pacific SA Standard Time,
+ America/Santo_Domingo: SA Western Standard Time,
+ America/Sao_Paulo: E. South America Standard Time,
+ America/Scoresbysund: Azores Standard Time,
+ America/Shiprock: Mountain Standard Time,
+ America/Sitka: Alaskan Standard Time,
+ America/St_Barthelemy: SA Western Standard Time,
+ America/St_Johns: Newfoundland Standard Time,
+ America/St_Kitts: SA Western Standard Time,
+ America/St_Lucia: SA Western Standard Time,
+ America/St_Thomas: SA Western Standard Time,
+ America/St_Vincent: SA Western Standard Time,
+ America/Swift_Current: Canada Central Standard Time,
+ America/Tegucigalpa: Central America Standard Time,
+ America/Thule: Atlantic Standard Time,
+ America/Thunder_Bay: Eastern Standard Time,
+ America/Tijuana: Pacific Standard Time (Mexico),
+ America/Toronto: Eastern Standard Time,
+ America/Tortola: SA Western Standard Time,
+ America/Vancouver: Pacific Standard Time,
+ America/Virgin: SA Western Standard Time,
+ America/Whitehorse: Yukon Standard Time,
+ America/Winnipeg: Central Standard Time,
+ America/Yakutat: Alaskan Standard Time,
+ America/Yellowknife: Mountain Standard Time,
+ Antarctica/Casey: Central Pacific Standard Time,
+ Antarctica/Davis: SE Asia Standard Time,
+ Antarctica/DumontDUrville: West Pacific Standard Time,
+ Antarctica/Macquarie: Tasmania Standard Time,
+ Antarctica/Mawson: West Asia Standard Time,
+ Antarctica/McMurdo: New Zealand Standard Time,
+ Antarctica/Palmer: SA Eastern Standard Time,
+ Antarctica/Rothera: SA Eastern Standard Time,
+ Antarctica/South_Pole: New Zealand Standard Time,
+ Antarctica/Syowa: E. Africa Standard Time,
+ Antarctica/Troll: null,
+ Antarctica/Vostok: Central Asia Standard Time,
+ Arctic/Longyearbyen: W. Europe Standard Time,
+ Asia/Aden: Arab Standard Time,
+ Asia/Almaty: West Asia Standard Time,
+ Asia/Amman: Jordan Standard Time,
+ Asia/Anadyr: Russia Time Zone 11,
+ Asia/Aqtau: West Asia Standard Time,
+ Asia/Aqtobe: West Asia Standard Time,
+ Asia/Ashgabat: West Asia Standard Time,
+ Asia/Ashkhabad: West Asia Standard Time,
+ Asia/Atyrau: West Asia Standard Time,
+ Asia/Baghdad: Arabic Standard Time,
+ Asia/Bahrain: Arab Standard Time,
+ Asia/Baku: Azerbaijan Standard Time,
+ Asia/Bangkok: SE Asia Standard Time,
+ Asia/Barnaul: Altai Standard Time,
+ Asia/Beirut: Middle East Standard Time,
+ Asia/Bishkek: Central Asia Standard Time,
+ Asia/Brunei: Singapore Standard Time,
+ Asia/Calcutta: India Standard Time,
+ Asia/Chita: Transbaikal Standard Time,
+ Asia/Choibalsan: Ulaanbaatar Standard Time,
+ Asia/Chongqing: China Standard Time,
+ Asia/Chungking: China Standard Time,
+ Asia/Colombo: Sri Lanka Standard Time,
+ Asia/Dacca: Bangladesh Standard Time,
+ Asia/Damascus: Syria Standard Time,
+ Asia/Dhaka: Bangladesh Standard Time,
+ Asia/Dili: Tokyo Standard Time,
+ Asia/Dubai: Arabian Standard Time,
+ Asia/Dushanbe: West Asia Standard Time,
+ Asia/Famagusta: GTB Standard Time,
+ Asia/Gaza: West Bank Standard Time,
+ Asia/Harbin: China Standard Time,
+ Asia/Hebron: West Bank Standard Time,
+ Asia/Ho_Chi_Minh: SE Asia Standard Time,
+ Asia/Hong_Kong: China Standard Time,
+ Asia/Hovd: W. Mongolia Standard Time,
+ Asia/Irkutsk: North Asia East Standard Time,
+ Asia/Istanbul: Turkey Standard Time,
+ Asia/Jakarta: SE Asia Standard Time,
+ Asia/Jayapura: Tokyo Standard Time,
+ Asia/Jerusalem: Israel Standard Time,
+ Asia/Kabul: Afghanistan Standard Time,
+ Asia/Kamchatka: Russia Time Zone 11,
+ Asia/Karachi: Pakistan Standard Time,
+ Asia/Kashgar: Central Asia Standard Time,
+ Asia/Kathmandu: Nepal Standard Time,
+ Asia/Katmandu: Nepal Standard Time,
+ Asia/Khandyga: Yakutsk Standard Time,
+ Asia/Kolkata: India Standard Time,
+ Asia/Krasnoyarsk: North Asia Standard Time,
+ Asia/Kuala_Lumpur: Singapore Standard Time,
+ Asia/Kuching: Singapore Standard Time,
+ Asia/Kuwait: Arab Standard Time,
+ Asia/Macao: China Standard Time,
+ Asia/Macau: China Standard Time,
+ Asia/Magadan: Magadan Standard Time,
+ Asia/Makassar: Singapore Standard Time,
+ Asia/Manila: Singapore Standard Time,
+ Asia/Muscat: Arabian Standard Time,
+ Asia/Nicosia: GTB Standard Time,
+ Asia/Novokuznetsk: North Asia Standard Time,
+ Asia/Novosibirsk: N. Central Asia Standard Time,
+ Asia/Omsk: Omsk Standard Time,
+ Asia/Oral: West Asia Standard Time,
+ Asia/Phnom_Penh: SE Asia Standard Time,
+ Asia/Pontianak: SE Asia Standard Time,
+ Asia/Pyongyang: North Korea Standard Time,
+ Asia/Qatar: Arab Standard Time,
+ Asia/Qostanay: West Asia Standard Time,
+ Asia/Qyzylorda: Qyzylorda Standard Time,
+ Asia/Rangoon: Myanmar Standard Time,
+ Asia/Riyadh: Arab Standard Time,
+ Asia/Saigon: SE Asia Standard Time,
+ Asia/Sakhalin: Sakhalin Standard Time,
+ Asia/Samarkand: West Asia Standard Time,
+ Asia/Seoul: Korea Standard Time,
+ Asia/Shanghai: China Standard Time,
+ Asia/Singapore: Singapore Standard Time,
+ Asia/Srednekolymsk: Russia Time Zone 10,
+ Asia/Taipei: Taipei Standard Time,
+ Asia/Tashkent: West Asia Standard Time,
+ Asia/Tbilisi: Georgian Standard Time,
+ Asia/Tehran: Iran Standard Time,
+ Asia/Tel_Aviv: Israel Standard Time,
+ Asia/Thimbu: Bangladesh Standard Time,
+ Asia/Thimphu: Bangladesh Standard Time,
+ Asia/Tokyo: Tokyo Standard Time,
+ Asia/Tomsk: Tomsk Standard Time,
+ Asia/Ujung_Pandang: Singapore Standard Time,
+ Asia/Ulaanbaatar: Ulaanbaatar Standard Time,
+ Asia/Ulan_Bator: Ulaanbaatar Standard Time,
+ Asia/Urumqi: Central Asia Standard Time,
+ Asia/Ust-Nera: Vladivostok Standard Time,
+ Asia/Vientiane: SE Asia Standard Time,
+ Asia/Vladivostok: Vladivostok Standard Time,
+ Asia/Yakutsk: Yakutsk Standard Time,
+ Asia/Yangon: Myanmar Standard Time,
+ Asia/Yekaterinburg: Ekaterinburg Standard Time,
+ Asia/Yerevan: Caucasus Standard Time,
+ Atlantic/Azores: Azores Standard Time,
+ Atlantic/Bermuda: Atlantic Standard Time,
+ Atlantic/Canary: GMT Standard Time,
+ Atlantic/Cape_Verde: Cape Verde Standard Time,
+ Atlantic/Faeroe: GMT Standard Time,
+ Atlantic/Faroe: GMT Standard Time,
+ Atlantic/Jan_Mayen: W. Europe Standard Time,
+ Atlantic/Madeira: GMT Standard Time,
+ Atlantic/Reykjavik: Greenwich Standard Time,
+ Atlantic/South_Georgia: UTC-02,
+ Atlantic/St_Helena: Greenwich Standard Time,
+ Atlantic/Stanley: SA Eastern Standard Time,
+ Australia/ACT: AUS Eastern Standard Time,
+ Australia/Adelaide: Cen. Australia Standard Time,
+ Australia/Brisbane: E. Australia Standard Time,
+ Australia/Broken_Hill: Cen. Australia Standard Time,
+ Australia/Canberra: AUS Eastern Standard Time,
+ Australia/Currie: Tasmania Standard Time,
+ Australia/Darwin: AUS Central Standard Time,
+ Australia/Eucla: Aus Central W. Standard Time,
+ Australia/Hobart: Tasmania Standard Time,
+ Australia/LHI: Lord Howe Standard Time,
+ Australia/Lindeman: E. Australia Standard Time,
+ Australia/Lord_Howe: Lord Howe Standard Time,
+ Australia/Melbourne: AUS Eastern Standard Time,
+ Australia/NSW: AUS Eastern Standard Time,
+ Australia/North: AUS Central Standard Time,
+ Australia/Perth: W. Australia Standard Time,
+ Australia/Queensland: E. Australia Standard Time,
+ Australia/South: Cen. Australia Standard Time,
+ Australia/Sydney: AUS Eastern Standard Time,
+ Australia/Tasmania: Tasmania Standard Time,
+ Australia/Victoria: AUS Eastern Standard Time,
+ Australia/West: W. Australia Standard Time,
+ Australia/Yancowinna: Cen. Australia Standard Time,
+ Brazil/Acre: SA Pacific Standard Time,
+ Brazil/DeNoronha: UTC-02,
+ Brazil/East: E. South America Standard Time,
+ Brazil/West: SA Western Standard Time,
+ CET: Romance Standard Time,
+ CST6CDT: Central Standard Time,
+ Canada/Atlantic: Atlantic Standard Time,
+ Canada/Central: Central Standard Time,
+ Canada/Eastern: Eastern Standard Time,
+ Canada/Mountain: Mountain Standard Time,
+ Canada/Newfoundland: Newfoundland Standard Time,
+ Canada/Pacific: Pacific Standard Time,
+ Canada/Saskatchewan: Canada Central Standard Time,
+ Canada/Yukon: Yukon Standard Time,
+ Chile/Continental: Pacific SA Standard Time,
+ Chile/EasterIsland: Easter Island Standard Time,
+ Cuba: Cuba Standard Time,
+ EET: GTB Standard Time,
+ EST: SA Pacific Standard Time,
+ EST5EDT: Eastern Standard Time,
+ Egypt: Egypt Standard Time,
+ Eire: GMT Standard Time,
+ Etc/GMT: UTC,
+ Etc/GMT+0: UTC,
+ Etc/GMT+1: Cape Verde Standard Time,
+ Etc/GMT+10: Hawaiian Standard Time,
+ Etc/GMT+11: UTC-11,
+ Etc/GMT+12: Dateline Standard Time,
+ Etc/GMT+2: UTC-02,
+ Etc/GMT+3: SA Eastern Standard Time,
+ Etc/GMT+4: SA Western Standard Time,
+ Etc/GMT+5: SA Pacific Standard Time,
+ Etc/GMT+6: Central America Standard Time,
+ Etc/GMT+7: US Mountain Standard Time,
+ Etc/GMT+8: UTC-08,
+ Etc/GMT+9: UTC-09,
+ Etc/GMT-0: UTC,
+ Etc/GMT-1: W. Central Africa Standard Time,
+ Etc/GMT-10: West Pacific Standard Time,
+ Etc/GMT-11: Central Pacific Standard Time,
+ Etc/GMT-12: UTC+12,
+ Etc/GMT-13: UTC+13,
+ Etc/GMT-14: Line Islands Standard Time,
+ Etc/GMT-2: South Africa Standard Time,
+ Etc/GMT-3: E. Africa Standard Time,
+ Etc/GMT-4: Arabian Standard Time,
+ Etc/GMT-5: West Asia Standard Time,
+ Etc/GMT-6: Central Asia Standard Time,
+ Etc/GMT-7: SE Asia Standard Time,
+ Etc/GMT-8: Singapore Standard Time,
+ Etc/GMT-9: Tokyo Standard Time,
+ Etc/GMT0: UTC,
+ Etc/Greenwich: UTC,
+ Etc/UCT: UTC,
+ Etc/UTC: UTC,
+ Etc/Universal: UTC,
+ Etc/Zulu: UTC,
+ Europe/Amsterdam: W. Europe Standard Time,
+ Europe/Andorra: W. Europe Standard Time,
+ Europe/Astrakhan: Astrakhan Standard Time,
+ Europe/Athens: GTB Standard Time,
+ Europe/Belfast: GMT Standard Time,
+ Europe/Belgrade: Central Europe Standard Time,
+ Europe/Berlin: W. Europe Standard Time,
+ Europe/Bratislava: Central Europe Standard Time,
+ Europe/Brussels: Romance Standard Time,
+ Europe/Bucharest: GTB Standard Time,
+ Europe/Budapest: Central Europe Standard Time,
+ Europe/Busingen: W. Europe Standard Time,
+ Europe/Chisinau: E. Europe Standard Time,
+ Europe/Copenhagen: Romance Standard Time,
+ Europe/Dublin: GMT Standard Time,
+ Europe/Gibraltar: W. Europe Standard Time,
+ Europe/Guernsey: GMT Standard Time,
+ Europe/Helsinki: FLE Standard Time,
+ Europe/Isle_of_Man: GMT Standard Time,
+ Europe/Istanbul: Turkey Standard Time,
+ Europe/Jersey: GMT Standard Time,
+ Europe/Kaliningrad: Kaliningrad Standard Time,
+ Europe/Kiev: FLE Standard Time,
+ Europe/Kirov: Russian Standard Time,
+ Europe/Kyiv: FLE Standard Time,
+ Europe/Lisbon: GMT Standard Time,
+ Europe/Ljubljana: Central Europe Standard Time,
+ Europe/London: GMT Standard Time,
+ Europe/Luxembourg: W. Europe Standard Time,
+ Europe/Madrid: Romance Standard Time,
+ Europe/Malta: W. Europe Standard Time,
+ Europe/Mariehamn: FLE Standard Time,
+ Europe/Minsk: Belarus Standard Time,
+ Europe/Monaco: W. Europe Standard Time,
+ Europe/Moscow: Russian Standard Time,
+ Europe/Nicosia: GTB Standard Time,
+ Europe/Oslo: W. Europe Standard Time,
+ Europe/Paris: Romance Standard Time,
+ Europe/Podgorica: Central Europe Standard Time,
+ Europe/Prague: Central Europe Standard Time,
+ Europe/Riga: FLE Standard Time,
+ Europe/Rome: W. Europe Standard Time,
+ Europe/Samara: Russia Time Zone 3,
+ Europe/San_Marino: W. Europe Standard Time,
+ Europe/Sarajevo: Central European Standard Time,
+ Europe/Saratov: Saratov Standard Time,
+ Europe/Simferopol: Russian Standard Time,
+ Europe/Skopje: Central European Standard Time,
+ Europe/Sofia: FLE Standard Time,
+ Europe/Stockholm: W. Europe Standard Time,
+ Europe/Tallinn: FLE Standard Time,
+ Europe/Tirane: Central Europe Standard Time,
+ Europe/Tiraspol: E. Europe Standard Time,
+ Europe/Ulyanovsk: Astrakhan Standard Time,
+ Europe/Uzhgorod: FLE Standard Time,
+ Europe/Vaduz: W. Europe Standard Time,
+ Europe/Vatican: W. Europe Standard Time,
+ Europe/Vienna: W. Europe Standard Time,
+ Europe/Vilnius: FLE Standard Time,
+ Europe/Volgograd: Volgograd Standard Time,
+ Europe/Warsaw: Central European Standard Time,
+ Europe/Zagreb: Central European Standard Time,
+ Europe/Zaporozhye: FLE Standard Time,
+ Europe/Zurich: W. Europe Standard Time,
+ GB: GMT Standard Time,
+ GB-Eire: GMT Standard Time,
+ GMT: UTC,
+ GMT+0: UTC,
+ GMT-0: UTC,
+ GMT0: UTC,
+ Greenwich: UTC,
+ HST: Hawaiian Standard Time,
+ Hongkong: China Standard Time,
+ Iceland: Greenwich Standard Time,
+ Indian/Antananarivo: E. Africa Standard Time,
+ Indian/Chagos: Central Asia Standard Time,
+ Indian/Christmas: SE Asia Standard Time,
+ Indian/Cocos: Myanmar Standard Time,
+ Indian/Comoro: E. Africa Standard Time,
+ Indian/Kerguelen: West Asia Standard Time,
+ Indian/Mahe: Mauritius Standard Time,
+ Indian/Maldives: West Asia Standard Time,
+ Indian/Mauritius: Mauritius Standard Time,
+ Indian/Mayotte: E. Africa Standard Time,
+ Indian/Reunion: Mauritius Standard Time,
+ Iran: Iran Standard Time,
+ Israel: Israel Standard Time,
+ Jamaica: SA Pacific Standard Time,
+ Japan: Tokyo Standard Time,
+ Kwajalein: UTC+12,
+ Libya: Libya Standard Time,
+ MET: Romance Standard Time,
+ MST: US Mountain Standard Time,
+ MST7MDT: Mountain Standard Time,
+ Mexico/BajaNorte: Pacific Standard Time (Mexico),
+ Mexico/BajaSur: Mountain Standard Time (Mexico),
+ Mexico/General: Central Standard Time (Mexico),
+ NZ: New Zealand Standard Time,
+ NZ-CHAT: Chatham Islands Standard Time,
+ Navajo: Mountain Standard Time,
+ PRC: China Standard Time,
+ PST8PDT: Pacific Standard Time,
+ Pacific/Apia: Samoa Standard Time,
+ Pacific/Auckland: New Zealand Standard Time,
+ Pacific/Bougainville: Bougainville Standard Time,
+ Pacific/Chatham: Chatham Islands Standard Time,
+ Pacific/Chuuk: West Pacific Standard Time,
+ Pacific/Easter: Easter Island Standard Time,
+ Pacific/Efate: Central Pacific Standard Time,
+ Pacific/Enderbury: UTC+13,
+ Pacific/Fakaofo: UTC+13,
+ Pacific/Fiji: Fiji Standard Time,
+ Pacific/Funafuti: UTC+12,
+ Pacific/Galapagos: Central America Standard Time,
+ Pacific/Gambier: UTC-09,
+ Pacific/Guadalcanal: Central Pacific Standard Time,
+ Pacific/Guam: West Pacific Standard Time,
+ Pacific/Honolulu: Hawaiian Standard Time,
+ Pacific/Johnston: Hawaiian Standard Time,
+ Pacific/Kanton: UTC+13,
+ Pacific/Kiritimati: Line Islands Standard Time,
+ Pacific/Kosrae: Central Pacific Standard Time,
+ Pacific/Kwajalein: UTC+12,
+ Pacific/Majuro: UTC+12,
+ Pacific/Marquesas: Marquesas Standard Time,
+ Pacific/Midway: UTC-11,
+ Pacific/Nauru: UTC+12,
+ Pacific/Niue: UTC-11,
+ Pacific/Norfolk: Norfolk Standard Time,
+ Pacific/Noumea: Central Pacific Standard Time,
+ Pacific/Pago_Pago: UTC-11,
+ Pacific/Palau: Tokyo Standard Time,
+ Pacific/Pitcairn: UTC-08,
+ Pacific/Pohnpei: Central Pacific Standard Time,
+ Pacific/Ponape: Central Pacific Standard Time,
+ Pacific/Port_Moresby: West Pacific Standard Time,
+ Pacific/Rarotonga: Hawaiian Standard Time,
+ Pacific/Saipan: West Pacific Standard Time,
+ Pacific/Samoa: UTC-11,
+ Pacific/Tahiti: Hawaiian Standard Time,
+ Pacific/Tarawa: UTC+12,
+ Pacific/Tongatapu: Tonga Standard Time,
+ Pacific/Truk: West Pacific Standard Time,
+ Pacific/Wake: UTC+12,
+ Pacific/Wallis: UTC+12,
+ Pacific/Yap: West Pacific Standard Time,
+ Poland: Central European Standard Time,
+ Portugal: GMT Standard Time,
+ ROC: Taipei Standard Time,
+ ROK: Korea Standard Time,
+ Singapore: Singapore Standard Time,
+ Turkey: Turkey Standard Time,
+ UCT: UTC,
+ US/Alaska: Alaskan Standard Time,
+ US/Aleutian: Aleutian Standard Time,
+ US/Arizona: US Mountain Standard Time,
+ US/Central: Central Standard Time,
+ US/East-Indiana: US Eastern Standard Time,
+ US/Eastern: Eastern Standard Time,
+ US/Hawaii: Hawaiian Standard Time,
+ US/Indiana-Starke: Central Standard Time,
+ US/Michigan: Eastern Standard Time,
+ US/Mountain: Mountain Standard Time,
+ US/Pacific: Pacific Standard Time,
+ US/Samoa: UTC-11,
+ UTC: UTC,
+ Universal: UTC,
+ W-SU: Russian Standard Time,
+ WET: GMT Standard Time,
+ Zulu: UTC
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_Territories_fullList=False.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_Territories_fullList=False.verified.txt
new file mode 100644
index 0000000..42894ab
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_Territories_fullList=False.verified.txt
@@ -0,0 +1,831 @@
+{
+ AD: [
+ Europe/Andorra
+ ],
+ AE: [
+ Asia/Dubai
+ ],
+ AF: [
+ Asia/Kabul
+ ],
+ AG: [
+ America/Antigua
+ ],
+ AI: [
+ America/Anguilla
+ ],
+ AL: [
+ Europe/Tirane
+ ],
+ AM: [
+ Asia/Yerevan
+ ],
+ AO: [
+ Africa/Luanda
+ ],
+ AQ: [
+ Antarctica/Casey,
+ Antarctica/Davis,
+ Antarctica/DumontDUrville,
+ Antarctica/Mawson,
+ Antarctica/McMurdo,
+ Antarctica/Rothera,
+ Antarctica/Syowa,
+ Antarctica/Troll,
+ Antarctica/Vostok
+ ],
+ AR: [
+ America/Argentina/Buenos_Aires
+ ],
+ AS: [
+ Pacific/Pago_Pago
+ ],
+ AT: [
+ Europe/Vienna
+ ],
+ AU: [
+ Australia/Adelaide,
+ Australia/Brisbane,
+ Australia/Darwin,
+ Australia/Eucla,
+ Australia/Hobart,
+ Australia/Lord_Howe,
+ Australia/Perth,
+ Australia/Sydney
+ ],
+ AW: [
+ America/Aruba
+ ],
+ AX: [
+ Europe/Mariehamn
+ ],
+ AZ: [
+ Asia/Baku
+ ],
+ BA: [
+ Europe/Sarajevo
+ ],
+ BB: [
+ America/Barbados
+ ],
+ BD: [
+ Asia/Dhaka
+ ],
+ BE: [
+ Europe/Brussels
+ ],
+ BF: [
+ Africa/Ouagadougou
+ ],
+ BG: [
+ Europe/Sofia
+ ],
+ BH: [
+ Asia/Bahrain
+ ],
+ BI: [
+ Africa/Bujumbura
+ ],
+ BJ: [
+ Africa/Porto-Novo
+ ],
+ BL: [
+ America/St_Barthelemy
+ ],
+ BM: [
+ Atlantic/Bermuda
+ ],
+ BN: [
+ Asia/Kuching
+ ],
+ BO: [
+ America/La_Paz
+ ],
+ BQ: [
+ America/Kralendijk
+ ],
+ BR: [
+ America/Araguaina,
+ America/Bahia,
+ America/Cuiaba,
+ America/Fortaleza,
+ America/Manaus,
+ America/Noronha,
+ America/Rio_Branco,
+ America/Sao_Paulo
+ ],
+ BS: [
+ America/Nassau
+ ],
+ BT: [
+ Asia/Thimphu
+ ],
+ BW: [
+ Africa/Gaborone
+ ],
+ BY: [
+ Europe/Minsk
+ ],
+ BZ: [
+ America/Belize
+ ],
+ CA: [
+ America/Blanc-Sablon,
+ America/Coral_Harbour,
+ America/Creston,
+ America/Edmonton,
+ America/Halifax,
+ America/Regina,
+ America/St_Johns,
+ America/Toronto,
+ America/Vancouver,
+ America/Whitehorse,
+ America/Winnipeg
+ ],
+ CC: [
+ Indian/Cocos
+ ],
+ CD: [
+ Africa/Kinshasa,
+ Africa/Lubumbashi
+ ],
+ CF: [
+ Africa/Bangui
+ ],
+ CG: [
+ Africa/Brazzaville
+ ],
+ CH: [
+ Europe/Zurich
+ ],
+ CI: [
+ Africa/Abidjan
+ ],
+ CK: [
+ Pacific/Rarotonga
+ ],
+ CL: [
+ America/Punta_Arenas,
+ America/Santiago,
+ Pacific/Easter
+ ],
+ CM: [
+ Africa/Douala
+ ],
+ CN: [
+ Asia/Shanghai,
+ Asia/Urumqi
+ ],
+ CO: [
+ America/Bogota
+ ],
+ CR: [
+ America/Costa_Rica
+ ],
+ CU: [
+ America/Havana
+ ],
+ CV: [
+ Atlantic/Cape_Verde
+ ],
+ CW: [
+ America/Curacao
+ ],
+ CX: [
+ Indian/Christmas
+ ],
+ CY: [
+ Asia/Nicosia
+ ],
+ CZ: [
+ Europe/Prague
+ ],
+ DE: [
+ Europe/Berlin
+ ],
+ DJ: [
+ Africa/Djibouti
+ ],
+ DK: [
+ Europe/Copenhagen
+ ],
+ DM: [
+ America/Dominica
+ ],
+ DO: [
+ America/Santo_Domingo
+ ],
+ DZ: [
+ Africa/Algiers
+ ],
+ EC: [
+ America/Guayaquil,
+ Pacific/Galapagos
+ ],
+ EE: [
+ Europe/Tallinn
+ ],
+ EG: [
+ Africa/Cairo
+ ],
+ EH: [
+ Africa/El_Aaiun
+ ],
+ ER: [
+ Africa/Asmera
+ ],
+ ES: [
+ Atlantic/Canary,
+ Europe/Madrid
+ ],
+ ET: [
+ Africa/Addis_Ababa
+ ],
+ FI: [
+ Europe/Helsinki
+ ],
+ FJ: [
+ Pacific/Fiji
+ ],
+ FK: [
+ Atlantic/Stanley
+ ],
+ FM: [
+ Pacific/Ponape,
+ Pacific/Truk
+ ],
+ FO: [
+ Atlantic/Faroe
+ ],
+ FR: [
+ Europe/Paris
+ ],
+ GA: [
+ Africa/Libreville
+ ],
+ GB: [
+ Europe/London
+ ],
+ GD: [
+ America/Grenada
+ ],
+ GE: [
+ Asia/Tbilisi
+ ],
+ GF: [
+ America/Cayenne
+ ],
+ GG: [
+ Europe/Guernsey
+ ],
+ GH: [
+ Africa/Accra
+ ],
+ GI: [
+ Europe/Gibraltar
+ ],
+ GL: [
+ America/Danmarkshavn,
+ America/Nuuk,
+ America/Scoresbysund,
+ America/Thule
+ ],
+ GM: [
+ Africa/Banjul
+ ],
+ GN: [
+ Africa/Conakry
+ ],
+ GP: [
+ America/Guadeloupe
+ ],
+ GQ: [
+ Africa/Malabo
+ ],
+ GR: [
+ Europe/Athens
+ ],
+ GS: [
+ Atlantic/South_Georgia
+ ],
+ GT: [
+ America/Guatemala
+ ],
+ GU: [
+ Pacific/Guam
+ ],
+ GW: [
+ Africa/Bissau
+ ],
+ GY: [
+ America/Guyana
+ ],
+ HK: [
+ Asia/Hong_Kong
+ ],
+ HN: [
+ America/Tegucigalpa
+ ],
+ HR: [
+ Europe/Zagreb
+ ],
+ HT: [
+ America/Port-au-Prince
+ ],
+ HU: [
+ Europe/Budapest
+ ],
+ ID: [
+ Asia/Jakarta,
+ Asia/Jayapura,
+ Asia/Makassar
+ ],
+ IE: [
+ Europe/Dublin
+ ],
+ IL: [
+ Asia/Jerusalem
+ ],
+ IM: [
+ Europe/Isle_of_Man
+ ],
+ IN: [
+ Asia/Kolkata
+ ],
+ IO: [
+ Indian/Chagos
+ ],
+ IQ: [
+ Asia/Baghdad
+ ],
+ IR: [
+ Asia/Tehran
+ ],
+ IS: [
+ Africa/Abidjan
+ ],
+ IT: [
+ Europe/Rome
+ ],
+ JE: [
+ Europe/Jersey
+ ],
+ JM: [
+ America/Jamaica
+ ],
+ JO: [
+ Asia/Amman
+ ],
+ JP: [
+ Asia/Tokyo
+ ],
+ KE: [
+ Africa/Nairobi
+ ],
+ KG: [
+ Asia/Bishkek
+ ],
+ KH: [
+ Asia/Phnom_Penh
+ ],
+ KI: [
+ Pacific/Kanton,
+ Pacific/Kiritimati,
+ Pacific/Tarawa
+ ],
+ KM: [
+ Indian/Comoro
+ ],
+ KN: [
+ America/St_Kitts
+ ],
+ KP: [
+ Asia/Pyongyang
+ ],
+ KR: [
+ Asia/Seoul
+ ],
+ KW: [
+ Asia/Kuwait
+ ],
+ KY: [
+ America/Cayman
+ ],
+ KZ: [
+ Asia/Oral,
+ Asia/Qyzylorda
+ ],
+ LA: [
+ Asia/Vientiane
+ ],
+ LB: [
+ Asia/Beirut
+ ],
+ LC: [
+ America/St_Lucia
+ ],
+ LI: [
+ Europe/Vaduz
+ ],
+ LK: [
+ Asia/Colombo
+ ],
+ LR: [
+ Africa/Monrovia
+ ],
+ LS: [
+ Africa/Maseru
+ ],
+ LT: [
+ Europe/Vilnius
+ ],
+ LU: [
+ Europe/Luxembourg
+ ],
+ LV: [
+ Europe/Riga
+ ],
+ LY: [
+ Africa/Tripoli
+ ],
+ MA: [
+ Africa/Casablanca
+ ],
+ MC: [
+ Europe/Monaco
+ ],
+ MD: [
+ Europe/Chisinau
+ ],
+ ME: [
+ Europe/Podgorica
+ ],
+ MF: [
+ America/Marigot
+ ],
+ MG: [
+ Indian/Antananarivo
+ ],
+ MH: [
+ Pacific/Majuro
+ ],
+ MK: [
+ Europe/Skopje
+ ],
+ ML: [
+ Africa/Bamako
+ ],
+ MM: [
+ Asia/Yangon
+ ],
+ MN: [
+ Asia/Hovd,
+ Asia/Ulaanbaatar
+ ],
+ MO: [
+ Asia/Macau
+ ],
+ MP: [
+ Pacific/Saipan
+ ],
+ MQ: [
+ America/Martinique
+ ],
+ MR: [
+ Africa/Nouakchott
+ ],
+ MS: [
+ America/Montserrat
+ ],
+ MT: [
+ Europe/Malta
+ ],
+ MU: [
+ Indian/Mauritius
+ ],
+ MV: [
+ Indian/Maldives
+ ],
+ MW: [
+ Africa/Blantyre
+ ],
+ MX: [
+ America/Cancun,
+ America/Ciudad_Juarez,
+ America/Hermosillo,
+ America/Matamoros,
+ America/Mazatlan,
+ America/Mexico_City,
+ America/Tijuana
+ ],
+ MY: [
+ Asia/Kuala_Lumpur
+ ],
+ MZ: [
+ Africa/Maputo
+ ],
+ NA: [
+ Africa/Windhoek
+ ],
+ NC: [
+ Pacific/Noumea
+ ],
+ NE: [
+ Africa/Niamey
+ ],
+ NF: [
+ Pacific/Norfolk
+ ],
+ NG: [
+ Africa/Lagos
+ ],
+ NI: [
+ America/Managua
+ ],
+ NL: [
+ Europe/Amsterdam
+ ],
+ NO: [
+ Europe/Oslo
+ ],
+ NP: [
+ Asia/Kathmandu
+ ],
+ NR: [
+ Pacific/Nauru
+ ],
+ NU: [
+ Pacific/Niue
+ ],
+ NZ: [
+ Pacific/Auckland,
+ Pacific/Chatham
+ ],
+ OM: [
+ Asia/Muscat
+ ],
+ PA: [
+ America/Panama
+ ],
+ PE: [
+ America/Lima
+ ],
+ PF: [
+ Pacific/Gambier,
+ Pacific/Marquesas,
+ Pacific/Tahiti
+ ],
+ PG: [
+ Pacific/Bougainville,
+ Pacific/Port_Moresby
+ ],
+ PH: [
+ Asia/Manila
+ ],
+ PK: [
+ Asia/Karachi
+ ],
+ PL: [
+ Europe/Warsaw
+ ],
+ PM: [
+ America/Miquelon
+ ],
+ PN: [
+ Pacific/Pitcairn
+ ],
+ PR: [
+ America/Puerto_Rico
+ ],
+ PS: [
+ Asia/Hebron
+ ],
+ PT: [
+ Atlantic/Azores,
+ Europe/Lisbon
+ ],
+ PW: [
+ Pacific/Palau
+ ],
+ PY: [
+ America/Asuncion
+ ],
+ QA: [
+ Asia/Qatar
+ ],
+ RE: [
+ Indian/Reunion
+ ],
+ RO: [
+ Europe/Bucharest
+ ],
+ RS: [
+ Europe/Belgrade
+ ],
+ RU: [
+ Asia/Barnaul,
+ Asia/Chita,
+ Asia/Irkutsk,
+ Asia/Kamchatka,
+ Asia/Krasnoyarsk,
+ Asia/Magadan,
+ Asia/Novosibirsk,
+ Asia/Omsk,
+ Asia/Sakhalin,
+ Asia/Srednekolymsk,
+ Asia/Tomsk,
+ Asia/Vladivostok,
+ Asia/Yakutsk,
+ Asia/Yekaterinburg,
+ Europe/Astrakhan,
+ Europe/Kaliningrad,
+ Europe/Moscow,
+ Europe/Samara,
+ Europe/Saratov,
+ Europe/Volgograd
+ ],
+ RW: [
+ Africa/Kigali
+ ],
+ SA: [
+ Asia/Riyadh
+ ],
+ SB: [
+ Pacific/Guadalcanal
+ ],
+ SC: [
+ Indian/Mahe
+ ],
+ SD: [
+ Africa/Khartoum
+ ],
+ SE: [
+ Europe/Stockholm
+ ],
+ SG: [
+ Asia/Singapore
+ ],
+ SH: [
+ Atlantic/St_Helena
+ ],
+ SI: [
+ Europe/Ljubljana
+ ],
+ SJ: [
+ Arctic/Longyearbyen
+ ],
+ SK: [
+ Europe/Bratislava
+ ],
+ SL: [
+ Africa/Freetown
+ ],
+ SM: [
+ Europe/San_Marino
+ ],
+ SN: [
+ Africa/Dakar
+ ],
+ SO: [
+ Africa/Mogadishu
+ ],
+ SR: [
+ America/Paramaribo
+ ],
+ SS: [
+ Africa/Juba
+ ],
+ ST: [
+ Africa/Sao_Tome
+ ],
+ SV: [
+ America/El_Salvador
+ ],
+ SX: [
+ America/Lower_Princes
+ ],
+ SY: [
+ Asia/Damascus
+ ],
+ SZ: [
+ Africa/Mbabane
+ ],
+ TC: [
+ America/Grand_Turk
+ ],
+ TD: [
+ Africa/Ndjamena
+ ],
+ TF: [
+ Indian/Kerguelen
+ ],
+ TG: [
+ Africa/Lome
+ ],
+ TH: [
+ Asia/Bangkok
+ ],
+ TJ: [
+ Asia/Dushanbe
+ ],
+ TK: [
+ Pacific/Fakaofo
+ ],
+ TL: [
+ Asia/Dili
+ ],
+ TM: [
+ Asia/Ashgabat
+ ],
+ TN: [
+ Africa/Tunis
+ ],
+ TO: [
+ Pacific/Tongatapu
+ ],
+ TR: [
+ Europe/Istanbul
+ ],
+ TT: [
+ America/Port_of_Spain
+ ],
+ TV: [
+ Pacific/Funafuti
+ ],
+ TW: [
+ Asia/Taipei
+ ],
+ TZ: [
+ Africa/Dar_es_Salaam
+ ],
+ UA: [
+ Europe/Kyiv,
+ Europe/Simferopol
+ ],
+ UG: [
+ Africa/Kampala
+ ],
+ UM: [
+ Pacific/Midway,
+ Pacific/Wake
+ ],
+ US: [
+ America/Adak,
+ America/Anchorage,
+ America/Chicago,
+ America/Denver,
+ America/Indiana/Indianapolis,
+ America/Los_Angeles,
+ America/New_York,
+ America/Phoenix,
+ Pacific/Honolulu
+ ],
+ UY: [
+ America/Montevideo
+ ],
+ UZ: [
+ Asia/Tashkent
+ ],
+ VA: [
+ Europe/Vatican
+ ],
+ VC: [
+ America/St_Vincent
+ ],
+ VE: [
+ America/Caracas
+ ],
+ VG: [
+ America/Tortola
+ ],
+ VI: [
+ America/St_Thomas
+ ],
+ VN: [
+ Asia/Ho_Chi_Minh
+ ],
+ VU: [
+ Pacific/Efate
+ ],
+ WF: [
+ Pacific/Wallis
+ ],
+ WS: [
+ Pacific/Apia
+ ],
+ YE: [
+ Asia/Aden
+ ],
+ YT: [
+ Indian/Mayotte
+ ],
+ ZA: [
+ Africa/Johannesburg
+ ],
+ ZM: [
+ Africa/Lusaka
+ ],
+ ZW: [
+ Africa/Harare
+ ]
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_Territories_fullList=True.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_Territories_fullList=True.verified.txt
new file mode 100644
index 0000000..5cfe4c7
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_Territories_fullList=True.verified.txt
@@ -0,0 +1,914 @@
+{
+ AD: [
+ Europe/Andorra
+ ],
+ AE: [
+ Asia/Dubai
+ ],
+ AF: [
+ Asia/Kabul
+ ],
+ AG: [
+ America/Antigua
+ ],
+ AI: [
+ America/Anguilla
+ ],
+ AL: [
+ Europe/Tirane
+ ],
+ AM: [
+ Asia/Yerevan
+ ],
+ AO: [
+ Africa/Luanda
+ ],
+ AQ: [
+ Antarctica/Casey,
+ Antarctica/Davis,
+ Antarctica/DumontDUrville,
+ Antarctica/Mawson,
+ Antarctica/McMurdo,
+ Antarctica/Palmer,
+ Antarctica/Rothera,
+ Antarctica/Syowa,
+ Antarctica/Troll,
+ Antarctica/Vostok
+ ],
+ AR: [
+ America/Argentina/Buenos_Aires,
+ America/Argentina/Catamarca,
+ America/Argentina/Cordoba,
+ America/Argentina/Jujuy,
+ America/Argentina/La_Rioja,
+ America/Argentina/Mendoza,
+ America/Argentina/Rio_Gallegos,
+ America/Argentina/Salta,
+ America/Argentina/San_Juan,
+ America/Argentina/San_Luis,
+ America/Argentina/Tucuman,
+ America/Argentina/Ushuaia
+ ],
+ AS: [
+ Pacific/Pago_Pago
+ ],
+ AT: [
+ Europe/Vienna
+ ],
+ AU: [
+ Antarctica/Macquarie,
+ Australia/Adelaide,
+ Australia/Brisbane,
+ Australia/Broken_Hill,
+ Australia/Darwin,
+ Australia/Eucla,
+ Australia/Hobart,
+ Australia/Lindeman,
+ Australia/Lord_Howe,
+ Australia/Melbourne,
+ Australia/Perth,
+ Australia/Sydney
+ ],
+ AW: [
+ America/Aruba
+ ],
+ AX: [
+ Europe/Mariehamn
+ ],
+ AZ: [
+ Asia/Baku
+ ],
+ BA: [
+ Europe/Sarajevo
+ ],
+ BB: [
+ America/Barbados
+ ],
+ BD: [
+ Asia/Dhaka
+ ],
+ BE: [
+ Europe/Brussels
+ ],
+ BF: [
+ Africa/Ouagadougou
+ ],
+ BG: [
+ Europe/Sofia
+ ],
+ BH: [
+ Asia/Bahrain
+ ],
+ BI: [
+ Africa/Bujumbura
+ ],
+ BJ: [
+ Africa/Porto-Novo
+ ],
+ BL: [
+ America/St_Barthelemy
+ ],
+ BM: [
+ Atlantic/Bermuda
+ ],
+ BN: [
+ Asia/Brunei
+ ],
+ BO: [
+ America/La_Paz
+ ],
+ BQ: [
+ America/Kralendijk
+ ],
+ BR: [
+ America/Araguaina,
+ America/Bahia,
+ America/Belem,
+ America/Boa_Vista,
+ America/Campo_Grande,
+ America/Cuiaba,
+ America/Eirunepe,
+ America/Fortaleza,
+ America/Maceio,
+ America/Manaus,
+ America/Noronha,
+ America/Porto_Velho,
+ America/Recife,
+ America/Rio_Branco,
+ America/Santarem,
+ America/Sao_Paulo
+ ],
+ BS: [
+ America/Nassau
+ ],
+ BT: [
+ Asia/Thimphu
+ ],
+ BW: [
+ Africa/Gaborone
+ ],
+ BY: [
+ Europe/Minsk
+ ],
+ BZ: [
+ America/Belize
+ ],
+ CA: [
+ America/Atikokan,
+ America/Blanc-Sablon,
+ America/Cambridge_Bay,
+ America/Creston,
+ America/Dawson,
+ America/Dawson_Creek,
+ America/Edmonton,
+ America/Fort_Nelson,
+ America/Glace_Bay,
+ America/Goose_Bay,
+ America/Halifax,
+ America/Inuvik,
+ America/Iqaluit,
+ America/Moncton,
+ America/Rankin_Inlet,
+ America/Regina,
+ America/Resolute,
+ America/St_Johns,
+ America/Swift_Current,
+ America/Toronto,
+ America/Vancouver,
+ America/Whitehorse,
+ America/Winnipeg
+ ],
+ CC: [
+ Indian/Cocos
+ ],
+ CD: [
+ Africa/Kinshasa,
+ Africa/Lubumbashi
+ ],
+ CF: [
+ Africa/Bangui
+ ],
+ CG: [
+ Africa/Brazzaville
+ ],
+ CH: [
+ Europe/Zurich
+ ],
+ CI: [
+ Africa/Abidjan
+ ],
+ CK: [
+ Pacific/Rarotonga
+ ],
+ CL: [
+ America/Coyhaique,
+ America/Punta_Arenas,
+ America/Santiago,
+ Pacific/Easter
+ ],
+ CM: [
+ Africa/Douala
+ ],
+ CN: [
+ Asia/Shanghai,
+ Asia/Urumqi
+ ],
+ CO: [
+ America/Bogota
+ ],
+ CR: [
+ America/Costa_Rica
+ ],
+ CU: [
+ America/Havana
+ ],
+ CV: [
+ Atlantic/Cape_Verde
+ ],
+ CW: [
+ America/Curacao
+ ],
+ CX: [
+ Indian/Christmas
+ ],
+ CY: [
+ Asia/Famagusta,
+ Asia/Nicosia
+ ],
+ CZ: [
+ Europe/Prague
+ ],
+ DE: [
+ Europe/Berlin,
+ Europe/Busingen
+ ],
+ DJ: [
+ Africa/Djibouti
+ ],
+ DK: [
+ Europe/Copenhagen
+ ],
+ DM: [
+ America/Dominica
+ ],
+ DO: [
+ America/Santo_Domingo
+ ],
+ DZ: [
+ Africa/Algiers
+ ],
+ EC: [
+ America/Guayaquil,
+ Pacific/Galapagos
+ ],
+ EE: [
+ Europe/Tallinn
+ ],
+ EG: [
+ Africa/Cairo
+ ],
+ EH: [
+ Africa/El_Aaiun
+ ],
+ ER: [
+ Africa/Asmara
+ ],
+ ES: [
+ Africa/Ceuta,
+ Atlantic/Canary,
+ Europe/Madrid
+ ],
+ ET: [
+ Africa/Addis_Ababa
+ ],
+ FI: [
+ Europe/Helsinki
+ ],
+ FJ: [
+ Pacific/Fiji
+ ],
+ FK: [
+ Atlantic/Stanley
+ ],
+ FM: [
+ Pacific/Chuuk,
+ Pacific/Kosrae,
+ Pacific/Pohnpei
+ ],
+ FO: [
+ Atlantic/Faroe
+ ],
+ FR: [
+ Europe/Paris
+ ],
+ GA: [
+ Africa/Libreville
+ ],
+ GB: [
+ Europe/London
+ ],
+ GD: [
+ America/Grenada
+ ],
+ GE: [
+ Asia/Tbilisi
+ ],
+ GF: [
+ America/Cayenne
+ ],
+ GG: [
+ Europe/Guernsey
+ ],
+ GH: [
+ Africa/Accra
+ ],
+ GI: [
+ Europe/Gibraltar
+ ],
+ GL: [
+ America/Danmarkshavn,
+ America/Nuuk,
+ America/Scoresbysund,
+ America/Thule
+ ],
+ GM: [
+ Africa/Banjul
+ ],
+ GN: [
+ Africa/Conakry
+ ],
+ GP: [
+ America/Guadeloupe
+ ],
+ GQ: [
+ Africa/Malabo
+ ],
+ GR: [
+ Europe/Athens
+ ],
+ GS: [
+ Atlantic/South_Georgia
+ ],
+ GT: [
+ America/Guatemala
+ ],
+ GU: [
+ Pacific/Guam
+ ],
+ GW: [
+ Africa/Bissau
+ ],
+ GY: [
+ America/Guyana
+ ],
+ HK: [
+ Asia/Hong_Kong
+ ],
+ HN: [
+ America/Tegucigalpa
+ ],
+ HR: [
+ Europe/Zagreb
+ ],
+ HT: [
+ America/Port-au-Prince
+ ],
+ HU: [
+ Europe/Budapest
+ ],
+ ID: [
+ Asia/Jakarta,
+ Asia/Jayapura,
+ Asia/Makassar,
+ Asia/Pontianak
+ ],
+ IE: [
+ Europe/Dublin
+ ],
+ IL: [
+ Asia/Jerusalem
+ ],
+ IM: [
+ Europe/Isle_of_Man
+ ],
+ IN: [
+ Asia/Kolkata
+ ],
+ IO: [
+ Indian/Chagos
+ ],
+ IQ: [
+ Asia/Baghdad
+ ],
+ IR: [
+ Asia/Tehran
+ ],
+ IS: [
+ Atlantic/Reykjavik
+ ],
+ IT: [
+ Europe/Rome
+ ],
+ JE: [
+ Europe/Jersey
+ ],
+ JM: [
+ America/Jamaica
+ ],
+ JO: [
+ Asia/Amman
+ ],
+ JP: [
+ Asia/Tokyo
+ ],
+ KE: [
+ Africa/Nairobi
+ ],
+ KG: [
+ Asia/Bishkek
+ ],
+ KH: [
+ Asia/Phnom_Penh
+ ],
+ KI: [
+ Pacific/Kanton,
+ Pacific/Kiritimati,
+ Pacific/Tarawa
+ ],
+ KM: [
+ Indian/Comoro
+ ],
+ KN: [
+ America/St_Kitts
+ ],
+ KP: [
+ Asia/Pyongyang
+ ],
+ KR: [
+ Asia/Seoul
+ ],
+ KW: [
+ Asia/Kuwait
+ ],
+ KY: [
+ America/Cayman
+ ],
+ KZ: [
+ Asia/Almaty,
+ Asia/Aqtau,
+ Asia/Aqtobe,
+ Asia/Atyrau,
+ Asia/Oral,
+ Asia/Qostanay,
+ Asia/Qyzylorda
+ ],
+ LA: [
+ Asia/Vientiane
+ ],
+ LB: [
+ Asia/Beirut
+ ],
+ LC: [
+ America/St_Lucia
+ ],
+ LI: [
+ Europe/Vaduz
+ ],
+ LK: [
+ Asia/Colombo
+ ],
+ LR: [
+ Africa/Monrovia
+ ],
+ LS: [
+ Africa/Maseru
+ ],
+ LT: [
+ Europe/Vilnius
+ ],
+ LU: [
+ Europe/Luxembourg
+ ],
+ LV: [
+ Europe/Riga
+ ],
+ LY: [
+ Africa/Tripoli
+ ],
+ MA: [
+ Africa/Casablanca
+ ],
+ MC: [
+ Europe/Monaco
+ ],
+ MD: [
+ Europe/Chisinau
+ ],
+ ME: [
+ Europe/Podgorica
+ ],
+ MF: [
+ America/Marigot
+ ],
+ MG: [
+ Indian/Antananarivo
+ ],
+ MH: [
+ Pacific/Kwajalein,
+ Pacific/Majuro
+ ],
+ MK: [
+ Europe/Skopje
+ ],
+ ML: [
+ Africa/Bamako
+ ],
+ MM: [
+ Asia/Yangon
+ ],
+ MN: [
+ Asia/Hovd,
+ Asia/Ulaanbaatar
+ ],
+ MO: [
+ Asia/Macau
+ ],
+ MP: [
+ Pacific/Saipan
+ ],
+ MQ: [
+ America/Martinique
+ ],
+ MR: [
+ Africa/Nouakchott
+ ],
+ MS: [
+ America/Montserrat
+ ],
+ MT: [
+ Europe/Malta
+ ],
+ MU: [
+ Indian/Mauritius
+ ],
+ MV: [
+ Indian/Maldives
+ ],
+ MW: [
+ Africa/Blantyre
+ ],
+ MX: [
+ America/Bahia_Banderas,
+ America/Cancun,
+ America/Chihuahua,
+ America/Ciudad_Juarez,
+ America/Hermosillo,
+ America/Matamoros,
+ America/Mazatlan,
+ America/Merida,
+ America/Mexico_City,
+ America/Monterrey,
+ America/Ojinaga,
+ America/Tijuana
+ ],
+ MY: [
+ Asia/Kuala_Lumpur,
+ Asia/Kuching
+ ],
+ MZ: [
+ Africa/Maputo
+ ],
+ NA: [
+ Africa/Windhoek
+ ],
+ NC: [
+ Pacific/Noumea
+ ],
+ NE: [
+ Africa/Niamey
+ ],
+ NF: [
+ Pacific/Norfolk
+ ],
+ NG: [
+ Africa/Lagos
+ ],
+ NI: [
+ America/Managua
+ ],
+ NL: [
+ Europe/Amsterdam
+ ],
+ NO: [
+ Europe/Oslo
+ ],
+ NP: [
+ Asia/Kathmandu
+ ],
+ NR: [
+ Pacific/Nauru
+ ],
+ NU: [
+ Pacific/Niue
+ ],
+ NZ: [
+ Pacific/Auckland,
+ Pacific/Chatham
+ ],
+ OM: [
+ Asia/Muscat
+ ],
+ PA: [
+ America/Panama
+ ],
+ PE: [
+ America/Lima
+ ],
+ PF: [
+ Pacific/Gambier,
+ Pacific/Marquesas,
+ Pacific/Tahiti
+ ],
+ PG: [
+ Pacific/Bougainville,
+ Pacific/Port_Moresby
+ ],
+ PH: [
+ Asia/Manila
+ ],
+ PK: [
+ Asia/Karachi
+ ],
+ PL: [
+ Europe/Warsaw
+ ],
+ PM: [
+ America/Miquelon
+ ],
+ PN: [
+ Pacific/Pitcairn
+ ],
+ PR: [
+ America/Puerto_Rico
+ ],
+ PS: [
+ Asia/Gaza,
+ Asia/Hebron
+ ],
+ PT: [
+ Atlantic/Azores,
+ Atlantic/Madeira,
+ Europe/Lisbon
+ ],
+ PW: [
+ Pacific/Palau
+ ],
+ PY: [
+ America/Asuncion
+ ],
+ QA: [
+ Asia/Qatar
+ ],
+ RE: [
+ Indian/Reunion
+ ],
+ RO: [
+ Europe/Bucharest
+ ],
+ RS: [
+ Europe/Belgrade
+ ],
+ RU: [
+ Asia/Anadyr,
+ Asia/Barnaul,
+ Asia/Chita,
+ Asia/Irkutsk,
+ Asia/Kamchatka,
+ Asia/Khandyga,
+ Asia/Krasnoyarsk,
+ Asia/Magadan,
+ Asia/Novokuznetsk,
+ Asia/Novosibirsk,
+ Asia/Omsk,
+ Asia/Sakhalin,
+ Asia/Srednekolymsk,
+ Asia/Tomsk,
+ Asia/Ust-Nera,
+ Asia/Vladivostok,
+ Asia/Yakutsk,
+ Asia/Yekaterinburg,
+ Europe/Astrakhan,
+ Europe/Kaliningrad,
+ Europe/Kirov,
+ Europe/Moscow,
+ Europe/Samara,
+ Europe/Saratov,
+ Europe/Ulyanovsk,
+ Europe/Volgograd
+ ],
+ RW: [
+ Africa/Kigali
+ ],
+ SA: [
+ Asia/Riyadh
+ ],
+ SB: [
+ Pacific/Guadalcanal
+ ],
+ SC: [
+ Indian/Mahe
+ ],
+ SD: [
+ Africa/Khartoum
+ ],
+ SE: [
+ Europe/Stockholm
+ ],
+ SG: [
+ Asia/Singapore
+ ],
+ SH: [
+ Atlantic/St_Helena
+ ],
+ SI: [
+ Europe/Ljubljana
+ ],
+ SJ: [
+ Arctic/Longyearbyen
+ ],
+ SK: [
+ Europe/Bratislava
+ ],
+ SL: [
+ Africa/Freetown
+ ],
+ SM: [
+ Europe/San_Marino
+ ],
+ SN: [
+ Africa/Dakar
+ ],
+ SO: [
+ Africa/Mogadishu
+ ],
+ SR: [
+ America/Paramaribo
+ ],
+ SS: [
+ Africa/Juba
+ ],
+ ST: [
+ Africa/Sao_Tome
+ ],
+ SV: [
+ America/El_Salvador
+ ],
+ SX: [
+ America/Lower_Princes
+ ],
+ SY: [
+ Asia/Damascus
+ ],
+ SZ: [
+ Africa/Mbabane
+ ],
+ TC: [
+ America/Grand_Turk
+ ],
+ TD: [
+ Africa/Ndjamena
+ ],
+ TF: [
+ Indian/Kerguelen
+ ],
+ TG: [
+ Africa/Lome
+ ],
+ TH: [
+ Asia/Bangkok
+ ],
+ TJ: [
+ Asia/Dushanbe
+ ],
+ TK: [
+ Pacific/Fakaofo
+ ],
+ TL: [
+ Asia/Dili
+ ],
+ TM: [
+ Asia/Ashgabat
+ ],
+ TN: [
+ Africa/Tunis
+ ],
+ TO: [
+ Pacific/Tongatapu
+ ],
+ TR: [
+ Europe/Istanbul
+ ],
+ TT: [
+ America/Port_of_Spain
+ ],
+ TV: [
+ Pacific/Funafuti
+ ],
+ TW: [
+ Asia/Taipei
+ ],
+ TZ: [
+ Africa/Dar_es_Salaam
+ ],
+ UA: [
+ Europe/Kyiv,
+ Europe/Simferopol
+ ],
+ UG: [
+ Africa/Kampala
+ ],
+ UM: [
+ Pacific/Midway,
+ Pacific/Wake
+ ],
+ US: [
+ America/Adak,
+ America/Anchorage,
+ America/Boise,
+ America/Chicago,
+ America/Denver,
+ America/Detroit,
+ America/Indiana/Indianapolis,
+ America/Indiana/Knox,
+ America/Indiana/Marengo,
+ America/Indiana/Petersburg,
+ America/Indiana/Tell_City,
+ America/Indiana/Vevay,
+ America/Indiana/Vincennes,
+ America/Indiana/Winamac,
+ America/Juneau,
+ America/Kentucky/Louisville,
+ America/Kentucky/Monticello,
+ America/Los_Angeles,
+ America/Menominee,
+ America/Metlakatla,
+ America/New_York,
+ America/Nome,
+ America/North_Dakota/Beulah,
+ America/North_Dakota/Center,
+ America/North_Dakota/New_Salem,
+ America/Phoenix,
+ America/Sitka,
+ America/Yakutat,
+ Pacific/Honolulu
+ ],
+ UY: [
+ America/Montevideo
+ ],
+ UZ: [
+ Asia/Samarkand,
+ Asia/Tashkent
+ ],
+ VA: [
+ Europe/Vatican
+ ],
+ VC: [
+ America/St_Vincent
+ ],
+ VE: [
+ America/Caracas
+ ],
+ VG: [
+ America/Tortola
+ ],
+ VI: [
+ America/St_Thomas
+ ],
+ VN: [
+ Asia/Ho_Chi_Minh
+ ],
+ VU: [
+ Pacific/Efate
+ ],
+ WF: [
+ Pacific/Wallis
+ ],
+ WS: [
+ Pacific/Apia
+ ],
+ YE: [
+ Asia/Aden
+ ],
+ YT: [
+ Indian/Mayotte
+ ],
+ ZA: [
+ Africa/Johannesburg
+ ],
+ ZM: [
+ Africa/Lusaka
+ ],
+ ZW: [
+ Africa/Harare
+ ]
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_To_Rails.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_To_Rails.verified.txt
new file mode 100644
index 0000000..d6baa29
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Iana_To_Rails.verified.txt
@@ -0,0 +1,1857 @@
+{
+ Africa/Abidjan: [
+ Africa/Abidjan
+ ],
+ Africa/Accra: [
+ Africa/Accra
+ ],
+ Africa/Addis_Ababa: [
+ Nairobi
+ ],
+ Africa/Algiers: [
+ West Central Africa
+ ],
+ Africa/Asmara: [
+ Nairobi
+ ],
+ Africa/Asmera: [
+ Nairobi
+ ],
+ Africa/Bamako: [
+ Africa/Bamako
+ ],
+ Africa/Bangui: [
+ Africa/Bangui
+ ],
+ Africa/Banjul: [
+ Africa/Banjul
+ ],
+ Africa/Bissau: [
+ Africa/Bissau
+ ],
+ Africa/Blantyre: [
+ Pretoria
+ ],
+ Africa/Brazzaville: [
+ Africa/Brazzaville
+ ],
+ Africa/Bujumbura: [
+ Pretoria
+ ],
+ Africa/Cairo: [
+ Cairo
+ ],
+ Africa/Casablanca: [
+ Casablanca
+ ],
+ Africa/Ceuta: [
+ Madrid
+ ],
+ Africa/Conakry: [
+ Africa/Conakry
+ ],
+ Africa/Dakar: [
+ Africa/Dakar
+ ],
+ Africa/Dar_es_Salaam: [
+ Nairobi
+ ],
+ Africa/Djibouti: [
+ Nairobi
+ ],
+ Africa/Douala: [
+ Africa/Douala
+ ],
+ Africa/El_Aaiun: [
+ Casablanca
+ ],
+ Africa/Freetown: [
+ Africa/Freetown
+ ],
+ Africa/Gaborone: [
+ Pretoria
+ ],
+ Africa/Harare: [
+ Harare
+ ],
+ Africa/Johannesburg: [
+ Pretoria
+ ],
+ Africa/Juba: [
+ Africa/Juba
+ ],
+ Africa/Kampala: [
+ Nairobi
+ ],
+ Africa/Khartoum: [
+ Africa/Khartoum
+ ],
+ Africa/Kigali: [
+ Harare
+ ],
+ Africa/Kinshasa: [
+ Africa/Kinshasa
+ ],
+ Africa/Lagos: [
+ Africa/Lagos
+ ],
+ Africa/Libreville: [
+ Africa/Libreville
+ ],
+ Africa/Lome: [
+ Africa/Lome
+ ],
+ Africa/Luanda: [
+ Africa/Luanda
+ ],
+ Africa/Lubumbashi: [
+ Harare
+ ],
+ Africa/Lusaka: [
+ Harare
+ ],
+ Africa/Malabo: [
+ Africa/Malabo
+ ],
+ Africa/Maputo: [
+ Harare
+ ],
+ Africa/Maseru: [
+ Pretoria
+ ],
+ Africa/Mbabane: [
+ Pretoria
+ ],
+ Africa/Mogadishu: [
+ Nairobi
+ ],
+ Africa/Monrovia: [
+ Monrovia
+ ],
+ Africa/Nairobi: [
+ Nairobi
+ ],
+ Africa/Ndjamena: [
+ Africa/Ndjamena
+ ],
+ Africa/Niamey: [
+ Africa/Niamey
+ ],
+ Africa/Nouakchott: [
+ Africa/Nouakchott
+ ],
+ Africa/Ouagadougou: [
+ Africa/Ouagadougou
+ ],
+ Africa/Porto-Novo: [
+ Africa/Porto-Novo
+ ],
+ Africa/Sao_Tome: [
+ Africa/Sao_Tome
+ ],
+ Africa/Timbuktu: [
+ Africa/Timbuktu
+ ],
+ Africa/Tripoli: [
+ Africa/Tripoli
+ ],
+ Africa/Tunis: [
+ Africa/Tunis
+ ],
+ Africa/Windhoek: [
+ Africa/Windhoek
+ ],
+ America/Adak: [
+ America/Adak
+ ],
+ America/Anchorage: [
+ Alaska
+ ],
+ America/Anguilla: [
+ Puerto Rico
+ ],
+ America/Antigua: [
+ Puerto Rico
+ ],
+ America/Araguaina: [
+ America/Araguaina
+ ],
+ America/Argentina/Buenos_Aires: [
+ Buenos Aires
+ ],
+ America/Argentina/Catamarca: [
+ Buenos Aires
+ ],
+ America/Argentina/ComodRivadavia: [
+ Buenos Aires
+ ],
+ America/Argentina/Cordoba: [
+ Buenos Aires
+ ],
+ America/Argentina/Jujuy: [
+ Buenos Aires
+ ],
+ America/Argentina/La_Rioja: [
+ Buenos Aires
+ ],
+ America/Argentina/Mendoza: [
+ Buenos Aires
+ ],
+ America/Argentina/Rio_Gallegos: [
+ Buenos Aires
+ ],
+ America/Argentina/Salta: [
+ Buenos Aires
+ ],
+ America/Argentina/San_Juan: [
+ Buenos Aires
+ ],
+ America/Argentina/San_Luis: [
+ Buenos Aires
+ ],
+ America/Argentina/Tucuman: [
+ Buenos Aires
+ ],
+ America/Argentina/Ushuaia: [
+ Buenos Aires
+ ],
+ America/Aruba: [
+ Puerto Rico
+ ],
+ America/Asuncion: [
+ Asuncion
+ ],
+ America/Atikokan: [
+ Bogota
+ ],
+ America/Atka: [
+ America/Atka
+ ],
+ America/Bahia: [
+ America/Bahia
+ ],
+ America/Bahia_Banderas: [
+ Guadalajara,
+ Mexico City
+ ],
+ America/Barbados: [
+ La Paz
+ ],
+ America/Belem: [
+ America/Belem
+ ],
+ America/Belize: [
+ Central America
+ ],
+ America/Blanc-Sablon: [
+ Puerto Rico
+ ],
+ America/Boa_Vista: [
+ La Paz
+ ],
+ America/Bogota: [
+ Bogota
+ ],
+ America/Boise: [
+ Mountain Time (US & Canada)
+ ],
+ America/Buenos_Aires: [
+ Buenos Aires
+ ],
+ America/Cambridge_Bay: [
+ Mountain Time (US & Canada)
+ ],
+ America/Campo_Grande: [
+ America/Campo_Grande
+ ],
+ America/Cancun: [
+ America/Cancun
+ ],
+ America/Caracas: [
+ Caracas
+ ],
+ America/Catamarca: [
+ Buenos Aires
+ ],
+ America/Cayenne: [
+ America/Cayenne
+ ],
+ America/Cayman: [
+ Bogota
+ ],
+ America/Chicago: [
+ Central Time (US & Canada)
+ ],
+ America/Chihuahua: [
+ Chihuahua
+ ],
+ America/Ciudad_Juarez: [
+ Mountain Time (US & Canada)
+ ],
+ America/Coral_Harbour: [
+ Bogota
+ ],
+ America/Cordoba: [
+ Buenos Aires
+ ],
+ America/Costa_Rica: [
+ Central America
+ ],
+ America/Coyhaique: [
+ America/Coyhaique
+ ],
+ America/Creston: [
+ Arizona
+ ],
+ America/Cuiaba: [
+ America/Cuiaba
+ ],
+ America/Curacao: [
+ Puerto Rico
+ ],
+ America/Danmarkshavn: [
+ America/Danmarkshavn
+ ],
+ America/Dawson: [
+ America/Dawson
+ ],
+ America/Dawson_Creek: [
+ Arizona
+ ],
+ America/Denver: [
+ Mountain Time (US & Canada)
+ ],
+ America/Detroit: [
+ Eastern Time (US & Canada)
+ ],
+ America/Dominica: [
+ Puerto Rico
+ ],
+ America/Edmonton: [
+ Mountain Time (US & Canada)
+ ],
+ America/Eirunepe: [
+ Bogota
+ ],
+ America/El_Salvador: [
+ Central America
+ ],
+ America/Ensenada: [
+ Tijuana
+ ],
+ America/Fort_Nelson: [
+ Arizona
+ ],
+ America/Fort_Wayne: [
+ Indiana (East)
+ ],
+ America/Fortaleza: [
+ America/Fortaleza
+ ],
+ America/Glace_Bay: [
+ Atlantic Time (Canada)
+ ],
+ America/Godthab: [
+ Greenland
+ ],
+ America/Goose_Bay: [
+ Atlantic Time (Canada)
+ ],
+ America/Grand_Turk: [
+ America/Grand_Turk
+ ],
+ America/Grenada: [
+ Puerto Rico
+ ],
+ America/Guadeloupe: [
+ Puerto Rico
+ ],
+ America/Guatemala: [
+ Central America
+ ],
+ America/Guayaquil: [
+ Bogota
+ ],
+ America/Guyana: [
+ Georgetown
+ ],
+ America/Halifax: [
+ Atlantic Time (Canada)
+ ],
+ America/Havana: [
+ America/Havana
+ ],
+ America/Hermosillo: [
+ Arizona
+ ],
+ America/Indiana/Indianapolis: [
+ Indiana (East)
+ ],
+ America/Indiana/Knox: [
+ Central Time (US & Canada)
+ ],
+ America/Indiana/Marengo: [
+ Indiana (East)
+ ],
+ America/Indiana/Petersburg: [
+ Eastern Time (US & Canada)
+ ],
+ America/Indiana/Tell_City: [
+ Central Time (US & Canada)
+ ],
+ America/Indiana/Vevay: [
+ Indiana (East)
+ ],
+ America/Indiana/Vincennes: [
+ Eastern Time (US & Canada)
+ ],
+ America/Indiana/Winamac: [
+ Eastern Time (US & Canada)
+ ],
+ America/Indianapolis: [
+ Indiana (East)
+ ],
+ America/Inuvik: [
+ Mountain Time (US & Canada)
+ ],
+ America/Iqaluit: [
+ Eastern Time (US & Canada)
+ ],
+ America/Jamaica: [
+ Bogota
+ ],
+ America/Jujuy: [
+ Buenos Aires
+ ],
+ America/Juneau: [
+ Alaska
+ ],
+ America/Kentucky/Louisville: [
+ Eastern Time (US & Canada)
+ ],
+ America/Kentucky/Monticello: [
+ Eastern Time (US & Canada)
+ ],
+ America/Knox_IN: [
+ Central Time (US & Canada)
+ ],
+ America/Kralendijk: [
+ Puerto Rico
+ ],
+ America/La_Paz: [
+ La Paz
+ ],
+ America/Lima: [
+ Lima,
+ Quito
+ ],
+ America/Los_Angeles: [
+ Pacific Time (US & Canada)
+ ],
+ America/Louisville: [
+ Eastern Time (US & Canada)
+ ],
+ America/Lower_Princes: [
+ Puerto Rico
+ ],
+ America/Maceio: [
+ America/Maceio
+ ],
+ America/Managua: [
+ Central America
+ ],
+ America/Manaus: [
+ La Paz
+ ],
+ America/Marigot: [
+ Puerto Rico
+ ],
+ America/Martinique: [
+ La Paz
+ ],
+ America/Matamoros: [
+ Central Time (US & Canada)
+ ],
+ America/Mazatlan: [
+ Mazatlan
+ ],
+ America/Mendoza: [
+ Buenos Aires
+ ],
+ America/Menominee: [
+ Central Time (US & Canada)
+ ],
+ America/Merida: [
+ Guadalajara,
+ Mexico City
+ ],
+ America/Metlakatla: [
+ Alaska
+ ],
+ America/Mexico_City: [
+ Guadalajara,
+ Mexico City
+ ],
+ America/Miquelon: [
+ America/Miquelon
+ ],
+ America/Moncton: [
+ Atlantic Time (Canada)
+ ],
+ America/Monterrey: [
+ Monterrey
+ ],
+ America/Montevideo: [
+ Montevideo
+ ],
+ America/Montreal: [
+ Eastern Time (US & Canada)
+ ],
+ America/Montserrat: [
+ Puerto Rico
+ ],
+ America/Nassau: [
+ Eastern Time (US & Canada)
+ ],
+ America/New_York: [
+ Eastern Time (US & Canada)
+ ],
+ America/Nipigon: [
+ Eastern Time (US & Canada)
+ ],
+ America/Nome: [
+ Alaska
+ ],
+ America/Noronha: [
+ America/Noronha
+ ],
+ America/North_Dakota/Beulah: [
+ Central Time (US & Canada)
+ ],
+ America/North_Dakota/Center: [
+ Central Time (US & Canada)
+ ],
+ America/North_Dakota/New_Salem: [
+ Central Time (US & Canada)
+ ],
+ America/Nuuk: [
+ Greenland
+ ],
+ America/Ojinaga: [
+ Central Time (US & Canada)
+ ],
+ America/Panama: [
+ Bogota
+ ],
+ America/Pangnirtung: [
+ Eastern Time (US & Canada)
+ ],
+ America/Paramaribo: [
+ America/Paramaribo
+ ],
+ America/Phoenix: [
+ Arizona
+ ],
+ America/Port-au-Prince: [
+ America/Port-au-Prince
+ ],
+ America/Port_of_Spain: [
+ Puerto Rico
+ ],
+ America/Porto_Acre: [
+ Bogota
+ ],
+ America/Porto_Velho: [
+ La Paz
+ ],
+ America/Puerto_Rico: [
+ Puerto Rico
+ ],
+ America/Punta_Arenas: [
+ America/Punta_Arenas
+ ],
+ America/Rainy_River: [
+ Central Time (US & Canada)
+ ],
+ America/Rankin_Inlet: [
+ Central Time (US & Canada)
+ ],
+ America/Recife: [
+ America/Recife
+ ],
+ America/Regina: [
+ Saskatchewan
+ ],
+ America/Resolute: [
+ Central Time (US & Canada)
+ ],
+ America/Rio_Branco: [
+ Bogota
+ ],
+ America/Rosario: [
+ Buenos Aires
+ ],
+ America/Santa_Isabel: [
+ Tijuana
+ ],
+ America/Santarem: [
+ America/Santarem
+ ],
+ America/Santiago: [
+ Santiago
+ ],
+ America/Santo_Domingo: [
+ La Paz
+ ],
+ America/Sao_Paulo: [
+ Brasilia
+ ],
+ America/Scoresbysund: [
+ Azores
+ ],
+ America/Shiprock: [
+ Mountain Time (US & Canada)
+ ],
+ America/Sitka: [
+ Alaska
+ ],
+ America/St_Barthelemy: [
+ Puerto Rico
+ ],
+ America/St_Johns: [
+ Newfoundland
+ ],
+ America/St_Kitts: [
+ Puerto Rico
+ ],
+ America/St_Lucia: [
+ Puerto Rico
+ ],
+ America/St_Thomas: [
+ Puerto Rico
+ ],
+ America/St_Vincent: [
+ Puerto Rico
+ ],
+ America/Swift_Current: [
+ Saskatchewan
+ ],
+ America/Tegucigalpa: [
+ Central America
+ ],
+ America/Thule: [
+ Atlantic Time (Canada)
+ ],
+ America/Thunder_Bay: [
+ Eastern Time (US & Canada)
+ ],
+ America/Tijuana: [
+ Tijuana
+ ],
+ America/Toronto: [
+ Eastern Time (US & Canada)
+ ],
+ America/Tortola: [
+ Puerto Rico
+ ],
+ America/Vancouver: [
+ Pacific Time (US & Canada)
+ ],
+ America/Virgin: [
+ Puerto Rico
+ ],
+ America/Whitehorse: [
+ America/Whitehorse
+ ],
+ America/Winnipeg: [
+ Central Time (US & Canada)
+ ],
+ America/Yakutat: [
+ Alaska
+ ],
+ America/Yellowknife: [
+ Mountain Time (US & Canada)
+ ],
+ Antarctica/Casey: [
+ Solomon Is.
+ ],
+ Antarctica/Davis: [
+ Bangkok,
+ Hanoi
+ ],
+ Antarctica/DumontDUrville: [
+ Port Moresby
+ ],
+ Antarctica/Macquarie: [
+ Hobart
+ ],
+ Antarctica/Mawson: [
+ Tashkent
+ ],
+ Antarctica/McMurdo: [
+ Auckland,
+ Wellington
+ ],
+ Antarctica/Palmer: [
+ Antarctica/Palmer
+ ],
+ Antarctica/Rothera: [
+ Antarctica/Rothera
+ ],
+ Antarctica/South_Pole: [
+ Auckland,
+ Wellington
+ ],
+ Antarctica/Syowa: [
+ Riyadh
+ ],
+ Antarctica/Troll: [
+ Antarctica/Troll
+ ],
+ Antarctica/Vostok: [
+ Antarctica/Vostok
+ ],
+ Arctic/Longyearbyen: [
+ Berlin
+ ],
+ Asia/Aden: [
+ Riyadh
+ ],
+ Asia/Almaty: [
+ Almaty,
+ Astana
+ ],
+ Asia/Amman: [
+ Asia/Amman
+ ],
+ Asia/Anadyr: [
+ Kamchatka
+ ],
+ Asia/Aqtau: [
+ Almaty,
+ Astana
+ ],
+ Asia/Aqtobe: [
+ Almaty,
+ Astana
+ ],
+ Asia/Ashgabat: [
+ Tashkent
+ ],
+ Asia/Ashkhabad: [
+ Tashkent
+ ],
+ Asia/Atyrau: [
+ Almaty,
+ Astana
+ ],
+ Asia/Baghdad: [
+ Baghdad
+ ],
+ Asia/Bahrain: [
+ Riyadh
+ ],
+ Asia/Baku: [
+ Baku
+ ],
+ Asia/Bangkok: [
+ Bangkok,
+ Hanoi
+ ],
+ Asia/Barnaul: [
+ Asia/Barnaul
+ ],
+ Asia/Beirut: [
+ Asia/Beirut
+ ],
+ Asia/Bishkek: [
+ Asia/Bishkek
+ ],
+ Asia/Brunei: [
+ Kuala Lumpur
+ ],
+ Asia/Calcutta: [
+ Chennai,
+ Kolkata,
+ Mumbai,
+ New Delhi
+ ],
+ Asia/Chita: [
+ Asia/Chita
+ ],
+ Asia/Choibalsan: [
+ Ulaanbaatar
+ ],
+ Asia/Chongqing: [
+ Chongqing
+ ],
+ Asia/Chungking: [
+ Beijing
+ ],
+ Asia/Colombo: [
+ Sri Jayawardenepura
+ ],
+ Asia/Dacca: [
+ Dhaka
+ ],
+ Asia/Damascus: [
+ Asia/Damascus
+ ],
+ Asia/Dhaka: [
+ Dhaka
+ ],
+ Asia/Dili: [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ Asia/Dubai: [
+ Abu Dhabi,
+ Muscat
+ ],
+ Asia/Dushanbe: [
+ Tashkent
+ ],
+ Asia/Famagusta: [
+ Bucharest
+ ],
+ Asia/Gaza: [
+ Asia/Gaza
+ ],
+ Asia/Harbin: [
+ Beijing
+ ],
+ Asia/Hebron: [
+ Asia/Hebron
+ ],
+ Asia/Ho_Chi_Minh: [
+ Bangkok,
+ Hanoi
+ ],
+ Asia/Hong_Kong: [
+ Hong Kong
+ ],
+ Asia/Hovd: [
+ Asia/Hovd
+ ],
+ Asia/Irkutsk: [
+ Irkutsk
+ ],
+ Asia/Istanbul: [
+ Istanbul
+ ],
+ Asia/Jakarta: [
+ Jakarta
+ ],
+ Asia/Jayapura: [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ Asia/Jerusalem: [
+ Jerusalem
+ ],
+ Asia/Kabul: [
+ Kabul
+ ],
+ Asia/Kamchatka: [
+ Kamchatka
+ ],
+ Asia/Karachi: [
+ Islamabad,
+ Karachi
+ ],
+ Asia/Kashgar: [
+ Urumqi
+ ],
+ Asia/Kathmandu: [
+ Kathmandu
+ ],
+ Asia/Katmandu: [
+ Kathmandu
+ ],
+ Asia/Khandyga: [
+ Yakutsk
+ ],
+ Asia/Kolkata: [
+ Chennai,
+ Kolkata,
+ Mumbai,
+ New Delhi
+ ],
+ Asia/Krasnoyarsk: [
+ Krasnoyarsk
+ ],
+ Asia/Kuala_Lumpur: [
+ Kuala Lumpur
+ ],
+ Asia/Kuching: [
+ Kuala Lumpur
+ ],
+ Asia/Kuwait: [
+ Kuwait
+ ],
+ Asia/Macao: [
+ Beijing
+ ],
+ Asia/Macau: [
+ Beijing
+ ],
+ Asia/Magadan: [
+ Magadan
+ ],
+ Asia/Makassar: [
+ Singapore
+ ],
+ Asia/Manila: [
+ Singapore
+ ],
+ Asia/Muscat: [
+ Abu Dhabi,
+ Muscat
+ ],
+ Asia/Nicosia: [
+ Bucharest
+ ],
+ Asia/Novokuznetsk: [
+ Krasnoyarsk
+ ],
+ Asia/Novosibirsk: [
+ Novosibirsk
+ ],
+ Asia/Omsk: [
+ Asia/Omsk
+ ],
+ Asia/Oral: [
+ Almaty,
+ Astana
+ ],
+ Asia/Phnom_Penh: [
+ Bangkok,
+ Hanoi
+ ],
+ Asia/Pontianak: [
+ Jakarta
+ ],
+ Asia/Pyongyang: [
+ Asia/Pyongyang
+ ],
+ Asia/Qatar: [
+ Riyadh
+ ],
+ Asia/Qostanay: [
+ Almaty,
+ Astana
+ ],
+ Asia/Qyzylorda: [
+ Asia/Qyzylorda
+ ],
+ Asia/Rangoon: [
+ Rangoon
+ ],
+ Asia/Riyadh: [
+ Riyadh
+ ],
+ Asia/Saigon: [
+ Bangkok,
+ Hanoi
+ ],
+ Asia/Sakhalin: [
+ Asia/Sakhalin
+ ],
+ Asia/Samarkand: [
+ Tashkent
+ ],
+ Asia/Seoul: [
+ Seoul
+ ],
+ Asia/Shanghai: [
+ Beijing
+ ],
+ Asia/Singapore: [
+ Singapore
+ ],
+ Asia/Srednekolymsk: [
+ Srednekolymsk
+ ],
+ Asia/Taipei: [
+ Taipei
+ ],
+ Asia/Tashkent: [
+ Tashkent
+ ],
+ Asia/Tbilisi: [
+ Tbilisi
+ ],
+ Asia/Tehran: [
+ Tehran
+ ],
+ Asia/Tel_Aviv: [
+ Jerusalem
+ ],
+ Asia/Thimbu: [
+ Dhaka
+ ],
+ Asia/Thimphu: [
+ Dhaka
+ ],
+ Asia/Tokyo: [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ Asia/Tomsk: [
+ Asia/Tomsk
+ ],
+ Asia/Ujung_Pandang: [
+ Singapore
+ ],
+ Asia/Ulaanbaatar: [
+ Ulaanbaatar
+ ],
+ Asia/Ulan_Bator: [
+ Ulaanbaatar
+ ],
+ Asia/Urumqi: [
+ Urumqi
+ ],
+ Asia/Ust-Nera: [
+ Vladivostok
+ ],
+ Asia/Vientiane: [
+ Bangkok,
+ Hanoi
+ ],
+ Asia/Vladivostok: [
+ Vladivostok
+ ],
+ Asia/Yakutsk: [
+ Yakutsk
+ ],
+ Asia/Yangon: [
+ Rangoon
+ ],
+ Asia/Yekaterinburg: [
+ Ekaterinburg
+ ],
+ Asia/Yerevan: [
+ Yerevan
+ ],
+ Atlantic/Azores: [
+ Azores
+ ],
+ Atlantic/Bermuda: [
+ Atlantic Time (Canada)
+ ],
+ Atlantic/Canary: [
+ Edinburgh,
+ London
+ ],
+ Atlantic/Cape_Verde: [
+ Cape Verde Is.
+ ],
+ Atlantic/Faeroe: [
+ Edinburgh,
+ London
+ ],
+ Atlantic/Faroe: [
+ Edinburgh,
+ London
+ ],
+ Atlantic/Jan_Mayen: [
+ Berlin
+ ],
+ Atlantic/Madeira: [
+ Lisbon
+ ],
+ Atlantic/Reykjavik: [
+ Atlantic/Reykjavik
+ ],
+ Atlantic/South_Georgia: [
+ Mid-Atlantic
+ ],
+ Atlantic/St_Helena: [
+ Atlantic/St_Helena
+ ],
+ Atlantic/Stanley: [
+ Atlantic/Stanley
+ ],
+ Australia/ACT: [
+ Sydney
+ ],
+ Australia/Adelaide: [
+ Adelaide
+ ],
+ Australia/Brisbane: [
+ Brisbane
+ ],
+ Australia/Broken_Hill: [
+ Adelaide
+ ],
+ Australia/Canberra: [
+ Canberra
+ ],
+ Australia/Currie: [
+ Hobart
+ ],
+ Australia/Darwin: [
+ Darwin
+ ],
+ Australia/Eucla: [
+ Australia/Eucla
+ ],
+ Australia/Hobart: [
+ Hobart
+ ],
+ Australia/LHI: [
+ Australia/LHI
+ ],
+ Australia/Lindeman: [
+ Brisbane
+ ],
+ Australia/Lord_Howe: [
+ Australia/Lord_Howe
+ ],
+ Australia/Melbourne: [
+ Melbourne
+ ],
+ Australia/NSW: [
+ Sydney
+ ],
+ Australia/North: [
+ Darwin
+ ],
+ Australia/Perth: [
+ Perth
+ ],
+ Australia/Queensland: [
+ Brisbane
+ ],
+ Australia/South: [
+ Adelaide
+ ],
+ Australia/Sydney: [
+ Sydney
+ ],
+ Australia/Tasmania: [
+ Hobart
+ ],
+ Australia/Victoria: [
+ Melbourne
+ ],
+ Australia/West: [
+ Perth
+ ],
+ Australia/Yancowinna: [
+ Adelaide
+ ],
+ Brazil/Acre: [
+ Bogota
+ ],
+ Brazil/DeNoronha: [
+ Brazil/DeNoronha
+ ],
+ Brazil/East: [
+ Brasilia
+ ],
+ Brazil/West: [
+ La Paz
+ ],
+ CET: [
+ Brussels
+ ],
+ CST6CDT: [
+ Central Time (US & Canada)
+ ],
+ Canada/Atlantic: [
+ Atlantic Time (Canada)
+ ],
+ Canada/Central: [
+ Central Time (US & Canada)
+ ],
+ Canada/Eastern: [
+ Eastern Time (US & Canada)
+ ],
+ Canada/Mountain: [
+ Mountain Time (US & Canada)
+ ],
+ Canada/Newfoundland: [
+ Newfoundland
+ ],
+ Canada/Pacific: [
+ Pacific Time (US & Canada)
+ ],
+ Canada/Saskatchewan: [
+ Saskatchewan
+ ],
+ Canada/Yukon: [
+ Canada/Yukon
+ ],
+ Chile/Continental: [
+ Santiago
+ ],
+ Chile/EasterIsland: [
+ Chile/EasterIsland
+ ],
+ Cuba: [
+ Cuba
+ ],
+ EET: [
+ Athens
+ ],
+ EST: [
+ Bogota
+ ],
+ EST5EDT: [
+ Eastern Time (US & Canada)
+ ],
+ Egypt: [
+ Cairo
+ ],
+ Eire: [
+ Dublin
+ ],
+ Etc/GMT: [
+ UTC
+ ],
+ Etc/GMT+0: [
+ UTC
+ ],
+ Etc/GMT+1: [
+ Cape Verde Is.
+ ],
+ Etc/GMT+10: [
+ -10:00
+ ],
+ Etc/GMT+11: [
+ -11:00
+ ],
+ Etc/GMT+12: [
+ -12:00
+ ],
+ Etc/GMT+2: [
+ Etc/GMT+2
+ ],
+ Etc/GMT+3: [
+ Etc/GMT+3
+ ],
+ Etc/GMT+4: [
+ La Paz
+ ],
+ Etc/GMT+5: [
+ Bogota
+ ],
+ Etc/GMT+6: [
+ Central America
+ ],
+ Etc/GMT+7: [
+ Arizona
+ ],
+ Etc/GMT+8: [
+ Etc/GMT+8
+ ],
+ Etc/GMT+9: [
+ Etc/GMT+9
+ ],
+ Etc/GMT-0: [
+ UTC
+ ],
+ Etc/GMT-1: [
+ Etc/GMT-1
+ ],
+ Etc/GMT-10: [
+ +10:00
+ ],
+ Etc/GMT-11: [
+ +11:00
+ ],
+ Etc/GMT-12: [
+ +12:00
+ ],
+ Etc/GMT-13: [
+ +13:00
+ ],
+ Etc/GMT-14: [
+ +14:00
+ ],
+ Etc/GMT-2: [
+ Pretoria
+ ],
+ Etc/GMT-3: [
+ Nairobi
+ ],
+ Etc/GMT-4: [
+ Abu Dhabi,
+ Muscat
+ ],
+ Etc/GMT-5: [
+ Tashkent
+ ],
+ Etc/GMT-6: [
+ Etc/GMT-6
+ ],
+ Etc/GMT-7: [
+ Bangkok,
+ Hanoi
+ ],
+ Etc/GMT-8: [
+ Singapore
+ ],
+ Etc/GMT-9: [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ Etc/GMT0: [
+ UTC
+ ],
+ Etc/Greenwich: [
+ UTC
+ ],
+ Etc/UCT: [
+ UTC
+ ],
+ Etc/UTC: [
+ UTC
+ ],
+ Etc/Universal: [
+ UTC
+ ],
+ Etc/Zulu: [
+ UTC
+ ],
+ Europe/Amsterdam: [
+ Amsterdam
+ ],
+ Europe/Andorra: [
+ Berlin
+ ],
+ Europe/Astrakhan: [
+ Europe/Astrakhan
+ ],
+ Europe/Athens: [
+ Athens
+ ],
+ Europe/Belfast: [
+ Edinburgh,
+ London
+ ],
+ Europe/Belgrade: [
+ Belgrade
+ ],
+ Europe/Berlin: [
+ Berlin
+ ],
+ Europe/Bratislava: [
+ Bratislava
+ ],
+ Europe/Brussels: [
+ Brussels
+ ],
+ Europe/Bucharest: [
+ Bucharest
+ ],
+ Europe/Budapest: [
+ Budapest
+ ],
+ Europe/Busingen: [
+ Bern,
+ Zurich
+ ],
+ Europe/Chisinau: [
+ Europe/Chisinau
+ ],
+ Europe/Copenhagen: [
+ Copenhagen
+ ],
+ Europe/Dublin: [
+ Dublin
+ ],
+ Europe/Gibraltar: [
+ Berlin
+ ],
+ Europe/Guernsey: [
+ Edinburgh,
+ London
+ ],
+ Europe/Helsinki: [
+ Helsinki
+ ],
+ Europe/Isle_of_Man: [
+ Edinburgh,
+ London
+ ],
+ Europe/Istanbul: [
+ Istanbul
+ ],
+ Europe/Jersey: [
+ Edinburgh,
+ London
+ ],
+ Europe/Kaliningrad: [
+ Kaliningrad
+ ],
+ Europe/Kiev: [
+ Kyiv
+ ],
+ Europe/Kirov: [
+ Moscow,
+ St. Petersburg
+ ],
+ Europe/Kyiv: [
+ Kyiv
+ ],
+ Europe/Lisbon: [
+ Lisbon
+ ],
+ Europe/Ljubljana: [
+ Ljubljana
+ ],
+ Europe/London: [
+ Edinburgh,
+ London
+ ],
+ Europe/Luxembourg: [
+ Brussels
+ ],
+ Europe/Madrid: [
+ Madrid
+ ],
+ Europe/Malta: [
+ Berlin
+ ],
+ Europe/Mariehamn: [
+ Helsinki
+ ],
+ Europe/Minsk: [
+ Minsk
+ ],
+ Europe/Monaco: [
+ Paris
+ ],
+ Europe/Moscow: [
+ Moscow,
+ St. Petersburg
+ ],
+ Europe/Nicosia: [
+ Bucharest
+ ],
+ Europe/Oslo: [
+ Berlin
+ ],
+ Europe/Paris: [
+ Paris
+ ],
+ Europe/Podgorica: [
+ Belgrade
+ ],
+ Europe/Prague: [
+ Prague
+ ],
+ Europe/Riga: [
+ Riga
+ ],
+ Europe/Rome: [
+ Rome
+ ],
+ Europe/Samara: [
+ Samara
+ ],
+ Europe/San_Marino: [
+ Rome
+ ],
+ Europe/Sarajevo: [
+ Sarajevo
+ ],
+ Europe/Saratov: [
+ Europe/Saratov
+ ],
+ Europe/Simferopol: [
+ Moscow,
+ St. Petersburg
+ ],
+ Europe/Skopje: [
+ Skopje
+ ],
+ Europe/Sofia: [
+ Sofia
+ ],
+ Europe/Stockholm: [
+ Stockholm
+ ],
+ Europe/Tallinn: [
+ Tallinn
+ ],
+ Europe/Tirane: [
+ Budapest
+ ],
+ Europe/Tiraspol: [
+ Europe/Tiraspol
+ ],
+ Europe/Ulyanovsk: [
+ Europe/Ulyanovsk
+ ],
+ Europe/Uzhgorod: [
+ Kyiv
+ ],
+ Europe/Vaduz: [
+ Bern,
+ Zurich
+ ],
+ Europe/Vatican: [
+ Rome
+ ],
+ Europe/Vienna: [
+ Vienna
+ ],
+ Europe/Vilnius: [
+ Vilnius
+ ],
+ Europe/Volgograd: [
+ Volgograd
+ ],
+ Europe/Warsaw: [
+ Warsaw
+ ],
+ Europe/Zagreb: [
+ Zagreb
+ ],
+ Europe/Zaporozhye: [
+ Kyiv
+ ],
+ Europe/Zurich: [
+ Bern,
+ Zurich
+ ],
+ GB: [
+ Edinburgh,
+ London
+ ],
+ GB-Eire: [
+ Edinburgh,
+ London
+ ],
+ GMT: [
+ UTC
+ ],
+ GMT+0: [
+ UTC
+ ],
+ GMT-0: [
+ UTC
+ ],
+ GMT0: [
+ UTC
+ ],
+ Greenwich: [
+ UTC
+ ],
+ HST: [
+ Hawaii
+ ],
+ Hongkong: [
+ Hong Kong
+ ],
+ Iceland: [
+ Iceland
+ ],
+ Indian/Antananarivo: [
+ Nairobi
+ ],
+ Indian/Chagos: [
+ Indian/Chagos
+ ],
+ Indian/Christmas: [
+ Bangkok,
+ Hanoi
+ ],
+ Indian/Cocos: [
+ Rangoon
+ ],
+ Indian/Comoro: [
+ Nairobi
+ ],
+ Indian/Kerguelen: [
+ Tashkent
+ ],
+ Indian/Mahe: [
+ Abu Dhabi,
+ Muscat
+ ],
+ Indian/Maldives: [
+ Tashkent
+ ],
+ Indian/Mauritius: [
+ Indian/Mauritius
+ ],
+ Indian/Mayotte: [
+ Nairobi
+ ],
+ Indian/Reunion: [
+ Abu Dhabi,
+ Muscat
+ ],
+ Iran: [
+ Tehran
+ ],
+ Israel: [
+ Jerusalem
+ ],
+ Jamaica: [
+ Bogota
+ ],
+ Japan: [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ Kwajalein: [
+ Marshall Is.
+ ],
+ Libya: [
+ Libya
+ ],
+ MET: [
+ Brussels
+ ],
+ MST: [
+ Arizona
+ ],
+ MST7MDT: [
+ Mountain Time (US & Canada)
+ ],
+ Mexico/BajaNorte: [
+ Tijuana
+ ],
+ Mexico/BajaSur: [
+ Mazatlan
+ ],
+ Mexico/General: [
+ Guadalajara,
+ Mexico City
+ ],
+ NZ: [
+ Auckland,
+ Wellington
+ ],
+ NZ-CHAT: [
+ Chatham Is.
+ ],
+ Navajo: [
+ Mountain Time (US & Canada)
+ ],
+ PRC: [
+ Beijing
+ ],
+ PST8PDT: [
+ Pacific Time (US & Canada)
+ ],
+ Pacific/Apia: [
+ Samoa
+ ],
+ Pacific/Auckland: [
+ Auckland,
+ Wellington
+ ],
+ Pacific/Bougainville: [
+ Pacific/Bougainville
+ ],
+ Pacific/Chatham: [
+ Chatham Is.
+ ],
+ Pacific/Chuuk: [
+ Port Moresby
+ ],
+ Pacific/Easter: [
+ Pacific/Easter
+ ],
+ Pacific/Efate: [
+ Solomon Is.
+ ],
+ Pacific/Enderbury: [
+ Pacific/Enderbury
+ ],
+ Pacific/Fakaofo: [
+ Tokelau Is.
+ ],
+ Pacific/Fiji: [
+ Fiji
+ ],
+ Pacific/Funafuti: [
+ Pacific/Funafuti
+ ],
+ Pacific/Galapagos: [
+ Central America
+ ],
+ Pacific/Gambier: [
+ Pacific/Gambier
+ ],
+ Pacific/Guadalcanal: [
+ Solomon Is.
+ ],
+ Pacific/Guam: [
+ Guam
+ ],
+ Pacific/Honolulu: [
+ Hawaii
+ ],
+ Pacific/Johnston: [
+ Hawaii
+ ],
+ Pacific/Kanton: [
+ Pacific/Kanton
+ ],
+ Pacific/Kiritimati: [
+ Pacific/Kiritimati
+ ],
+ Pacific/Kosrae: [
+ Solomon Is.
+ ],
+ Pacific/Kwajalein: [
+ Marshall Is.
+ ],
+ Pacific/Majuro: [
+ Marshall Is.
+ ],
+ Pacific/Marquesas: [
+ Pacific/Marquesas
+ ],
+ Pacific/Midway: [
+ Midway Island
+ ],
+ Pacific/Nauru: [
+ Pacific/Nauru
+ ],
+ Pacific/Niue: [
+ Pacific/Niue
+ ],
+ Pacific/Norfolk: [
+ Pacific/Norfolk
+ ],
+ Pacific/Noumea: [
+ New Caledonia
+ ],
+ Pacific/Pago_Pago: [
+ American Samoa
+ ],
+ Pacific/Palau: [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ Pacific/Pitcairn: [
+ Pacific/Pitcairn
+ ],
+ Pacific/Pohnpei: [
+ Solomon Is.
+ ],
+ Pacific/Ponape: [
+ Solomon Is.
+ ],
+ Pacific/Port_Moresby: [
+ Port Moresby
+ ],
+ Pacific/Rarotonga: [
+ Hawaii
+ ],
+ Pacific/Saipan: [
+ Guam
+ ],
+ Pacific/Samoa: [
+ American Samoa
+ ],
+ Pacific/Tahiti: [
+ Hawaii
+ ],
+ Pacific/Tarawa: [
+ Marshall Is.
+ ],
+ Pacific/Tongatapu: [
+ Nuku'alofa
+ ],
+ Pacific/Truk: [
+ Port Moresby
+ ],
+ Pacific/Wake: [
+ Marshall Is.
+ ],
+ Pacific/Wallis: [
+ Marshall Is.
+ ],
+ Pacific/Yap: [
+ Port Moresby
+ ],
+ Poland: [
+ Warsaw
+ ],
+ Portugal: [
+ Lisbon
+ ],
+ ROC: [
+ Taipei
+ ],
+ ROK: [
+ Seoul
+ ],
+ Singapore: [
+ Singapore
+ ],
+ Turkey: [
+ Istanbul
+ ],
+ UCT: [
+ UTC
+ ],
+ US/Alaska: [
+ Alaska
+ ],
+ US/Aleutian: [
+ US/Aleutian
+ ],
+ US/Arizona: [
+ Arizona
+ ],
+ US/Central: [
+ Central Time (US & Canada)
+ ],
+ US/East-Indiana: [
+ Indiana (East)
+ ],
+ US/Eastern: [
+ Eastern Time (US & Canada)
+ ],
+ US/Hawaii: [
+ Hawaii
+ ],
+ US/Indiana-Starke: [
+ Central Time (US & Canada)
+ ],
+ US/Michigan: [
+ Eastern Time (US & Canada)
+ ],
+ US/Mountain: [
+ Mountain Time (US & Canada)
+ ],
+ US/Pacific: [
+ Pacific Time (US & Canada)
+ ],
+ US/Samoa: [
+ American Samoa
+ ],
+ UTC: [
+ UTC
+ ],
+ Universal: [
+ UTC
+ ],
+ W-SU: [
+ Moscow,
+ St. Petersburg
+ ],
+ WET: [
+ Lisbon
+ ],
+ Zulu: [
+ UTC
+ ]
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Rails_To_Iana.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Rails_To_Iana.verified.txt
new file mode 100644
index 0000000..8641e9d
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Rails_To_Iana.verified.txt
@@ -0,0 +1,154 @@
+{
+ Abu Dhabi: Asia/Muscat,
+ Adelaide: Australia/Adelaide,
+ Alaska: America/Juneau,
+ Almaty: Asia/Almaty,
+ American Samoa: Pacific/Pago_Pago,
+ Amsterdam: Europe/Amsterdam,
+ Arizona: America/Phoenix,
+ Astana: Asia/Almaty,
+ Asuncion: America/Asuncion,
+ Athens: Europe/Athens,
+ Atlantic Time (Canada): America/Halifax,
+ Auckland: Pacific/Auckland,
+ Azores: Atlantic/Azores,
+ Baghdad: Asia/Baghdad,
+ Baku: Asia/Baku,
+ Bangkok: Asia/Bangkok,
+ Beijing: Asia/Shanghai,
+ Belgrade: Europe/Belgrade,
+ Berlin: Europe/Berlin,
+ Bern: Europe/Zurich,
+ Bogota: America/Bogota,
+ Brasilia: America/Sao_Paulo,
+ Bratislava: Europe/Bratislava,
+ Brisbane: Australia/Brisbane,
+ Brussels: Europe/Brussels,
+ Bucharest: Europe/Bucharest,
+ Budapest: Europe/Budapest,
+ Buenos Aires: America/Argentina/Buenos_Aires,
+ Cairo: Africa/Cairo,
+ Canberra: Australia/Canberra,
+ Cape Verde Is.: Atlantic/Cape_Verde,
+ Caracas: America/Caracas,
+ Casablanca: Africa/Casablanca,
+ Central America: America/Guatemala,
+ Central Time (US & Canada): America/Chicago,
+ Chatham Is.: Pacific/Chatham,
+ Chennai: Asia/Kolkata,
+ Chihuahua: America/Chihuahua,
+ Chongqing: Asia/Chongqing,
+ Copenhagen: Europe/Copenhagen,
+ Darwin: Australia/Darwin,
+ Dhaka: Asia/Dhaka,
+ Dublin: Europe/Dublin,
+ Eastern Time (US & Canada): America/New_York,
+ Edinburgh: Europe/London,
+ Ekaterinburg: Asia/Yekaterinburg,
+ Fiji: Pacific/Fiji,
+ Georgetown: America/Guyana,
+ Greenland: America/Nuuk,
+ Guadalajara: America/Mexico_City,
+ Guam: Pacific/Guam,
+ Hanoi: Asia/Bangkok,
+ Harare: Africa/Harare,
+ Hawaii: Pacific/Honolulu,
+ Helsinki: Europe/Helsinki,
+ Hobart: Australia/Hobart,
+ Hong Kong: Asia/Hong_Kong,
+ Indiana (East): America/Indiana/Indianapolis,
+ International Date Line West: Etc/GMT+12,
+ Irkutsk: Asia/Irkutsk,
+ Islamabad: Asia/Karachi,
+ Istanbul: Europe/Istanbul,
+ Jakarta: Asia/Jakarta,
+ Jerusalem: Asia/Jerusalem,
+ Kabul: Asia/Kabul,
+ Kaliningrad: Europe/Kaliningrad,
+ Kamchatka: Asia/Kamchatka,
+ Karachi: Asia/Karachi,
+ Kathmandu: Asia/Kathmandu,
+ Kolkata: Asia/Kolkata,
+ Krasnoyarsk: Asia/Krasnoyarsk,
+ Kuala Lumpur: Asia/Kuala_Lumpur,
+ Kuwait: Asia/Kuwait,
+ Kyiv: Europe/Kiev,
+ La Paz: America/La_Paz,
+ Lima: America/Lima,
+ Lisbon: Europe/Lisbon,
+ Ljubljana: Europe/Ljubljana,
+ London: Europe/London,
+ Madrid: Europe/Madrid,
+ Magadan: Asia/Magadan,
+ Marshall Is.: Pacific/Majuro,
+ Mazatlan: America/Mazatlan,
+ Melbourne: Australia/Melbourne,
+ Mexico City: America/Mexico_City,
+ Mid-Atlantic: Atlantic/South_Georgia,
+ Midway Island: Pacific/Midway,
+ Minsk: Europe/Minsk,
+ Monrovia: Africa/Monrovia,
+ Monterrey: America/Monterrey,
+ Montevideo: America/Montevideo,
+ Moscow: Europe/Moscow,
+ Mountain Time (US & Canada): America/Denver,
+ Mumbai: Asia/Kolkata,
+ Muscat: Asia/Muscat,
+ Nairobi: Africa/Nairobi,
+ New Caledonia: Pacific/Noumea,
+ New Delhi: Asia/Kolkata,
+ Newfoundland: America/St_Johns,
+ Novosibirsk: Asia/Novosibirsk,
+ Nuku'alofa: Pacific/Tongatapu,
+ Osaka: Asia/Tokyo,
+ Pacific Time (US & Canada): America/Los_Angeles,
+ Paris: Europe/Paris,
+ Perth: Australia/Perth,
+ Port Moresby: Pacific/Port_Moresby,
+ Prague: Europe/Prague,
+ Pretoria: Africa/Johannesburg,
+ Puerto Rico: America/Puerto_Rico,
+ Quito: America/Lima,
+ Rangoon: Asia/Rangoon,
+ Riga: Europe/Riga,
+ Riyadh: Asia/Riyadh,
+ Rome: Europe/Rome,
+ Samara: Europe/Samara,
+ Samoa: Pacific/Apia,
+ Santiago: America/Santiago,
+ Sapporo: Asia/Tokyo,
+ Sarajevo: Europe/Sarajevo,
+ Saskatchewan: America/Regina,
+ Seoul: Asia/Seoul,
+ Singapore: Asia/Singapore,
+ Skopje: Europe/Skopje,
+ Sofia: Europe/Sofia,
+ Solomon Is.: Pacific/Guadalcanal,
+ Srednekolymsk: Asia/Srednekolymsk,
+ Sri Jayawardenepura: Asia/Colombo,
+ St. Petersburg: Europe/Moscow,
+ Stockholm: Europe/Stockholm,
+ Sydney: Australia/Sydney,
+ Taipei: Asia/Taipei,
+ Tallinn: Europe/Tallinn,
+ Tashkent: Asia/Tashkent,
+ Tbilisi: Asia/Tbilisi,
+ Tehran: Asia/Tehran,
+ Tijuana: America/Tijuana,
+ Tokelau Is.: Pacific/Fakaofo,
+ Tokyo: Asia/Tokyo,
+ UTC: Etc/UTC,
+ Ulaanbaatar: Asia/Ulaanbaatar,
+ Urumqi: Asia/Urumqi,
+ Vienna: Europe/Vienna,
+ Vilnius: Europe/Vilnius,
+ Vladivostok: Asia/Vladivostok,
+ Volgograd: Europe/Volgograd,
+ Warsaw: Europe/Warsaw,
+ Wellington: Pacific/Auckland,
+ West Central Africa: Africa/Algiers,
+ Yakutsk: Asia/Yakutsk,
+ Yerevan: Asia/Yerevan,
+ Zagreb: Europe/Zagreb,
+ Zurich: Europe/Zurich
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Rails_To_Windows.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Rails_To_Windows.verified.txt
new file mode 100644
index 0000000..88a34fd
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Rails_To_Windows.verified.txt
@@ -0,0 +1,154 @@
+{
+ Abu Dhabi: Arabian Standard Time,
+ Adelaide: Cen. Australia Standard Time,
+ Alaska: Alaskan Standard Time,
+ Almaty: West Asia Standard Time,
+ American Samoa: UTC-11,
+ Amsterdam: W. Europe Standard Time,
+ Arizona: US Mountain Standard Time,
+ Astana: West Asia Standard Time,
+ Asuncion: Paraguay Standard Time,
+ Athens: GTB Standard Time,
+ Atlantic Time (Canada): Atlantic Standard Time,
+ Auckland: New Zealand Standard Time,
+ Azores: Azores Standard Time,
+ Baghdad: Arabic Standard Time,
+ Baku: Azerbaijan Standard Time,
+ Bangkok: SE Asia Standard Time,
+ Beijing: China Standard Time,
+ Belgrade: Central Europe Standard Time,
+ Berlin: W. Europe Standard Time,
+ Bern: W. Europe Standard Time,
+ Bogota: SA Pacific Standard Time,
+ Brasilia: E. South America Standard Time,
+ Bratislava: Central Europe Standard Time,
+ Brisbane: E. Australia Standard Time,
+ Brussels: Romance Standard Time,
+ Bucharest: GTB Standard Time,
+ Budapest: Central Europe Standard Time,
+ Buenos Aires: Argentina Standard Time,
+ Cairo: Egypt Standard Time,
+ Canberra: AUS Eastern Standard Time,
+ Cape Verde Is.: Cape Verde Standard Time,
+ Caracas: Venezuela Standard Time,
+ Casablanca: Morocco Standard Time,
+ Central America: Central America Standard Time,
+ Central Time (US & Canada): Central Standard Time,
+ Chatham Is.: Chatham Islands Standard Time,
+ Chennai: India Standard Time,
+ Chihuahua: Central Standard Time (Mexico),
+ Chongqing: China Standard Time,
+ Copenhagen: Romance Standard Time,
+ Darwin: AUS Central Standard Time,
+ Dhaka: Bangladesh Standard Time,
+ Dublin: GMT Standard Time,
+ Eastern Time (US & Canada): Eastern Standard Time,
+ Edinburgh: GMT Standard Time,
+ Ekaterinburg: Ekaterinburg Standard Time,
+ Fiji: Fiji Standard Time,
+ Georgetown: SA Western Standard Time,
+ Greenland: Greenland Standard Time,
+ Guadalajara: Central Standard Time (Mexico),
+ Guam: West Pacific Standard Time,
+ Hanoi: SE Asia Standard Time,
+ Harare: South Africa Standard Time,
+ Hawaii: Hawaiian Standard Time,
+ Helsinki: FLE Standard Time,
+ Hobart: Tasmania Standard Time,
+ Hong Kong: China Standard Time,
+ Indiana (East): US Eastern Standard Time,
+ International Date Line West: Dateline Standard Time,
+ Irkutsk: North Asia East Standard Time,
+ Islamabad: Pakistan Standard Time,
+ Istanbul: Turkey Standard Time,
+ Jakarta: SE Asia Standard Time,
+ Jerusalem: Israel Standard Time,
+ Kabul: Afghanistan Standard Time,
+ Kaliningrad: Kaliningrad Standard Time,
+ Kamchatka: Russia Time Zone 11,
+ Karachi: Pakistan Standard Time,
+ Kathmandu: Nepal Standard Time,
+ Kolkata: India Standard Time,
+ Krasnoyarsk: North Asia Standard Time,
+ Kuala Lumpur: Singapore Standard Time,
+ Kuwait: Arab Standard Time,
+ Kyiv: FLE Standard Time,
+ La Paz: SA Western Standard Time,
+ Lima: SA Pacific Standard Time,
+ Lisbon: GMT Standard Time,
+ Ljubljana: Central Europe Standard Time,
+ London: GMT Standard Time,
+ Madrid: Romance Standard Time,
+ Magadan: Magadan Standard Time,
+ Marshall Is.: UTC+12,
+ Mazatlan: Mountain Standard Time (Mexico),
+ Melbourne: AUS Eastern Standard Time,
+ Mexico City: Central Standard Time (Mexico),
+ Mid-Atlantic: UTC-02,
+ Midway Island: UTC-11,
+ Minsk: Belarus Standard Time,
+ Monrovia: Greenwich Standard Time,
+ Monterrey: Central Standard Time (Mexico),
+ Montevideo: Montevideo Standard Time,
+ Moscow: Russian Standard Time,
+ Mountain Time (US & Canada): Mountain Standard Time,
+ Mumbai: India Standard Time,
+ Muscat: Arabian Standard Time,
+ Nairobi: E. Africa Standard Time,
+ New Caledonia: Central Pacific Standard Time,
+ New Delhi: India Standard Time,
+ Newfoundland: Newfoundland Standard Time,
+ Novosibirsk: N. Central Asia Standard Time,
+ Nuku'alofa: Tonga Standard Time,
+ Osaka: Tokyo Standard Time,
+ Pacific Time (US & Canada): Pacific Standard Time,
+ Paris: Romance Standard Time,
+ Perth: W. Australia Standard Time,
+ Port Moresby: West Pacific Standard Time,
+ Prague: Central Europe Standard Time,
+ Pretoria: South Africa Standard Time,
+ Puerto Rico: SA Western Standard Time,
+ Quito: SA Pacific Standard Time,
+ Rangoon: Myanmar Standard Time,
+ Riga: FLE Standard Time,
+ Riyadh: Arab Standard Time,
+ Rome: W. Europe Standard Time,
+ Samara: Russia Time Zone 3,
+ Samoa: Samoa Standard Time,
+ Santiago: Pacific SA Standard Time,
+ Sapporo: Tokyo Standard Time,
+ Sarajevo: Central European Standard Time,
+ Saskatchewan: Canada Central Standard Time,
+ Seoul: Korea Standard Time,
+ Singapore: Singapore Standard Time,
+ Skopje: Central European Standard Time,
+ Sofia: FLE Standard Time,
+ Solomon Is.: Central Pacific Standard Time,
+ Srednekolymsk: Russia Time Zone 10,
+ Sri Jayawardenepura: Sri Lanka Standard Time,
+ St. Petersburg: Russian Standard Time,
+ Stockholm: W. Europe Standard Time,
+ Sydney: AUS Eastern Standard Time,
+ Taipei: Taipei Standard Time,
+ Tallinn: FLE Standard Time,
+ Tashkent: West Asia Standard Time,
+ Tbilisi: Georgian Standard Time,
+ Tehran: Iran Standard Time,
+ Tijuana: Pacific Standard Time (Mexico),
+ Tokelau Is.: UTC+13,
+ Tokyo: Tokyo Standard Time,
+ UTC: UTC,
+ Ulaanbaatar: Ulaanbaatar Standard Time,
+ Urumqi: Central Asia Standard Time,
+ Vienna: W. Europe Standard Time,
+ Vilnius: FLE Standard Time,
+ Vladivostok: Vladivostok Standard Time,
+ Volgograd: Volgograd Standard Time,
+ Warsaw: Central European Standard Time,
+ Wellington: New Zealand Standard Time,
+ West Central Africa: W. Central Africa Standard Time,
+ Yakutsk: Yakutsk Standard Time,
+ Yerevan: Caucasus Standard Time,
+ Zagreb: Central European Standard Time,
+ Zurich: W. Europe Standard Time
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Canonical.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Canonical.verified.txt
new file mode 100644
index 0000000..951a575
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Canonical.verified.txt
@@ -0,0 +1,290 @@
+{
+ (AUS Central Standard Time, 001): Australia/Darwin,
+ (AUS Eastern Standard Time, 001): Australia/Sydney,
+ (Afghanistan Standard Time, 001): Asia/Kabul,
+ (Alaskan Standard Time, 001): America/Anchorage,
+ (Aleutian Standard Time, 001): America/Adak,
+ (Altai Standard Time, 001): Asia/Barnaul,
+ (Arab Standard Time, 001): Asia/Riyadh,
+ (Arab Standard Time, BH): Asia/Qatar,
+ (Arab Standard Time, QA): Asia/Qatar,
+ (Arabian Standard Time, 001): Asia/Dubai,
+ (Arabic Standard Time, 001): Asia/Baghdad,
+ (Argentina Standard Time, 001): America/Argentina/Buenos_Aires,
+ (Astrakhan Standard Time, 001): Europe/Astrakhan,
+ (Atlantic Standard Time, 001): America/Halifax,
+ (Atlantic Standard Time, BM): Atlantic/Bermuda,
+ (Atlantic Standard Time, GL): America/Thule,
+ (Aus Central W. Standard Time, 001): Australia/Eucla,
+ (Azerbaijan Standard Time, 001): Asia/Baku,
+ (Azores Standard Time, 001): Atlantic/Azores,
+ (Azores Standard Time, GL): America/Scoresbysund,
+ (Bahia Standard Time, 001): America/Bahia,
+ (Bangladesh Standard Time, 001): Asia/Dhaka,
+ (Bangladesh Standard Time, BT): Asia/Thimphu,
+ (Belarus Standard Time, 001): Europe/Minsk,
+ (Bougainville Standard Time, 001): Pacific/Bougainville,
+ (Canada Central Standard Time, 001): America/Regina,
+ (Cape Verde Standard Time, 001): Atlantic/Cape_Verde,
+ (Caucasus Standard Time, 001): Asia/Yerevan,
+ (Cen. Australia Standard Time, 001): Australia/Adelaide,
+ (Central America Standard Time, 001): America/Guatemala,
+ (Central America Standard Time, BZ): America/Belize,
+ (Central America Standard Time, CR): America/Costa_Rica,
+ (Central America Standard Time, EC): Pacific/Galapagos,
+ (Central America Standard Time, HN): America/Tegucigalpa,
+ (Central America Standard Time, NI): America/Managua,
+ (Central America Standard Time, SV): America/El_Salvador,
+ (Central Asia Standard Time, 001): Asia/Bishkek,
+ (Central Asia Standard Time, CN): Asia/Urumqi,
+ (Central Asia Standard Time, DG): Indian/Chagos,
+ (Central Asia Standard Time, IO): Indian/Chagos,
+ (Central Brazilian Standard Time, 001): America/Cuiaba,
+ (Central Europe Standard Time, 001): Europe/Budapest,
+ (Central Europe Standard Time, AL): Europe/Tirane,
+ (Central Europe Standard Time, CZ): Europe/Prague,
+ (Central Europe Standard Time, ME): Europe/Belgrade,
+ (Central Europe Standard Time, RS): Europe/Belgrade,
+ (Central Europe Standard Time, SI): Europe/Belgrade,
+ (Central Europe Standard Time, SK): Europe/Prague,
+ (Central Europe Standard Time, XK): Europe/Belgrade,
+ (Central European Standard Time, 001): Europe/Warsaw,
+ (Central European Standard Time, BA): Europe/Belgrade,
+ (Central European Standard Time, HR): Europe/Belgrade,
+ (Central European Standard Time, MK): Europe/Belgrade,
+ (Central Pacific Standard Time, 001): Pacific/Guadalcanal,
+ (Central Pacific Standard Time, NC): Pacific/Noumea,
+ (Central Pacific Standard Time, VU): Pacific/Efate,
+ (Central Standard Time (Mexico), 001): America/Mexico_City,
+ (Central Standard Time, 001): America/Chicago,
+ (Central Standard Time, CA): America/Winnipeg,
+ (Central Standard Time, MX): America/Matamoros,
+ (Chatham Islands Standard Time, 001): Pacific/Chatham,
+ (China Standard Time, 001): Asia/Shanghai,
+ (China Standard Time, HK): Asia/Hong_Kong,
+ (China Standard Time, MO): Asia/Macau,
+ (Cuba Standard Time, 001): America/Havana,
+ (Dateline Standard Time, 001): Etc/GMT+12,
+ (E. Africa Standard Time, 001): Africa/Nairobi,
+ (E. Australia Standard Time, 001): Australia/Brisbane,
+ (E. Europe Standard Time, 001): Europe/Chisinau,
+ (E. South America Standard Time, 001): America/Sao_Paulo,
+ (Easter Island Standard Time, 001): Pacific/Easter,
+ (Eastern Standard Time (Mexico), 001): America/Cancun,
+ (Eastern Standard Time, 001): America/New_York,
+ (Eastern Standard Time, BS): America/Toronto,
+ (Eastern Standard Time, CA): America/Toronto,
+ (Egypt Standard Time, 001): Africa/Cairo,
+ (Ekaterinburg Standard Time, 001): Asia/Yekaterinburg,
+ (FLE Standard Time, 001): Europe/Kyiv,
+ (FLE Standard Time, AX): Europe/Helsinki,
+ (FLE Standard Time, BG): Europe/Sofia,
+ (FLE Standard Time, EE): Europe/Tallinn,
+ (FLE Standard Time, FI): Europe/Helsinki,
+ (FLE Standard Time, LT): Europe/Vilnius,
+ (FLE Standard Time, LV): Europe/Riga,
+ (Fiji Standard Time, 001): Pacific/Fiji,
+ (GMT Standard Time, 001): Europe/London,
+ (GMT Standard Time, ES): Atlantic/Canary,
+ (GMT Standard Time, FO): Atlantic/Faroe,
+ (GMT Standard Time, IC): Atlantic/Canary,
+ (GMT Standard Time, IE): Europe/Dublin,
+ (GMT Standard Time, PT): Europe/Lisbon,
+ (GTB Standard Time, 001): Europe/Bucharest,
+ (GTB Standard Time, CY): Asia/Nicosia,
+ (GTB Standard Time, GR): Europe/Athens,
+ (Georgian Standard Time, 001): Asia/Tbilisi,
+ (Greenland Standard Time, 001): America/Nuuk,
+ (Greenwich Standard Time, 001): Africa/Abidjan,
+ (Greenwich Standard Time, GL): America/Danmarkshavn,
+ (Greenwich Standard Time, GW): Africa/Bissau,
+ (Greenwich Standard Time, LR): Africa/Monrovia,
+ (Haiti Standard Time, 001): America/Port-au-Prince,
+ (Hawaiian Standard Time, 001): Pacific/Honolulu,
+ (Hawaiian Standard Time, CK): Pacific/Rarotonga,
+ (Hawaiian Standard Time, PF): Pacific/Tahiti,
+ (India Standard Time, 001): Asia/Kolkata,
+ (Iran Standard Time, 001): Asia/Tehran,
+ (Israel Standard Time, 001): Asia/Jerusalem,
+ (Jordan Standard Time, 001): Asia/Amman,
+ (Kaliningrad Standard Time, 001): Europe/Kaliningrad,
+ (Korea Standard Time, 001): Asia/Seoul,
+ (Libya Standard Time, 001): Africa/Tripoli,
+ (Line Islands Standard Time, 001): Pacific/Kiritimati,
+ (Lord Howe Standard Time, 001): Australia/Lord_Howe,
+ (Magadan Standard Time, 001): Asia/Magadan,
+ (Magallanes Standard Time, 001): America/Punta_Arenas,
+ (Marquesas Standard Time, 001): Pacific/Marquesas,
+ (Mauritius Standard Time, 001): Indian/Mauritius,
+ (Mauritius Standard Time, RE): Asia/Dubai,
+ (Mauritius Standard Time, SC): Asia/Dubai,
+ (Middle East Standard Time, 001): Asia/Beirut,
+ (Montevideo Standard Time, 001): America/Montevideo,
+ (Morocco Standard Time, 001): Africa/Casablanca,
+ (Morocco Standard Time, EH): Africa/El_Aaiun,
+ (Mountain Standard Time (Mexico), 001): America/Mazatlan,
+ (Mountain Standard Time, 001): America/Denver,
+ (Mountain Standard Time, CA): America/Edmonton,
+ (Mountain Standard Time, MX): America/Ciudad_Juarez,
+ (Myanmar Standard Time, 001): Asia/Yangon,
+ (N. Central Asia Standard Time, 001): Asia/Novosibirsk,
+ (Namibia Standard Time, 001): Africa/Windhoek,
+ (Nepal Standard Time, 001): Asia/Kathmandu,
+ (New Zealand Standard Time, 001): Pacific/Auckland,
+ (Newfoundland Standard Time, 001): America/St_Johns,
+ (Norfolk Standard Time, 001): Pacific/Norfolk,
+ (North Asia East Standard Time, 001): Asia/Irkutsk,
+ (North Asia Standard Time, 001): Asia/Krasnoyarsk,
+ (North Korea Standard Time, 001): Asia/Pyongyang,
+ (Omsk Standard Time, 001): Asia/Omsk,
+ (Pacific SA Standard Time, 001): America/Santiago,
+ (Pacific Standard Time (Mexico), 001): America/Tijuana,
+ (Pacific Standard Time, 001): America/Los_Angeles,
+ (Pacific Standard Time, CA): America/Vancouver,
+ (Pakistan Standard Time, 001): Asia/Karachi,
+ (Paraguay Standard Time, 001): America/Asuncion,
+ (Qyzylorda Standard Time, 001): Asia/Qyzylorda,
+ (Romance Standard Time, 001): Europe/Paris,
+ (Romance Standard Time, BE): Europe/Brussels,
+ (Romance Standard Time, DK): Europe/Berlin,
+ (Romance Standard Time, EA): Africa/Ceuta,
+ (Romance Standard Time, ES): Europe/Madrid,
+ (Russia Time Zone 10, 001): Asia/Srednekolymsk,
+ (Russia Time Zone 11, 001): Asia/Kamchatka,
+ (Russia Time Zone 3, 001): Europe/Samara,
+ (Russian Standard Time, 001): Europe/Moscow,
+ (Russian Standard Time, UA): Europe/Simferopol,
+ (SA Eastern Standard Time, 001): America/Cayenne,
+ (SA Eastern Standard Time, BR): America/Fortaleza,
+ (SA Eastern Standard Time, FK): Atlantic/Stanley,
+ (SA Eastern Standard Time, SR): America/Paramaribo,
+ (SA Pacific Standard Time, 001): America/Bogota,
+ (SA Pacific Standard Time, BR): America/Rio_Branco,
+ (SA Pacific Standard Time, CA): America/Panama,
+ (SA Pacific Standard Time, EC): America/Guayaquil,
+ (SA Pacific Standard Time, JM): America/Jamaica,
+ (SA Pacific Standard Time, KY): America/Panama,
+ (SA Pacific Standard Time, PA): America/Panama,
+ (SA Pacific Standard Time, PE): America/Lima,
+ (SA Western Standard Time, 001): America/La_Paz,
+ (SA Western Standard Time, AG): America/Puerto_Rico,
+ (SA Western Standard Time, AI): America/Puerto_Rico,
+ (SA Western Standard Time, AW): America/Puerto_Rico,
+ (SA Western Standard Time, BB): America/Barbados,
+ (SA Western Standard Time, BL): America/Puerto_Rico,
+ (SA Western Standard Time, BQ): America/Puerto_Rico,
+ (SA Western Standard Time, BR): America/Manaus,
+ (SA Western Standard Time, CA): America/Puerto_Rico,
+ (SA Western Standard Time, CW): America/Puerto_Rico,
+ (SA Western Standard Time, DM): America/Puerto_Rico,
+ (SA Western Standard Time, DO): America/Santo_Domingo,
+ (SA Western Standard Time, GD): America/Puerto_Rico,
+ (SA Western Standard Time, GP): America/Puerto_Rico,
+ (SA Western Standard Time, GY): America/Guyana,
+ (SA Western Standard Time, KN): America/Puerto_Rico,
+ (SA Western Standard Time, LC): America/Puerto_Rico,
+ (SA Western Standard Time, MF): America/Puerto_Rico,
+ (SA Western Standard Time, MQ): America/Martinique,
+ (SA Western Standard Time, MS): America/Puerto_Rico,
+ (SA Western Standard Time, PR): America/Puerto_Rico,
+ (SA Western Standard Time, SX): America/Puerto_Rico,
+ (SA Western Standard Time, TT): America/Puerto_Rico,
+ (SA Western Standard Time, VC): America/Puerto_Rico,
+ (SA Western Standard Time, VG): America/Puerto_Rico,
+ (SA Western Standard Time, VI): America/Puerto_Rico,
+ (SE Asia Standard Time, 001): Asia/Bangkok,
+ (SE Asia Standard Time, ID): Asia/Jakarta,
+ (SE Asia Standard Time, VN): Asia/Ho_Chi_Minh,
+ (Saint Pierre Standard Time, 001): America/Miquelon,
+ (Sakhalin Standard Time, 001): Asia/Sakhalin,
+ (Samoa Standard Time, 001): Pacific/Apia,
+ (Sao Tome Standard Time, 001): Africa/Sao_Tome,
+ (Saratov Standard Time, 001): Europe/Saratov,
+ (Singapore Standard Time, 001): Asia/Singapore,
+ (Singapore Standard Time, BN): Asia/Kuching,
+ (Singapore Standard Time, ID): Asia/Makassar,
+ (Singapore Standard Time, PH): Asia/Manila,
+ (South Africa Standard Time, 001): Africa/Johannesburg,
+ (South Africa Standard Time, BI): Africa/Maputo,
+ (South Africa Standard Time, BW): Africa/Maputo,
+ (South Africa Standard Time, CD): Africa/Maputo,
+ (South Africa Standard Time, MW): Africa/Maputo,
+ (South Africa Standard Time, MZ): Africa/Maputo,
+ (South Africa Standard Time, RW): Africa/Maputo,
+ (South Africa Standard Time, ZM): Africa/Maputo,
+ (South Africa Standard Time, ZW): Africa/Maputo,
+ (South Sudan Standard Time, 001): Africa/Juba,
+ (Sri Lanka Standard Time, 001): Asia/Colombo,
+ (Sudan Standard Time, 001): Africa/Khartoum,
+ (Syria Standard Time, 001): Asia/Damascus,
+ (Taipei Standard Time, 001): Asia/Taipei,
+ (Tasmania Standard Time, 001): Australia/Hobart,
+ (Tocantins Standard Time, 001): America/Araguaina,
+ (Tokyo Standard Time, 001): Asia/Tokyo,
+ (Tokyo Standard Time, ID): Asia/Jayapura,
+ (Tokyo Standard Time, PW): Pacific/Palau,
+ (Tokyo Standard Time, TL): Asia/Dili,
+ (Tomsk Standard Time, 001): Asia/Tomsk,
+ (Tonga Standard Time, 001): Pacific/Tongatapu,
+ (Transbaikal Standard Time, 001): Asia/Chita,
+ (Turkey Standard Time, 001): Europe/Istanbul,
+ (Turks And Caicos Standard Time, 001): America/Grand_Turk,
+ (US Eastern Standard Time, 001): America/Indiana/Indianapolis,
+ (US Mountain Standard Time, 001): America/Phoenix,
+ (US Mountain Standard Time, MX): America/Hermosillo,
+ (UTC+12, 001): Etc/GMT-12,
+ (UTC+12, KI): Pacific/Tarawa,
+ (UTC+12, MH): Pacific/Tarawa,
+ (UTC+12, NR): Pacific/Nauru,
+ (UTC+12, TV): Pacific/Tarawa,
+ (UTC+12, UM): Pacific/Tarawa,
+ (UTC+12, WF): Pacific/Tarawa,
+ (UTC+13, 001): Etc/GMT-13,
+ (UTC+13, KI): Pacific/Kanton,
+ (UTC+13, TK): Pacific/Fakaofo,
+ (UTC, 001): Etc/UTC,
+ (UTC-02, 001): Etc/GMT+2,
+ (UTC-02, BR): America/Noronha,
+ (UTC-08, 001): Etc/GMT+8,
+ (UTC-08, PN): Pacific/Pitcairn,
+ (UTC-09, 001): Etc/GMT+9,
+ (UTC-09, PF): Pacific/Gambier,
+ (UTC-11, 001): Etc/GMT+11,
+ (UTC-11, AS): Pacific/Pago_Pago,
+ (UTC-11, NU): Pacific/Niue,
+ (UTC-11, UM): Pacific/Pago_Pago,
+ (Ulaanbaatar Standard Time, 001): Asia/Ulaanbaatar,
+ (Venezuela Standard Time, 001): America/Caracas,
+ (Vladivostok Standard Time, 001): Asia/Vladivostok,
+ (Volgograd Standard Time, 001): Europe/Volgograd,
+ (W. Australia Standard Time, 001): Australia/Perth,
+ (W. Central Africa Standard Time, 001): Africa/Lagos,
+ (W. Central Africa Standard Time, DZ): Africa/Algiers,
+ (W. Central Africa Standard Time, TD): Africa/Ndjamena,
+ (W. Central Africa Standard Time, TN): Africa/Tunis,
+ (W. Europe Standard Time, 001): Europe/Berlin,
+ (W. Europe Standard Time, AD): Europe/Andorra,
+ (W. Europe Standard Time, AT): Europe/Vienna,
+ (W. Europe Standard Time, CH): Europe/Zurich,
+ (W. Europe Standard Time, GI): Europe/Gibraltar,
+ (W. Europe Standard Time, IT): Europe/Rome,
+ (W. Europe Standard Time, LI): Europe/Zurich,
+ (W. Europe Standard Time, LU): Europe/Brussels,
+ (W. Europe Standard Time, MC): Europe/Paris,
+ (W. Europe Standard Time, MT): Europe/Malta,
+ (W. Europe Standard Time, NL): Europe/Brussels,
+ (W. Europe Standard Time, SM): Europe/Rome,
+ (W. Europe Standard Time, VA): Europe/Rome,
+ (W. Mongolia Standard Time, 001): Asia/Hovd,
+ (West Asia Standard Time, 001): Asia/Tashkent,
+ (West Asia Standard Time, KZ): Asia/Oral,
+ (West Asia Standard Time, MV): Indian/Maldives,
+ (West Asia Standard Time, TJ): Asia/Dushanbe,
+ (West Asia Standard Time, TM): Asia/Ashgabat,
+ (West Bank Standard Time, 001): Asia/Hebron,
+ (West Pacific Standard Time, 001): Pacific/Port_Moresby,
+ (West Pacific Standard Time, GU): Pacific/Guam,
+ (West Pacific Standard Time, MP): Pacific/Guam,
+ (Yakutsk Standard Time, 001): Asia/Yakutsk,
+ (Yukon Standard Time, 001): America/Whitehorse
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Default.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Default.verified.txt
new file mode 100644
index 0000000..2fb3161
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Default.verified.txt
@@ -0,0 +1,337 @@
+{
+ (AUS Central Standard Time, 001): Australia/Darwin,
+ (AUS Eastern Standard Time, 001): Australia/Sydney,
+ (Afghanistan Standard Time, 001): Asia/Kabul,
+ (Alaskan Standard Time, 001): America/Anchorage,
+ (Aleutian Standard Time, 001): America/Adak,
+ (Altai Standard Time, 001): Asia/Barnaul,
+ (Arab Standard Time, 001): Asia/Riyadh,
+ (Arab Standard Time, BH): Asia/Bahrain,
+ (Arab Standard Time, KW): Asia/Kuwait,
+ (Arab Standard Time, QA): Asia/Qatar,
+ (Arab Standard Time, YE): Asia/Aden,
+ (Arabian Standard Time, 001): Asia/Dubai,
+ (Arabian Standard Time, OM): Asia/Muscat,
+ (Arabic Standard Time, 001): Asia/Baghdad,
+ (Argentina Standard Time, 001): America/Argentina/Buenos_Aires,
+ (Astrakhan Standard Time, 001): Europe/Astrakhan,
+ (Atlantic Standard Time, 001): America/Halifax,
+ (Atlantic Standard Time, BM): Atlantic/Bermuda,
+ (Atlantic Standard Time, GL): America/Thule,
+ (Aus Central W. Standard Time, 001): Australia/Eucla,
+ (Azerbaijan Standard Time, 001): Asia/Baku,
+ (Azores Standard Time, 001): Atlantic/Azores,
+ (Azores Standard Time, GL): America/Scoresbysund,
+ (Bahia Standard Time, 001): America/Bahia,
+ (Bangladesh Standard Time, 001): Asia/Dhaka,
+ (Bangladesh Standard Time, BT): Asia/Thimphu,
+ (Belarus Standard Time, 001): Europe/Minsk,
+ (Bougainville Standard Time, 001): Pacific/Bougainville,
+ (Canada Central Standard Time, 001): America/Regina,
+ (Cape Verde Standard Time, 001): Atlantic/Cape_Verde,
+ (Caucasus Standard Time, 001): Asia/Yerevan,
+ (Cen. Australia Standard Time, 001): Australia/Adelaide,
+ (Central America Standard Time, 001): America/Guatemala,
+ (Central America Standard Time, BZ): America/Belize,
+ (Central America Standard Time, CR): America/Costa_Rica,
+ (Central America Standard Time, EC): Pacific/Galapagos,
+ (Central America Standard Time, HN): America/Tegucigalpa,
+ (Central America Standard Time, NI): America/Managua,
+ (Central America Standard Time, SV): America/El_Salvador,
+ (Central Asia Standard Time, 001): Asia/Bishkek,
+ (Central Asia Standard Time, CN): Asia/Urumqi,
+ (Central Asia Standard Time, DG): Indian/Chagos,
+ (Central Asia Standard Time, IO): Indian/Chagos,
+ (Central Brazilian Standard Time, 001): America/Cuiaba,
+ (Central Europe Standard Time, 001): Europe/Budapest,
+ (Central Europe Standard Time, AL): Europe/Tirane,
+ (Central Europe Standard Time, CZ): Europe/Prague,
+ (Central Europe Standard Time, ME): Europe/Podgorica,
+ (Central Europe Standard Time, RS): Europe/Belgrade,
+ (Central Europe Standard Time, SI): Europe/Ljubljana,
+ (Central Europe Standard Time, SK): Europe/Bratislava,
+ (Central Europe Standard Time, XK): Europe/Belgrade,
+ (Central European Standard Time, 001): Europe/Warsaw,
+ (Central European Standard Time, BA): Europe/Sarajevo,
+ (Central European Standard Time, HR): Europe/Zagreb,
+ (Central European Standard Time, MK): Europe/Skopje,
+ (Central Pacific Standard Time, 001): Pacific/Guadalcanal,
+ (Central Pacific Standard Time, FM): Pacific/Ponape,
+ (Central Pacific Standard Time, NC): Pacific/Noumea,
+ (Central Pacific Standard Time, VU): Pacific/Efate,
+ (Central Standard Time (Mexico), 001): America/Mexico_City,
+ (Central Standard Time, 001): America/Chicago,
+ (Central Standard Time, CA): America/Winnipeg,
+ (Central Standard Time, MX): America/Matamoros,
+ (Chatham Islands Standard Time, 001): Pacific/Chatham,
+ (China Standard Time, 001): Asia/Shanghai,
+ (China Standard Time, HK): Asia/Hong_Kong,
+ (China Standard Time, MO): Asia/Macau,
+ (Cuba Standard Time, 001): America/Havana,
+ (Dateline Standard Time, 001): Etc/GMT+12,
+ (E. Africa Standard Time, 001): Africa/Nairobi,
+ (E. Africa Standard Time, DJ): Africa/Djibouti,
+ (E. Africa Standard Time, ER): Africa/Asmera,
+ (E. Africa Standard Time, ET): Africa/Addis_Ababa,
+ (E. Africa Standard Time, KM): Indian/Comoro,
+ (E. Africa Standard Time, MG): Indian/Antananarivo,
+ (E. Africa Standard Time, SO): Africa/Mogadishu,
+ (E. Africa Standard Time, TZ): Africa/Dar_es_Salaam,
+ (E. Africa Standard Time, UG): Africa/Kampala,
+ (E. Africa Standard Time, YT): Indian/Mayotte,
+ (E. Australia Standard Time, 001): Australia/Brisbane,
+ (E. Europe Standard Time, 001): Europe/Chisinau,
+ (E. South America Standard Time, 001): America/Sao_Paulo,
+ (Easter Island Standard Time, 001): Pacific/Easter,
+ (Eastern Standard Time (Mexico), 001): America/Cancun,
+ (Eastern Standard Time, 001): America/New_York,
+ (Eastern Standard Time, BS): America/Nassau,
+ (Eastern Standard Time, CA): America/Toronto,
+ (Egypt Standard Time, 001): Africa/Cairo,
+ (Ekaterinburg Standard Time, 001): Asia/Yekaterinburg,
+ (FLE Standard Time, 001): Europe/Kyiv,
+ (FLE Standard Time, AX): Europe/Mariehamn,
+ (FLE Standard Time, BG): Europe/Sofia,
+ (FLE Standard Time, EE): Europe/Tallinn,
+ (FLE Standard Time, FI): Europe/Helsinki,
+ (FLE Standard Time, LT): Europe/Vilnius,
+ (FLE Standard Time, LV): Europe/Riga,
+ (Fiji Standard Time, 001): Pacific/Fiji,
+ (GMT Standard Time, 001): Europe/London,
+ (GMT Standard Time, ES): Atlantic/Canary,
+ (GMT Standard Time, FO): Atlantic/Faroe,
+ (GMT Standard Time, GG): Europe/Guernsey,
+ (GMT Standard Time, IC): Atlantic/Canary,
+ (GMT Standard Time, IE): Europe/Dublin,
+ (GMT Standard Time, IM): Europe/Isle_of_Man,
+ (GMT Standard Time, JE): Europe/Jersey,
+ (GMT Standard Time, PT): Europe/Lisbon,
+ (GTB Standard Time, 001): Europe/Bucharest,
+ (GTB Standard Time, CY): Asia/Nicosia,
+ (GTB Standard Time, GR): Europe/Athens,
+ (Georgian Standard Time, 001): Asia/Tbilisi,
+ (Greenland Standard Time, 001): America/Nuuk,
+ (Greenwich Standard Time, 001): Africa/Abidjan,
+ (Greenwich Standard Time, BF): Africa/Ouagadougou,
+ (Greenwich Standard Time, GH): Africa/Accra,
+ (Greenwich Standard Time, GL): America/Danmarkshavn,
+ (Greenwich Standard Time, GM): Africa/Banjul,
+ (Greenwich Standard Time, GN): Africa/Conakry,
+ (Greenwich Standard Time, GW): Africa/Bissau,
+ (Greenwich Standard Time, LR): Africa/Monrovia,
+ (Greenwich Standard Time, ML): Africa/Bamako,
+ (Greenwich Standard Time, MR): Africa/Nouakchott,
+ (Greenwich Standard Time, SH): Atlantic/St_Helena,
+ (Greenwich Standard Time, SL): Africa/Freetown,
+ (Greenwich Standard Time, SN): Africa/Dakar,
+ (Greenwich Standard Time, TG): Africa/Lome,
+ (Haiti Standard Time, 001): America/Port-au-Prince,
+ (Hawaiian Standard Time, 001): Pacific/Honolulu,
+ (Hawaiian Standard Time, CK): Pacific/Rarotonga,
+ (Hawaiian Standard Time, PF): Pacific/Tahiti,
+ (India Standard Time, 001): Asia/Kolkata,
+ (Iran Standard Time, 001): Asia/Tehran,
+ (Israel Standard Time, 001): Asia/Jerusalem,
+ (Jordan Standard Time, 001): Asia/Amman,
+ (Kaliningrad Standard Time, 001): Europe/Kaliningrad,
+ (Korea Standard Time, 001): Asia/Seoul,
+ (Libya Standard Time, 001): Africa/Tripoli,
+ (Line Islands Standard Time, 001): Pacific/Kiritimati,
+ (Lord Howe Standard Time, 001): Australia/Lord_Howe,
+ (Magadan Standard Time, 001): Asia/Magadan,
+ (Magallanes Standard Time, 001): America/Punta_Arenas,
+ (Marquesas Standard Time, 001): Pacific/Marquesas,
+ (Mauritius Standard Time, 001): Indian/Mauritius,
+ (Mauritius Standard Time, RE): Indian/Reunion,
+ (Mauritius Standard Time, SC): Indian/Mahe,
+ (Middle East Standard Time, 001): Asia/Beirut,
+ (Montevideo Standard Time, 001): America/Montevideo,
+ (Morocco Standard Time, 001): Africa/Casablanca,
+ (Morocco Standard Time, EH): Africa/El_Aaiun,
+ (Mountain Standard Time (Mexico), 001): America/Mazatlan,
+ (Mountain Standard Time, 001): America/Denver,
+ (Mountain Standard Time, CA): America/Edmonton,
+ (Mountain Standard Time, MX): America/Ciudad_Juarez,
+ (Myanmar Standard Time, 001): Asia/Yangon,
+ (Myanmar Standard Time, CC): Indian/Cocos,
+ (N. Central Asia Standard Time, 001): Asia/Novosibirsk,
+ (Namibia Standard Time, 001): Africa/Windhoek,
+ (Nepal Standard Time, 001): Asia/Kathmandu,
+ (New Zealand Standard Time, 001): Pacific/Auckland,
+ (Newfoundland Standard Time, 001): America/St_Johns,
+ (Norfolk Standard Time, 001): Pacific/Norfolk,
+ (North Asia East Standard Time, 001): Asia/Irkutsk,
+ (North Asia Standard Time, 001): Asia/Krasnoyarsk,
+ (North Korea Standard Time, 001): Asia/Pyongyang,
+ (Omsk Standard Time, 001): Asia/Omsk,
+ (Pacific SA Standard Time, 001): America/Santiago,
+ (Pacific Standard Time (Mexico), 001): America/Tijuana,
+ (Pacific Standard Time, 001): America/Los_Angeles,
+ (Pacific Standard Time, CA): America/Vancouver,
+ (Pakistan Standard Time, 001): Asia/Karachi,
+ (Paraguay Standard Time, 001): America/Asuncion,
+ (Qyzylorda Standard Time, 001): Asia/Qyzylorda,
+ (Romance Standard Time, 001): Europe/Paris,
+ (Romance Standard Time, BE): Europe/Brussels,
+ (Romance Standard Time, DK): Europe/Copenhagen,
+ (Romance Standard Time, EA): Africa/Ceuta,
+ (Romance Standard Time, ES): Europe/Madrid,
+ (Russia Time Zone 10, 001): Asia/Srednekolymsk,
+ (Russia Time Zone 11, 001): Asia/Kamchatka,
+ (Russia Time Zone 3, 001): Europe/Samara,
+ (Russian Standard Time, 001): Europe/Moscow,
+ (Russian Standard Time, UA): Europe/Simferopol,
+ (SA Eastern Standard Time, 001): America/Cayenne,
+ (SA Eastern Standard Time, BR): America/Fortaleza,
+ (SA Eastern Standard Time, FK): Atlantic/Stanley,
+ (SA Eastern Standard Time, SR): America/Paramaribo,
+ (SA Pacific Standard Time, 001): America/Bogota,
+ (SA Pacific Standard Time, BR): America/Rio_Branco,
+ (SA Pacific Standard Time, CA): America/Coral_Harbour,
+ (SA Pacific Standard Time, EC): America/Guayaquil,
+ (SA Pacific Standard Time, JM): America/Jamaica,
+ (SA Pacific Standard Time, KY): America/Cayman,
+ (SA Pacific Standard Time, PA): America/Panama,
+ (SA Pacific Standard Time, PE): America/Lima,
+ (SA Western Standard Time, 001): America/La_Paz,
+ (SA Western Standard Time, AG): America/Antigua,
+ (SA Western Standard Time, AI): America/Anguilla,
+ (SA Western Standard Time, AW): America/Aruba,
+ (SA Western Standard Time, BB): America/Barbados,
+ (SA Western Standard Time, BL): America/St_Barthelemy,
+ (SA Western Standard Time, BQ): America/Kralendijk,
+ (SA Western Standard Time, BR): America/Manaus,
+ (SA Western Standard Time, CA): America/Blanc-Sablon,
+ (SA Western Standard Time, CW): America/Curacao,
+ (SA Western Standard Time, DM): America/Dominica,
+ (SA Western Standard Time, DO): America/Santo_Domingo,
+ (SA Western Standard Time, GD): America/Grenada,
+ (SA Western Standard Time, GP): America/Guadeloupe,
+ (SA Western Standard Time, GY): America/Guyana,
+ (SA Western Standard Time, KN): America/St_Kitts,
+ (SA Western Standard Time, LC): America/St_Lucia,
+ (SA Western Standard Time, MF): America/Marigot,
+ (SA Western Standard Time, MQ): America/Martinique,
+ (SA Western Standard Time, MS): America/Montserrat,
+ (SA Western Standard Time, PR): America/Puerto_Rico,
+ (SA Western Standard Time, SX): America/Lower_Princes,
+ (SA Western Standard Time, TT): America/Port_of_Spain,
+ (SA Western Standard Time, VC): America/St_Vincent,
+ (SA Western Standard Time, VG): America/Tortola,
+ (SA Western Standard Time, VI): America/St_Thomas,
+ (SE Asia Standard Time, 001): Asia/Bangkok,
+ (SE Asia Standard Time, CX): Indian/Christmas,
+ (SE Asia Standard Time, ID): Asia/Jakarta,
+ (SE Asia Standard Time, KH): Asia/Phnom_Penh,
+ (SE Asia Standard Time, LA): Asia/Vientiane,
+ (SE Asia Standard Time, VN): Asia/Ho_Chi_Minh,
+ (Saint Pierre Standard Time, 001): America/Miquelon,
+ (Sakhalin Standard Time, 001): Asia/Sakhalin,
+ (Samoa Standard Time, 001): Pacific/Apia,
+ (Sao Tome Standard Time, 001): Africa/Sao_Tome,
+ (Saratov Standard Time, 001): Europe/Saratov,
+ (Singapore Standard Time, 001): Asia/Singapore,
+ (Singapore Standard Time, BN): Asia/Kuching,
+ (Singapore Standard Time, ID): Asia/Makassar,
+ (Singapore Standard Time, MY): Asia/Kuala_Lumpur,
+ (Singapore Standard Time, PH): Asia/Manila,
+ (South Africa Standard Time, 001): Africa/Johannesburg,
+ (South Africa Standard Time, BI): Africa/Bujumbura,
+ (South Africa Standard Time, BW): Africa/Gaborone,
+ (South Africa Standard Time, CD): Africa/Lubumbashi,
+ (South Africa Standard Time, LS): Africa/Maseru,
+ (South Africa Standard Time, MW): Africa/Blantyre,
+ (South Africa Standard Time, MZ): Africa/Maputo,
+ (South Africa Standard Time, RW): Africa/Kigali,
+ (South Africa Standard Time, SZ): Africa/Mbabane,
+ (South Africa Standard Time, ZM): Africa/Lusaka,
+ (South Africa Standard Time, ZW): Africa/Harare,
+ (South Sudan Standard Time, 001): Africa/Juba,
+ (Sri Lanka Standard Time, 001): Asia/Colombo,
+ (Sudan Standard Time, 001): Africa/Khartoum,
+ (Syria Standard Time, 001): Asia/Damascus,
+ (Taipei Standard Time, 001): Asia/Taipei,
+ (Tasmania Standard Time, 001): Australia/Hobart,
+ (Tocantins Standard Time, 001): America/Araguaina,
+ (Tokyo Standard Time, 001): Asia/Tokyo,
+ (Tokyo Standard Time, ID): Asia/Jayapura,
+ (Tokyo Standard Time, PW): Pacific/Palau,
+ (Tokyo Standard Time, TL): Asia/Dili,
+ (Tomsk Standard Time, 001): Asia/Tomsk,
+ (Tonga Standard Time, 001): Pacific/Tongatapu,
+ (Transbaikal Standard Time, 001): Asia/Chita,
+ (Turkey Standard Time, 001): Europe/Istanbul,
+ (Turks And Caicos Standard Time, 001): America/Grand_Turk,
+ (US Eastern Standard Time, 001): America/Indiana/Indianapolis,
+ (US Mountain Standard Time, 001): America/Phoenix,
+ (US Mountain Standard Time, CA): America/Creston,
+ (US Mountain Standard Time, MX): America/Hermosillo,
+ (UTC+12, 001): Etc/GMT-12,
+ (UTC+12, KI): Pacific/Tarawa,
+ (UTC+12, MH): Pacific/Majuro,
+ (UTC+12, NR): Pacific/Nauru,
+ (UTC+12, TV): Pacific/Funafuti,
+ (UTC+12, UM): Pacific/Wake,
+ (UTC+12, WF): Pacific/Wallis,
+ (UTC+13, 001): Etc/GMT-13,
+ (UTC+13, KI): Pacific/Kanton,
+ (UTC+13, TK): Pacific/Fakaofo,
+ (UTC, 001): Etc/UTC,
+ (UTC-02, 001): Etc/GMT+2,
+ (UTC-02, BR): America/Noronha,
+ (UTC-08, 001): Etc/GMT+8,
+ (UTC-08, PN): Pacific/Pitcairn,
+ (UTC-09, 001): Etc/GMT+9,
+ (UTC-09, PF): Pacific/Gambier,
+ (UTC-11, 001): Etc/GMT+11,
+ (UTC-11, AS): Pacific/Pago_Pago,
+ (UTC-11, NU): Pacific/Niue,
+ (UTC-11, UM): Pacific/Midway,
+ (Ulaanbaatar Standard Time, 001): Asia/Ulaanbaatar,
+ (Venezuela Standard Time, 001): America/Caracas,
+ (Vladivostok Standard Time, 001): Asia/Vladivostok,
+ (Volgograd Standard Time, 001): Europe/Volgograd,
+ (W. Australia Standard Time, 001): Australia/Perth,
+ (W. Central Africa Standard Time, 001): Africa/Lagos,
+ (W. Central Africa Standard Time, AO): Africa/Luanda,
+ (W. Central Africa Standard Time, BJ): Africa/Porto-Novo,
+ (W. Central Africa Standard Time, CD): Africa/Kinshasa,
+ (W. Central Africa Standard Time, CF): Africa/Bangui,
+ (W. Central Africa Standard Time, CG): Africa/Brazzaville,
+ (W. Central Africa Standard Time, CM): Africa/Douala,
+ (W. Central Africa Standard Time, DZ): Africa/Algiers,
+ (W. Central Africa Standard Time, GA): Africa/Libreville,
+ (W. Central Africa Standard Time, GQ): Africa/Malabo,
+ (W. Central Africa Standard Time, NE): Africa/Niamey,
+ (W. Central Africa Standard Time, TD): Africa/Ndjamena,
+ (W. Central Africa Standard Time, TN): Africa/Tunis,
+ (W. Europe Standard Time, 001): Europe/Berlin,
+ (W. Europe Standard Time, AD): Europe/Andorra,
+ (W. Europe Standard Time, AT): Europe/Vienna,
+ (W. Europe Standard Time, CH): Europe/Zurich,
+ (W. Europe Standard Time, GI): Europe/Gibraltar,
+ (W. Europe Standard Time, IT): Europe/Rome,
+ (W. Europe Standard Time, LI): Europe/Vaduz,
+ (W. Europe Standard Time, LU): Europe/Luxembourg,
+ (W. Europe Standard Time, MC): Europe/Monaco,
+ (W. Europe Standard Time, MT): Europe/Malta,
+ (W. Europe Standard Time, NL): Europe/Amsterdam,
+ (W. Europe Standard Time, NO): Europe/Oslo,
+ (W. Europe Standard Time, SE): Europe/Stockholm,
+ (W. Europe Standard Time, SJ): Arctic/Longyearbyen,
+ (W. Europe Standard Time, SM): Europe/San_Marino,
+ (W. Europe Standard Time, VA): Europe/Vatican,
+ (W. Mongolia Standard Time, 001): Asia/Hovd,
+ (West Asia Standard Time, 001): Asia/Tashkent,
+ (West Asia Standard Time, KZ): Asia/Oral,
+ (West Asia Standard Time, MV): Indian/Maldives,
+ (West Asia Standard Time, TJ): Asia/Dushanbe,
+ (West Asia Standard Time, TM): Asia/Ashgabat,
+ (West Bank Standard Time, 001): Asia/Hebron,
+ (West Pacific Standard Time, 001): Pacific/Port_Moresby,
+ (West Pacific Standard Time, FM): Pacific/Truk,
+ (West Pacific Standard Time, GU): Pacific/Guam,
+ (West Pacific Standard Time, MP): Pacific/Saipan,
+ (Yakutsk Standard Time, 001): Asia/Yakutsk,
+ (Yukon Standard Time, 001): America/Whitehorse
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Original.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Original.verified.txt
new file mode 100644
index 0000000..f44e58d
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_Regional_mode=Original.verified.txt
@@ -0,0 +1,338 @@
+{
+ (AUS Central Standard Time, 001): Australia/Darwin,
+ (AUS Eastern Standard Time, 001): Australia/Sydney,
+ (Afghanistan Standard Time, 001): Asia/Kabul,
+ (Alaskan Standard Time, 001): America/Anchorage,
+ (Aleutian Standard Time, 001): America/Adak,
+ (Altai Standard Time, 001): Asia/Barnaul,
+ (Arab Standard Time, 001): Asia/Riyadh,
+ (Arab Standard Time, BH): Asia/Bahrain,
+ (Arab Standard Time, KW): Asia/Kuwait,
+ (Arab Standard Time, QA): Asia/Qatar,
+ (Arab Standard Time, YE): Asia/Aden,
+ (Arabian Standard Time, 001): Asia/Dubai,
+ (Arabian Standard Time, OM): Asia/Muscat,
+ (Arabic Standard Time, 001): Asia/Baghdad,
+ (Argentina Standard Time, 001): America/Buenos_Aires,
+ (Astrakhan Standard Time, 001): Europe/Astrakhan,
+ (Atlantic Standard Time, 001): America/Halifax,
+ (Atlantic Standard Time, BM): Atlantic/Bermuda,
+ (Atlantic Standard Time, GL): America/Thule,
+ (Aus Central W. Standard Time, 001): Australia/Eucla,
+ (Azerbaijan Standard Time, 001): Asia/Baku,
+ (Azores Standard Time, 001): Atlantic/Azores,
+ (Azores Standard Time, GL): America/Scoresbysund,
+ (Bahia Standard Time, 001): America/Bahia,
+ (Bangladesh Standard Time, 001): Asia/Dhaka,
+ (Bangladesh Standard Time, BT): Asia/Thimphu,
+ (Belarus Standard Time, 001): Europe/Minsk,
+ (Bougainville Standard Time, 001): Pacific/Bougainville,
+ (Canada Central Standard Time, 001): America/Regina,
+ (Cape Verde Standard Time, 001): Atlantic/Cape_Verde,
+ (Caucasus Standard Time, 001): Asia/Yerevan,
+ (Cen. Australia Standard Time, 001): Australia/Adelaide,
+ (Central America Standard Time, 001): America/Guatemala,
+ (Central America Standard Time, BZ): America/Belize,
+ (Central America Standard Time, CR): America/Costa_Rica,
+ (Central America Standard Time, EC): Pacific/Galapagos,
+ (Central America Standard Time, HN): America/Tegucigalpa,
+ (Central America Standard Time, NI): America/Managua,
+ (Central America Standard Time, SV): America/El_Salvador,
+ (Central Asia Standard Time, 001): Asia/Bishkek,
+ (Central Asia Standard Time, CN): Asia/Urumqi,
+ (Central Asia Standard Time, DG): Indian/Chagos,
+ (Central Asia Standard Time, IO): Indian/Chagos,
+ (Central Brazilian Standard Time, 001): America/Cuiaba,
+ (Central Europe Standard Time, 001): Europe/Budapest,
+ (Central Europe Standard Time, AL): Europe/Tirane,
+ (Central Europe Standard Time, CZ): Europe/Prague,
+ (Central Europe Standard Time, ME): Europe/Podgorica,
+ (Central Europe Standard Time, RS): Europe/Belgrade,
+ (Central Europe Standard Time, SI): Europe/Ljubljana,
+ (Central Europe Standard Time, SK): Europe/Bratislava,
+ (Central Europe Standard Time, XK): Europe/Belgrade,
+ (Central European Standard Time, 001): Europe/Warsaw,
+ (Central European Standard Time, BA): Europe/Sarajevo,
+ (Central European Standard Time, HR): Europe/Zagreb,
+ (Central European Standard Time, MK): Europe/Skopje,
+ (Central Pacific Standard Time, 001): Pacific/Guadalcanal,
+ (Central Pacific Standard Time, FM): Pacific/Ponape,
+ (Central Pacific Standard Time, NC): Pacific/Noumea,
+ (Central Pacific Standard Time, VU): Pacific/Efate,
+ (Central Standard Time (Mexico), 001): America/Mexico_City,
+ (Central Standard Time, 001): America/Chicago,
+ (Central Standard Time, CA): America/Winnipeg,
+ (Central Standard Time, MX): America/Matamoros,
+ (Chatham Islands Standard Time, 001): Pacific/Chatham,
+ (China Standard Time, 001): Asia/Shanghai,
+ (China Standard Time, HK): Asia/Hong_Kong,
+ (China Standard Time, MO): Asia/Macau,
+ (Cuba Standard Time, 001): America/Havana,
+ (Dateline Standard Time, 001): Etc/GMT+12,
+ (E. Africa Standard Time, 001): Africa/Nairobi,
+ (E. Africa Standard Time, DJ): Africa/Djibouti,
+ (E. Africa Standard Time, ER): Africa/Asmera,
+ (E. Africa Standard Time, ET): Africa/Addis_Ababa,
+ (E. Africa Standard Time, KM): Indian/Comoro,
+ (E. Africa Standard Time, MG): Indian/Antananarivo,
+ (E. Africa Standard Time, SO): Africa/Mogadishu,
+ (E. Africa Standard Time, TZ): Africa/Dar_es_Salaam,
+ (E. Africa Standard Time, UG): Africa/Kampala,
+ (E. Africa Standard Time, YT): Indian/Mayotte,
+ (E. Australia Standard Time, 001): Australia/Brisbane,
+ (E. Europe Standard Time, 001): Europe/Chisinau,
+ (E. South America Standard Time, 001): America/Sao_Paulo,
+ (Easter Island Standard Time, 001): Pacific/Easter,
+ (Eastern Standard Time (Mexico), 001): America/Cancun,
+ (Eastern Standard Time, 001): America/New_York,
+ (Eastern Standard Time, BS): America/Nassau,
+ (Eastern Standard Time, CA): America/Toronto,
+ (Egypt Standard Time, 001): Africa/Cairo,
+ (Ekaterinburg Standard Time, 001): Asia/Yekaterinburg,
+ (FLE Standard Time, 001): Europe/Kiev,
+ (FLE Standard Time, AX): Europe/Mariehamn,
+ (FLE Standard Time, BG): Europe/Sofia,
+ (FLE Standard Time, EE): Europe/Tallinn,
+ (FLE Standard Time, FI): Europe/Helsinki,
+ (FLE Standard Time, LT): Europe/Vilnius,
+ (FLE Standard Time, LV): Europe/Riga,
+ (Fiji Standard Time, 001): Pacific/Fiji,
+ (GMT Standard Time, 001): Europe/London,
+ (GMT Standard Time, ES): Atlantic/Canary,
+ (GMT Standard Time, FO): Atlantic/Faeroe,
+ (GMT Standard Time, GG): Europe/Guernsey,
+ (GMT Standard Time, IC): Atlantic/Canary,
+ (GMT Standard Time, IE): Europe/Dublin,
+ (GMT Standard Time, IM): Europe/Isle_of_Man,
+ (GMT Standard Time, JE): Europe/Jersey,
+ (GMT Standard Time, PT): Europe/Lisbon,
+ (GTB Standard Time, 001): Europe/Bucharest,
+ (GTB Standard Time, CY): Asia/Nicosia,
+ (GTB Standard Time, GR): Europe/Athens,
+ (Georgian Standard Time, 001): Asia/Tbilisi,
+ (Greenland Standard Time, 001): America/Godthab,
+ (Greenwich Standard Time, 001): Atlantic/Reykjavik,
+ (Greenwich Standard Time, BF): Africa/Ouagadougou,
+ (Greenwich Standard Time, CI): Africa/Abidjan,
+ (Greenwich Standard Time, GH): Africa/Accra,
+ (Greenwich Standard Time, GL): America/Danmarkshavn,
+ (Greenwich Standard Time, GM): Africa/Banjul,
+ (Greenwich Standard Time, GN): Africa/Conakry,
+ (Greenwich Standard Time, GW): Africa/Bissau,
+ (Greenwich Standard Time, LR): Africa/Monrovia,
+ (Greenwich Standard Time, ML): Africa/Bamako,
+ (Greenwich Standard Time, MR): Africa/Nouakchott,
+ (Greenwich Standard Time, SH): Atlantic/St_Helena,
+ (Greenwich Standard Time, SL): Africa/Freetown,
+ (Greenwich Standard Time, SN): Africa/Dakar,
+ (Greenwich Standard Time, TG): Africa/Lome,
+ (Haiti Standard Time, 001): America/Port-au-Prince,
+ (Hawaiian Standard Time, 001): Pacific/Honolulu,
+ (Hawaiian Standard Time, CK): Pacific/Rarotonga,
+ (Hawaiian Standard Time, PF): Pacific/Tahiti,
+ (India Standard Time, 001): Asia/Calcutta,
+ (Iran Standard Time, 001): Asia/Tehran,
+ (Israel Standard Time, 001): Asia/Jerusalem,
+ (Jordan Standard Time, 001): Asia/Amman,
+ (Kaliningrad Standard Time, 001): Europe/Kaliningrad,
+ (Korea Standard Time, 001): Asia/Seoul,
+ (Libya Standard Time, 001): Africa/Tripoli,
+ (Line Islands Standard Time, 001): Pacific/Kiritimati,
+ (Lord Howe Standard Time, 001): Australia/Lord_Howe,
+ (Magadan Standard Time, 001): Asia/Magadan,
+ (Magallanes Standard Time, 001): America/Punta_Arenas,
+ (Marquesas Standard Time, 001): Pacific/Marquesas,
+ (Mauritius Standard Time, 001): Indian/Mauritius,
+ (Mauritius Standard Time, RE): Indian/Reunion,
+ (Mauritius Standard Time, SC): Indian/Mahe,
+ (Middle East Standard Time, 001): Asia/Beirut,
+ (Montevideo Standard Time, 001): America/Montevideo,
+ (Morocco Standard Time, 001): Africa/Casablanca,
+ (Morocco Standard Time, EH): Africa/El_Aaiun,
+ (Mountain Standard Time (Mexico), 001): America/Mazatlan,
+ (Mountain Standard Time, 001): America/Denver,
+ (Mountain Standard Time, CA): America/Edmonton,
+ (Mountain Standard Time, MX): America/Ciudad_Juarez,
+ (Myanmar Standard Time, 001): Asia/Rangoon,
+ (Myanmar Standard Time, CC): Indian/Cocos,
+ (N. Central Asia Standard Time, 001): Asia/Novosibirsk,
+ (Namibia Standard Time, 001): Africa/Windhoek,
+ (Nepal Standard Time, 001): Asia/Katmandu,
+ (New Zealand Standard Time, 001): Pacific/Auckland,
+ (Newfoundland Standard Time, 001): America/St_Johns,
+ (Norfolk Standard Time, 001): Pacific/Norfolk,
+ (North Asia East Standard Time, 001): Asia/Irkutsk,
+ (North Asia Standard Time, 001): Asia/Krasnoyarsk,
+ (North Korea Standard Time, 001): Asia/Pyongyang,
+ (Omsk Standard Time, 001): Asia/Omsk,
+ (Pacific SA Standard Time, 001): America/Santiago,
+ (Pacific Standard Time (Mexico), 001): America/Tijuana,
+ (Pacific Standard Time, 001): America/Los_Angeles,
+ (Pacific Standard Time, CA): America/Vancouver,
+ (Pakistan Standard Time, 001): Asia/Karachi,
+ (Paraguay Standard Time, 001): America/Asuncion,
+ (Qyzylorda Standard Time, 001): Asia/Qyzylorda,
+ (Romance Standard Time, 001): Europe/Paris,
+ (Romance Standard Time, BE): Europe/Brussels,
+ (Romance Standard Time, DK): Europe/Copenhagen,
+ (Romance Standard Time, EA): Africa/Ceuta,
+ (Romance Standard Time, ES): Europe/Madrid,
+ (Russia Time Zone 10, 001): Asia/Srednekolymsk,
+ (Russia Time Zone 11, 001): Asia/Kamchatka,
+ (Russia Time Zone 3, 001): Europe/Samara,
+ (Russian Standard Time, 001): Europe/Moscow,
+ (Russian Standard Time, UA): Europe/Simferopol,
+ (SA Eastern Standard Time, 001): America/Cayenne,
+ (SA Eastern Standard Time, BR): America/Fortaleza,
+ (SA Eastern Standard Time, FK): Atlantic/Stanley,
+ (SA Eastern Standard Time, SR): America/Paramaribo,
+ (SA Pacific Standard Time, 001): America/Bogota,
+ (SA Pacific Standard Time, BR): America/Rio_Branco,
+ (SA Pacific Standard Time, CA): America/Coral_Harbour,
+ (SA Pacific Standard Time, EC): America/Guayaquil,
+ (SA Pacific Standard Time, JM): America/Jamaica,
+ (SA Pacific Standard Time, KY): America/Cayman,
+ (SA Pacific Standard Time, PA): America/Panama,
+ (SA Pacific Standard Time, PE): America/Lima,
+ (SA Western Standard Time, 001): America/La_Paz,
+ (SA Western Standard Time, AG): America/Antigua,
+ (SA Western Standard Time, AI): America/Anguilla,
+ (SA Western Standard Time, AW): America/Aruba,
+ (SA Western Standard Time, BB): America/Barbados,
+ (SA Western Standard Time, BL): America/St_Barthelemy,
+ (SA Western Standard Time, BQ): America/Kralendijk,
+ (SA Western Standard Time, BR): America/Manaus,
+ (SA Western Standard Time, CA): America/Blanc-Sablon,
+ (SA Western Standard Time, CW): America/Curacao,
+ (SA Western Standard Time, DM): America/Dominica,
+ (SA Western Standard Time, DO): America/Santo_Domingo,
+ (SA Western Standard Time, GD): America/Grenada,
+ (SA Western Standard Time, GP): America/Guadeloupe,
+ (SA Western Standard Time, GY): America/Guyana,
+ (SA Western Standard Time, KN): America/St_Kitts,
+ (SA Western Standard Time, LC): America/St_Lucia,
+ (SA Western Standard Time, MF): America/Marigot,
+ (SA Western Standard Time, MQ): America/Martinique,
+ (SA Western Standard Time, MS): America/Montserrat,
+ (SA Western Standard Time, PR): America/Puerto_Rico,
+ (SA Western Standard Time, SX): America/Lower_Princes,
+ (SA Western Standard Time, TT): America/Port_of_Spain,
+ (SA Western Standard Time, VC): America/St_Vincent,
+ (SA Western Standard Time, VG): America/Tortola,
+ (SA Western Standard Time, VI): America/St_Thomas,
+ (SE Asia Standard Time, 001): Asia/Bangkok,
+ (SE Asia Standard Time, CX): Indian/Christmas,
+ (SE Asia Standard Time, ID): Asia/Jakarta,
+ (SE Asia Standard Time, KH): Asia/Phnom_Penh,
+ (SE Asia Standard Time, LA): Asia/Vientiane,
+ (SE Asia Standard Time, VN): Asia/Saigon,
+ (Saint Pierre Standard Time, 001): America/Miquelon,
+ (Sakhalin Standard Time, 001): Asia/Sakhalin,
+ (Samoa Standard Time, 001): Pacific/Apia,
+ (Sao Tome Standard Time, 001): Africa/Sao_Tome,
+ (Saratov Standard Time, 001): Europe/Saratov,
+ (Singapore Standard Time, 001): Asia/Singapore,
+ (Singapore Standard Time, BN): Asia/Brunei,
+ (Singapore Standard Time, ID): Asia/Makassar,
+ (Singapore Standard Time, MY): Asia/Kuala_Lumpur,
+ (Singapore Standard Time, PH): Asia/Manila,
+ (South Africa Standard Time, 001): Africa/Johannesburg,
+ (South Africa Standard Time, BI): Africa/Bujumbura,
+ (South Africa Standard Time, BW): Africa/Gaborone,
+ (South Africa Standard Time, CD): Africa/Lubumbashi,
+ (South Africa Standard Time, LS): Africa/Maseru,
+ (South Africa Standard Time, MW): Africa/Blantyre,
+ (South Africa Standard Time, MZ): Africa/Maputo,
+ (South Africa Standard Time, RW): Africa/Kigali,
+ (South Africa Standard Time, SZ): Africa/Mbabane,
+ (South Africa Standard Time, ZM): Africa/Lusaka,
+ (South Africa Standard Time, ZW): Africa/Harare,
+ (South Sudan Standard Time, 001): Africa/Juba,
+ (Sri Lanka Standard Time, 001): Asia/Colombo,
+ (Sudan Standard Time, 001): Africa/Khartoum,
+ (Syria Standard Time, 001): Asia/Damascus,
+ (Taipei Standard Time, 001): Asia/Taipei,
+ (Tasmania Standard Time, 001): Australia/Hobart,
+ (Tocantins Standard Time, 001): America/Araguaina,
+ (Tokyo Standard Time, 001): Asia/Tokyo,
+ (Tokyo Standard Time, ID): Asia/Jayapura,
+ (Tokyo Standard Time, PW): Pacific/Palau,
+ (Tokyo Standard Time, TL): Asia/Dili,
+ (Tomsk Standard Time, 001): Asia/Tomsk,
+ (Tonga Standard Time, 001): Pacific/Tongatapu,
+ (Transbaikal Standard Time, 001): Asia/Chita,
+ (Turkey Standard Time, 001): Europe/Istanbul,
+ (Turks And Caicos Standard Time, 001): America/Grand_Turk,
+ (US Eastern Standard Time, 001): America/Indianapolis,
+ (US Mountain Standard Time, 001): America/Phoenix,
+ (US Mountain Standard Time, CA): America/Creston,
+ (US Mountain Standard Time, MX): America/Hermosillo,
+ (UTC+12, 001): Etc/GMT-12,
+ (UTC+12, KI): Pacific/Tarawa,
+ (UTC+12, MH): Pacific/Majuro,
+ (UTC+12, NR): Pacific/Nauru,
+ (UTC+12, TV): Pacific/Funafuti,
+ (UTC+12, UM): Pacific/Wake,
+ (UTC+12, WF): Pacific/Wallis,
+ (UTC+13, 001): Etc/GMT-13,
+ (UTC+13, KI): Pacific/Enderbury,
+ (UTC+13, TK): Pacific/Fakaofo,
+ (UTC, 001): Etc/UTC,
+ (UTC-02, 001): Etc/GMT+2,
+ (UTC-02, BR): America/Noronha,
+ (UTC-08, 001): Etc/GMT+8,
+ (UTC-08, PN): Pacific/Pitcairn,
+ (UTC-09, 001): Etc/GMT+9,
+ (UTC-09, PF): Pacific/Gambier,
+ (UTC-11, 001): Etc/GMT+11,
+ (UTC-11, AS): Pacific/Pago_Pago,
+ (UTC-11, NU): Pacific/Niue,
+ (UTC-11, UM): Pacific/Midway,
+ (Ulaanbaatar Standard Time, 001): Asia/Ulaanbaatar,
+ (Venezuela Standard Time, 001): America/Caracas,
+ (Vladivostok Standard Time, 001): Asia/Vladivostok,
+ (Volgograd Standard Time, 001): Europe/Volgograd,
+ (W. Australia Standard Time, 001): Australia/Perth,
+ (W. Central Africa Standard Time, 001): Africa/Lagos,
+ (W. Central Africa Standard Time, AO): Africa/Luanda,
+ (W. Central Africa Standard Time, BJ): Africa/Porto-Novo,
+ (W. Central Africa Standard Time, CD): Africa/Kinshasa,
+ (W. Central Africa Standard Time, CF): Africa/Bangui,
+ (W. Central Africa Standard Time, CG): Africa/Brazzaville,
+ (W. Central Africa Standard Time, CM): Africa/Douala,
+ (W. Central Africa Standard Time, DZ): Africa/Algiers,
+ (W. Central Africa Standard Time, GA): Africa/Libreville,
+ (W. Central Africa Standard Time, GQ): Africa/Malabo,
+ (W. Central Africa Standard Time, NE): Africa/Niamey,
+ (W. Central Africa Standard Time, TD): Africa/Ndjamena,
+ (W. Central Africa Standard Time, TN): Africa/Tunis,
+ (W. Europe Standard Time, 001): Europe/Berlin,
+ (W. Europe Standard Time, AD): Europe/Andorra,
+ (W. Europe Standard Time, AT): Europe/Vienna,
+ (W. Europe Standard Time, CH): Europe/Zurich,
+ (W. Europe Standard Time, GI): Europe/Gibraltar,
+ (W. Europe Standard Time, IT): Europe/Rome,
+ (W. Europe Standard Time, LI): Europe/Vaduz,
+ (W. Europe Standard Time, LU): Europe/Luxembourg,
+ (W. Europe Standard Time, MC): Europe/Monaco,
+ (W. Europe Standard Time, MT): Europe/Malta,
+ (W. Europe Standard Time, NL): Europe/Amsterdam,
+ (W. Europe Standard Time, NO): Europe/Oslo,
+ (W. Europe Standard Time, SE): Europe/Stockholm,
+ (W. Europe Standard Time, SJ): Arctic/Longyearbyen,
+ (W. Europe Standard Time, SM): Europe/San_Marino,
+ (W. Europe Standard Time, VA): Europe/Vatican,
+ (W. Mongolia Standard Time, 001): Asia/Hovd,
+ (West Asia Standard Time, 001): Asia/Tashkent,
+ (West Asia Standard Time, KZ): Asia/Oral,
+ (West Asia Standard Time, MV): Indian/Maldives,
+ (West Asia Standard Time, TJ): Asia/Dushanbe,
+ (West Asia Standard Time, TM): Asia/Ashgabat,
+ (West Bank Standard Time, 001): Asia/Hebron,
+ (West Pacific Standard Time, 001): Pacific/Port_Moresby,
+ (West Pacific Standard Time, FM): Pacific/Truk,
+ (West Pacific Standard Time, GU): Pacific/Guam,
+ (West Pacific Standard Time, MP): Pacific/Saipan,
+ (Yakutsk Standard Time, 001): Asia/Yakutsk,
+ (Yukon Standard Time, 001): America/Whitehorse
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Canonical.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Canonical.verified.txt
new file mode 100644
index 0000000..1539491
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Canonical.verified.txt
@@ -0,0 +1,141 @@
+{
+ AUS Central Standard Time: Australia/Darwin,
+ AUS Eastern Standard Time: Australia/Sydney,
+ Afghanistan Standard Time: Asia/Kabul,
+ Alaskan Standard Time: America/Anchorage,
+ Aleutian Standard Time: America/Adak,
+ Altai Standard Time: Asia/Barnaul,
+ Arab Standard Time: Asia/Riyadh,
+ Arabian Standard Time: Asia/Dubai,
+ Arabic Standard Time: Asia/Baghdad,
+ Argentina Standard Time: America/Argentina/Buenos_Aires,
+ Astrakhan Standard Time: Europe/Astrakhan,
+ Atlantic Standard Time: America/Halifax,
+ Aus Central W. Standard Time: Australia/Eucla,
+ Azerbaijan Standard Time: Asia/Baku,
+ Azores Standard Time: Atlantic/Azores,
+ Bahia Standard Time: America/Bahia,
+ Bangladesh Standard Time: Asia/Dhaka,
+ Belarus Standard Time: Europe/Minsk,
+ Bougainville Standard Time: Pacific/Bougainville,
+ Canada Central Standard Time: America/Regina,
+ Cape Verde Standard Time: Atlantic/Cape_Verde,
+ Caucasus Standard Time: Asia/Yerevan,
+ Cen. Australia Standard Time: Australia/Adelaide,
+ Central America Standard Time: America/Guatemala,
+ Central Asia Standard Time: Asia/Bishkek,
+ Central Brazilian Standard Time: America/Cuiaba,
+ Central Europe Standard Time: Europe/Budapest,
+ Central European Standard Time: Europe/Warsaw,
+ Central Pacific Standard Time: Pacific/Guadalcanal,
+ Central Standard Time: America/Chicago,
+ Central Standard Time (Mexico): America/Mexico_City,
+ Chatham Islands Standard Time: Pacific/Chatham,
+ China Standard Time: Asia/Shanghai,
+ Cuba Standard Time: America/Havana,
+ Dateline Standard Time: Etc/GMT+12,
+ E. Africa Standard Time: Africa/Nairobi,
+ E. Australia Standard Time: Australia/Brisbane,
+ E. Europe Standard Time: Europe/Chisinau,
+ E. South America Standard Time: America/Sao_Paulo,
+ Easter Island Standard Time: Pacific/Easter,
+ Eastern Standard Time: America/New_York,
+ Eastern Standard Time (Mexico): America/Cancun,
+ Egypt Standard Time: Africa/Cairo,
+ Ekaterinburg Standard Time: Asia/Yekaterinburg,
+ FLE Standard Time: Europe/Kyiv,
+ Fiji Standard Time: Pacific/Fiji,
+ GMT Standard Time: Europe/London,
+ GTB Standard Time: Europe/Bucharest,
+ Georgian Standard Time: Asia/Tbilisi,
+ Greenland Standard Time: America/Nuuk,
+ Greenwich Standard Time: Africa/Abidjan,
+ Haiti Standard Time: America/Port-au-Prince,
+ Hawaiian Standard Time: Pacific/Honolulu,
+ India Standard Time: Asia/Kolkata,
+ Iran Standard Time: Asia/Tehran,
+ Israel Standard Time: Asia/Jerusalem,
+ Jordan Standard Time: Asia/Amman,
+ Kaliningrad Standard Time: Europe/Kaliningrad,
+ Korea Standard Time: Asia/Seoul,
+ Libya Standard Time: Africa/Tripoli,
+ Line Islands Standard Time: Pacific/Kiritimati,
+ Lord Howe Standard Time: Australia/Lord_Howe,
+ Magadan Standard Time: Asia/Magadan,
+ Magallanes Standard Time: America/Punta_Arenas,
+ Marquesas Standard Time: Pacific/Marquesas,
+ Mauritius Standard Time: Indian/Mauritius,
+ Middle East Standard Time: Asia/Beirut,
+ Montevideo Standard Time: America/Montevideo,
+ Morocco Standard Time: Africa/Casablanca,
+ Mountain Standard Time: America/Denver,
+ Mountain Standard Time (Mexico): America/Mazatlan,
+ Myanmar Standard Time: Asia/Yangon,
+ N. Central Asia Standard Time: Asia/Novosibirsk,
+ Namibia Standard Time: Africa/Windhoek,
+ Nepal Standard Time: Asia/Kathmandu,
+ New Zealand Standard Time: Pacific/Auckland,
+ Newfoundland Standard Time: America/St_Johns,
+ Norfolk Standard Time: Pacific/Norfolk,
+ North Asia East Standard Time: Asia/Irkutsk,
+ North Asia Standard Time: Asia/Krasnoyarsk,
+ North Korea Standard Time: Asia/Pyongyang,
+ Omsk Standard Time: Asia/Omsk,
+ Pacific SA Standard Time: America/Santiago,
+ Pacific Standard Time: America/Los_Angeles,
+ Pacific Standard Time (Mexico): America/Tijuana,
+ Pakistan Standard Time: Asia/Karachi,
+ Paraguay Standard Time: America/Asuncion,
+ Qyzylorda Standard Time: Asia/Qyzylorda,
+ Romance Standard Time: Europe/Paris,
+ Russia Time Zone 10: Asia/Srednekolymsk,
+ Russia Time Zone 11: Asia/Kamchatka,
+ Russia Time Zone 3: Europe/Samara,
+ Russian Standard Time: Europe/Moscow,
+ SA Eastern Standard Time: America/Cayenne,
+ SA Pacific Standard Time: America/Bogota,
+ SA Western Standard Time: America/La_Paz,
+ SE Asia Standard Time: Asia/Bangkok,
+ Saint Pierre Standard Time: America/Miquelon,
+ Sakhalin Standard Time: Asia/Sakhalin,
+ Samoa Standard Time: Pacific/Apia,
+ Sao Tome Standard Time: Africa/Sao_Tome,
+ Saratov Standard Time: Europe/Saratov,
+ Singapore Standard Time: Asia/Singapore,
+ South Africa Standard Time: Africa/Johannesburg,
+ South Sudan Standard Time: Africa/Juba,
+ Sri Lanka Standard Time: Asia/Colombo,
+ Sudan Standard Time: Africa/Khartoum,
+ Syria Standard Time: Asia/Damascus,
+ Taipei Standard Time: Asia/Taipei,
+ Tasmania Standard Time: Australia/Hobart,
+ Tocantins Standard Time: America/Araguaina,
+ Tokyo Standard Time: Asia/Tokyo,
+ Tomsk Standard Time: Asia/Tomsk,
+ Tonga Standard Time: Pacific/Tongatapu,
+ Transbaikal Standard Time: Asia/Chita,
+ Turkey Standard Time: Europe/Istanbul,
+ Turks And Caicos Standard Time: America/Grand_Turk,
+ US Eastern Standard Time: America/Indiana/Indianapolis,
+ US Mountain Standard Time: America/Phoenix,
+ UTC: Etc/UTC,
+ UTC+12: Etc/GMT-12,
+ UTC+13: Etc/GMT-13,
+ UTC-02: Etc/GMT+2,
+ UTC-08: Etc/GMT+8,
+ UTC-09: Etc/GMT+9,
+ UTC-11: Etc/GMT+11,
+ Ulaanbaatar Standard Time: Asia/Ulaanbaatar,
+ Venezuela Standard Time: America/Caracas,
+ Vladivostok Standard Time: Asia/Vladivostok,
+ Volgograd Standard Time: Europe/Volgograd,
+ W. Australia Standard Time: Australia/Perth,
+ W. Central Africa Standard Time: Africa/Lagos,
+ W. Europe Standard Time: Europe/Berlin,
+ W. Mongolia Standard Time: Asia/Hovd,
+ West Asia Standard Time: Asia/Tashkent,
+ West Bank Standard Time: Asia/Hebron,
+ West Pacific Standard Time: Pacific/Port_Moresby,
+ Yakutsk Standard Time: Asia/Yakutsk,
+ Yukon Standard Time: America/Whitehorse
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Default.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Default.verified.txt
new file mode 100644
index 0000000..1539491
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Default.verified.txt
@@ -0,0 +1,141 @@
+{
+ AUS Central Standard Time: Australia/Darwin,
+ AUS Eastern Standard Time: Australia/Sydney,
+ Afghanistan Standard Time: Asia/Kabul,
+ Alaskan Standard Time: America/Anchorage,
+ Aleutian Standard Time: America/Adak,
+ Altai Standard Time: Asia/Barnaul,
+ Arab Standard Time: Asia/Riyadh,
+ Arabian Standard Time: Asia/Dubai,
+ Arabic Standard Time: Asia/Baghdad,
+ Argentina Standard Time: America/Argentina/Buenos_Aires,
+ Astrakhan Standard Time: Europe/Astrakhan,
+ Atlantic Standard Time: America/Halifax,
+ Aus Central W. Standard Time: Australia/Eucla,
+ Azerbaijan Standard Time: Asia/Baku,
+ Azores Standard Time: Atlantic/Azores,
+ Bahia Standard Time: America/Bahia,
+ Bangladesh Standard Time: Asia/Dhaka,
+ Belarus Standard Time: Europe/Minsk,
+ Bougainville Standard Time: Pacific/Bougainville,
+ Canada Central Standard Time: America/Regina,
+ Cape Verde Standard Time: Atlantic/Cape_Verde,
+ Caucasus Standard Time: Asia/Yerevan,
+ Cen. Australia Standard Time: Australia/Adelaide,
+ Central America Standard Time: America/Guatemala,
+ Central Asia Standard Time: Asia/Bishkek,
+ Central Brazilian Standard Time: America/Cuiaba,
+ Central Europe Standard Time: Europe/Budapest,
+ Central European Standard Time: Europe/Warsaw,
+ Central Pacific Standard Time: Pacific/Guadalcanal,
+ Central Standard Time: America/Chicago,
+ Central Standard Time (Mexico): America/Mexico_City,
+ Chatham Islands Standard Time: Pacific/Chatham,
+ China Standard Time: Asia/Shanghai,
+ Cuba Standard Time: America/Havana,
+ Dateline Standard Time: Etc/GMT+12,
+ E. Africa Standard Time: Africa/Nairobi,
+ E. Australia Standard Time: Australia/Brisbane,
+ E. Europe Standard Time: Europe/Chisinau,
+ E. South America Standard Time: America/Sao_Paulo,
+ Easter Island Standard Time: Pacific/Easter,
+ Eastern Standard Time: America/New_York,
+ Eastern Standard Time (Mexico): America/Cancun,
+ Egypt Standard Time: Africa/Cairo,
+ Ekaterinburg Standard Time: Asia/Yekaterinburg,
+ FLE Standard Time: Europe/Kyiv,
+ Fiji Standard Time: Pacific/Fiji,
+ GMT Standard Time: Europe/London,
+ GTB Standard Time: Europe/Bucharest,
+ Georgian Standard Time: Asia/Tbilisi,
+ Greenland Standard Time: America/Nuuk,
+ Greenwich Standard Time: Africa/Abidjan,
+ Haiti Standard Time: America/Port-au-Prince,
+ Hawaiian Standard Time: Pacific/Honolulu,
+ India Standard Time: Asia/Kolkata,
+ Iran Standard Time: Asia/Tehran,
+ Israel Standard Time: Asia/Jerusalem,
+ Jordan Standard Time: Asia/Amman,
+ Kaliningrad Standard Time: Europe/Kaliningrad,
+ Korea Standard Time: Asia/Seoul,
+ Libya Standard Time: Africa/Tripoli,
+ Line Islands Standard Time: Pacific/Kiritimati,
+ Lord Howe Standard Time: Australia/Lord_Howe,
+ Magadan Standard Time: Asia/Magadan,
+ Magallanes Standard Time: America/Punta_Arenas,
+ Marquesas Standard Time: Pacific/Marquesas,
+ Mauritius Standard Time: Indian/Mauritius,
+ Middle East Standard Time: Asia/Beirut,
+ Montevideo Standard Time: America/Montevideo,
+ Morocco Standard Time: Africa/Casablanca,
+ Mountain Standard Time: America/Denver,
+ Mountain Standard Time (Mexico): America/Mazatlan,
+ Myanmar Standard Time: Asia/Yangon,
+ N. Central Asia Standard Time: Asia/Novosibirsk,
+ Namibia Standard Time: Africa/Windhoek,
+ Nepal Standard Time: Asia/Kathmandu,
+ New Zealand Standard Time: Pacific/Auckland,
+ Newfoundland Standard Time: America/St_Johns,
+ Norfolk Standard Time: Pacific/Norfolk,
+ North Asia East Standard Time: Asia/Irkutsk,
+ North Asia Standard Time: Asia/Krasnoyarsk,
+ North Korea Standard Time: Asia/Pyongyang,
+ Omsk Standard Time: Asia/Omsk,
+ Pacific SA Standard Time: America/Santiago,
+ Pacific Standard Time: America/Los_Angeles,
+ Pacific Standard Time (Mexico): America/Tijuana,
+ Pakistan Standard Time: Asia/Karachi,
+ Paraguay Standard Time: America/Asuncion,
+ Qyzylorda Standard Time: Asia/Qyzylorda,
+ Romance Standard Time: Europe/Paris,
+ Russia Time Zone 10: Asia/Srednekolymsk,
+ Russia Time Zone 11: Asia/Kamchatka,
+ Russia Time Zone 3: Europe/Samara,
+ Russian Standard Time: Europe/Moscow,
+ SA Eastern Standard Time: America/Cayenne,
+ SA Pacific Standard Time: America/Bogota,
+ SA Western Standard Time: America/La_Paz,
+ SE Asia Standard Time: Asia/Bangkok,
+ Saint Pierre Standard Time: America/Miquelon,
+ Sakhalin Standard Time: Asia/Sakhalin,
+ Samoa Standard Time: Pacific/Apia,
+ Sao Tome Standard Time: Africa/Sao_Tome,
+ Saratov Standard Time: Europe/Saratov,
+ Singapore Standard Time: Asia/Singapore,
+ South Africa Standard Time: Africa/Johannesburg,
+ South Sudan Standard Time: Africa/Juba,
+ Sri Lanka Standard Time: Asia/Colombo,
+ Sudan Standard Time: Africa/Khartoum,
+ Syria Standard Time: Asia/Damascus,
+ Taipei Standard Time: Asia/Taipei,
+ Tasmania Standard Time: Australia/Hobart,
+ Tocantins Standard Time: America/Araguaina,
+ Tokyo Standard Time: Asia/Tokyo,
+ Tomsk Standard Time: Asia/Tomsk,
+ Tonga Standard Time: Pacific/Tongatapu,
+ Transbaikal Standard Time: Asia/Chita,
+ Turkey Standard Time: Europe/Istanbul,
+ Turks And Caicos Standard Time: America/Grand_Turk,
+ US Eastern Standard Time: America/Indiana/Indianapolis,
+ US Mountain Standard Time: America/Phoenix,
+ UTC: Etc/UTC,
+ UTC+12: Etc/GMT-12,
+ UTC+13: Etc/GMT-13,
+ UTC-02: Etc/GMT+2,
+ UTC-08: Etc/GMT+8,
+ UTC-09: Etc/GMT+9,
+ UTC-11: Etc/GMT+11,
+ Ulaanbaatar Standard Time: Asia/Ulaanbaatar,
+ Venezuela Standard Time: America/Caracas,
+ Vladivostok Standard Time: Asia/Vladivostok,
+ Volgograd Standard Time: Europe/Volgograd,
+ W. Australia Standard Time: Australia/Perth,
+ W. Central Africa Standard Time: Africa/Lagos,
+ W. Europe Standard Time: Europe/Berlin,
+ W. Mongolia Standard Time: Asia/Hovd,
+ West Asia Standard Time: Asia/Tashkent,
+ West Bank Standard Time: Asia/Hebron,
+ West Pacific Standard Time: Pacific/Port_Moresby,
+ Yakutsk Standard Time: Asia/Yakutsk,
+ Yukon Standard Time: America/Whitehorse
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Original.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Original.verified.txt
new file mode 100644
index 0000000..ef9d8db
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_IANA_mode=Original.verified.txt
@@ -0,0 +1,141 @@
+{
+ AUS Central Standard Time: Australia/Darwin,
+ AUS Eastern Standard Time: Australia/Sydney,
+ Afghanistan Standard Time: Asia/Kabul,
+ Alaskan Standard Time: America/Anchorage,
+ Aleutian Standard Time: America/Adak,
+ Altai Standard Time: Asia/Barnaul,
+ Arab Standard Time: Asia/Riyadh,
+ Arabian Standard Time: Asia/Dubai,
+ Arabic Standard Time: Asia/Baghdad,
+ Argentina Standard Time: America/Buenos_Aires,
+ Astrakhan Standard Time: Europe/Astrakhan,
+ Atlantic Standard Time: America/Halifax,
+ Aus Central W. Standard Time: Australia/Eucla,
+ Azerbaijan Standard Time: Asia/Baku,
+ Azores Standard Time: Atlantic/Azores,
+ Bahia Standard Time: America/Bahia,
+ Bangladesh Standard Time: Asia/Dhaka,
+ Belarus Standard Time: Europe/Minsk,
+ Bougainville Standard Time: Pacific/Bougainville,
+ Canada Central Standard Time: America/Regina,
+ Cape Verde Standard Time: Atlantic/Cape_Verde,
+ Caucasus Standard Time: Asia/Yerevan,
+ Cen. Australia Standard Time: Australia/Adelaide,
+ Central America Standard Time: America/Guatemala,
+ Central Asia Standard Time: Asia/Bishkek,
+ Central Brazilian Standard Time: America/Cuiaba,
+ Central Europe Standard Time: Europe/Budapest,
+ Central European Standard Time: Europe/Warsaw,
+ Central Pacific Standard Time: Pacific/Guadalcanal,
+ Central Standard Time: America/Chicago,
+ Central Standard Time (Mexico): America/Mexico_City,
+ Chatham Islands Standard Time: Pacific/Chatham,
+ China Standard Time: Asia/Shanghai,
+ Cuba Standard Time: America/Havana,
+ Dateline Standard Time: Etc/GMT+12,
+ E. Africa Standard Time: Africa/Nairobi,
+ E. Australia Standard Time: Australia/Brisbane,
+ E. Europe Standard Time: Europe/Chisinau,
+ E. South America Standard Time: America/Sao_Paulo,
+ Easter Island Standard Time: Pacific/Easter,
+ Eastern Standard Time: America/New_York,
+ Eastern Standard Time (Mexico): America/Cancun,
+ Egypt Standard Time: Africa/Cairo,
+ Ekaterinburg Standard Time: Asia/Yekaterinburg,
+ FLE Standard Time: Europe/Kiev,
+ Fiji Standard Time: Pacific/Fiji,
+ GMT Standard Time: Europe/London,
+ GTB Standard Time: Europe/Bucharest,
+ Georgian Standard Time: Asia/Tbilisi,
+ Greenland Standard Time: America/Godthab,
+ Greenwich Standard Time: Atlantic/Reykjavik,
+ Haiti Standard Time: America/Port-au-Prince,
+ Hawaiian Standard Time: Pacific/Honolulu,
+ India Standard Time: Asia/Calcutta,
+ Iran Standard Time: Asia/Tehran,
+ Israel Standard Time: Asia/Jerusalem,
+ Jordan Standard Time: Asia/Amman,
+ Kaliningrad Standard Time: Europe/Kaliningrad,
+ Korea Standard Time: Asia/Seoul,
+ Libya Standard Time: Africa/Tripoli,
+ Line Islands Standard Time: Pacific/Kiritimati,
+ Lord Howe Standard Time: Australia/Lord_Howe,
+ Magadan Standard Time: Asia/Magadan,
+ Magallanes Standard Time: America/Punta_Arenas,
+ Marquesas Standard Time: Pacific/Marquesas,
+ Mauritius Standard Time: Indian/Mauritius,
+ Middle East Standard Time: Asia/Beirut,
+ Montevideo Standard Time: America/Montevideo,
+ Morocco Standard Time: Africa/Casablanca,
+ Mountain Standard Time: America/Denver,
+ Mountain Standard Time (Mexico): America/Mazatlan,
+ Myanmar Standard Time: Asia/Rangoon,
+ N. Central Asia Standard Time: Asia/Novosibirsk,
+ Namibia Standard Time: Africa/Windhoek,
+ Nepal Standard Time: Asia/Katmandu,
+ New Zealand Standard Time: Pacific/Auckland,
+ Newfoundland Standard Time: America/St_Johns,
+ Norfolk Standard Time: Pacific/Norfolk,
+ North Asia East Standard Time: Asia/Irkutsk,
+ North Asia Standard Time: Asia/Krasnoyarsk,
+ North Korea Standard Time: Asia/Pyongyang,
+ Omsk Standard Time: Asia/Omsk,
+ Pacific SA Standard Time: America/Santiago,
+ Pacific Standard Time: America/Los_Angeles,
+ Pacific Standard Time (Mexico): America/Tijuana,
+ Pakistan Standard Time: Asia/Karachi,
+ Paraguay Standard Time: America/Asuncion,
+ Qyzylorda Standard Time: Asia/Qyzylorda,
+ Romance Standard Time: Europe/Paris,
+ Russia Time Zone 10: Asia/Srednekolymsk,
+ Russia Time Zone 11: Asia/Kamchatka,
+ Russia Time Zone 3: Europe/Samara,
+ Russian Standard Time: Europe/Moscow,
+ SA Eastern Standard Time: America/Cayenne,
+ SA Pacific Standard Time: America/Bogota,
+ SA Western Standard Time: America/La_Paz,
+ SE Asia Standard Time: Asia/Bangkok,
+ Saint Pierre Standard Time: America/Miquelon,
+ Sakhalin Standard Time: Asia/Sakhalin,
+ Samoa Standard Time: Pacific/Apia,
+ Sao Tome Standard Time: Africa/Sao_Tome,
+ Saratov Standard Time: Europe/Saratov,
+ Singapore Standard Time: Asia/Singapore,
+ South Africa Standard Time: Africa/Johannesburg,
+ South Sudan Standard Time: Africa/Juba,
+ Sri Lanka Standard Time: Asia/Colombo,
+ Sudan Standard Time: Africa/Khartoum,
+ Syria Standard Time: Asia/Damascus,
+ Taipei Standard Time: Asia/Taipei,
+ Tasmania Standard Time: Australia/Hobart,
+ Tocantins Standard Time: America/Araguaina,
+ Tokyo Standard Time: Asia/Tokyo,
+ Tomsk Standard Time: Asia/Tomsk,
+ Tonga Standard Time: Pacific/Tongatapu,
+ Transbaikal Standard Time: Asia/Chita,
+ Turkey Standard Time: Europe/Istanbul,
+ Turks And Caicos Standard Time: America/Grand_Turk,
+ US Eastern Standard Time: America/Indianapolis,
+ US Mountain Standard Time: America/Phoenix,
+ UTC: Etc/UTC,
+ UTC+12: Etc/GMT-12,
+ UTC+13: Etc/GMT-13,
+ UTC-02: Etc/GMT+2,
+ UTC-08: Etc/GMT+8,
+ UTC-09: Etc/GMT+9,
+ UTC-11: Etc/GMT+11,
+ Ulaanbaatar Standard Time: Asia/Ulaanbaatar,
+ Venezuela Standard Time: America/Caracas,
+ Vladivostok Standard Time: Asia/Vladivostok,
+ Volgograd Standard Time: Europe/Volgograd,
+ W. Australia Standard Time: Australia/Perth,
+ W. Central Africa Standard Time: Africa/Lagos,
+ W. Europe Standard Time: Europe/Berlin,
+ W. Mongolia Standard Time: Asia/Hovd,
+ West Asia Standard Time: Asia/Tashkent,
+ West Bank Standard Time: Asia/Hebron,
+ West Pacific Standard Time: Pacific/Port_Moresby,
+ Yakutsk Standard Time: Asia/Yakutsk,
+ Yukon Standard Time: America/Whitehorse
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_Rails.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_Rails.verified.txt
new file mode 100644
index 0000000..4972e63
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_Rails.verified.txt
@@ -0,0 +1,431 @@
+{
+ AUS Central Standard Time: [
+ Darwin
+ ],
+ AUS Eastern Standard Time: [
+ Sydney
+ ],
+ Afghanistan Standard Time: [
+ Kabul
+ ],
+ Alaskan Standard Time: [
+ Alaska
+ ],
+ Aleutian Standard Time: [
+ America/Adak
+ ],
+ Altai Standard Time: [
+ Asia/Barnaul
+ ],
+ Arab Standard Time: [
+ Riyadh
+ ],
+ Arabian Standard Time: [
+ Abu Dhabi,
+ Muscat
+ ],
+ Arabic Standard Time: [
+ Baghdad
+ ],
+ Argentina Standard Time: [
+ Buenos Aires
+ ],
+ Astrakhan Standard Time: [
+ Europe/Astrakhan
+ ],
+ Atlantic Standard Time: [
+ Atlantic Time (Canada)
+ ],
+ Aus Central W. Standard Time: [
+ Australia/Eucla
+ ],
+ Azerbaijan Standard Time: [
+ Baku
+ ],
+ Azores Standard Time: [
+ Azores
+ ],
+ Bahia Standard Time: [
+ America/Bahia
+ ],
+ Bangladesh Standard Time: [
+ Dhaka
+ ],
+ Belarus Standard Time: [
+ Minsk
+ ],
+ Bougainville Standard Time: [
+ Pacific/Bougainville
+ ],
+ Canada Central Standard Time: [
+ Saskatchewan
+ ],
+ Cape Verde Standard Time: [
+ Cape Verde Is.
+ ],
+ Caucasus Standard Time: [
+ Yerevan
+ ],
+ Cen. Australia Standard Time: [
+ Adelaide
+ ],
+ Central America Standard Time: [
+ Central America
+ ],
+ Central Asia Standard Time: [
+ Asia/Bishkek
+ ],
+ Central Brazilian Standard Time: [
+ America/Cuiaba
+ ],
+ Central Europe Standard Time: [
+ Budapest
+ ],
+ Central European Standard Time: [
+ Warsaw
+ ],
+ Central Pacific Standard Time: [
+ Solomon Is.
+ ],
+ Central Standard Time: [
+ Central Time (US & Canada)
+ ],
+ Central Standard Time (Mexico): [
+ Guadalajara,
+ Mexico City
+ ],
+ Chatham Islands Standard Time: [
+ Chatham Is.
+ ],
+ China Standard Time: [
+ Beijing
+ ],
+ Cuba Standard Time: [
+ America/Havana
+ ],
+ Dateline Standard Time: [
+ International Date Line West
+ ],
+ E. Africa Standard Time: [
+ Nairobi
+ ],
+ E. Australia Standard Time: [
+ Brisbane
+ ],
+ E. Europe Standard Time: [
+ Europe/Chisinau
+ ],
+ E. South America Standard Time: [
+ Brasilia
+ ],
+ Easter Island Standard Time: [
+ Pacific/Easter
+ ],
+ Eastern Standard Time: [
+ Eastern Time (US & Canada)
+ ],
+ Eastern Standard Time (Mexico): [
+ America/Cancun
+ ],
+ Egypt Standard Time: [
+ Cairo
+ ],
+ Ekaterinburg Standard Time: [
+ Ekaterinburg
+ ],
+ FLE Standard Time: [
+ Kyiv
+ ],
+ Fiji Standard Time: [
+ Fiji
+ ],
+ GMT Standard Time: [
+ Edinburgh,
+ London
+ ],
+ GTB Standard Time: [
+ Bucharest
+ ],
+ Georgian Standard Time: [
+ Tbilisi
+ ],
+ Greenland Standard Time: [
+ Greenland
+ ],
+ Greenwich Standard Time: [
+ Africa/Abidjan
+ ],
+ Haiti Standard Time: [
+ America/Port-au-Prince
+ ],
+ Hawaiian Standard Time: [
+ Hawaii
+ ],
+ India Standard Time: [
+ Chennai,
+ Kolkata,
+ Mumbai,
+ New Delhi
+ ],
+ Iran Standard Time: [
+ Tehran
+ ],
+ Israel Standard Time: [
+ Jerusalem
+ ],
+ Jordan Standard Time: [
+ Asia/Amman
+ ],
+ Kaliningrad Standard Time: [
+ Kaliningrad
+ ],
+ Korea Standard Time: [
+ Seoul
+ ],
+ Libya Standard Time: [
+ Africa/Tripoli
+ ],
+ Line Islands Standard Time: [
+ Pacific/Kiritimati
+ ],
+ Lord Howe Standard Time: [
+ Australia/Lord_Howe
+ ],
+ Magadan Standard Time: [
+ Magadan
+ ],
+ Magallanes Standard Time: [
+ America/Punta_Arenas
+ ],
+ Marquesas Standard Time: [
+ Pacific/Marquesas
+ ],
+ Mauritius Standard Time: [
+ Indian/Mauritius
+ ],
+ Middle East Standard Time: [
+ Asia/Beirut
+ ],
+ Montevideo Standard Time: [
+ Montevideo
+ ],
+ Morocco Standard Time: [
+ Casablanca
+ ],
+ Mountain Standard Time: [
+ Mountain Time (US & Canada)
+ ],
+ Mountain Standard Time (Mexico): [
+ Mazatlan
+ ],
+ Myanmar Standard Time: [
+ Rangoon
+ ],
+ N. Central Asia Standard Time: [
+ Novosibirsk
+ ],
+ Namibia Standard Time: [
+ Africa/Windhoek
+ ],
+ Nepal Standard Time: [
+ Kathmandu
+ ],
+ New Zealand Standard Time: [
+ Auckland,
+ Wellington
+ ],
+ Newfoundland Standard Time: [
+ Newfoundland
+ ],
+ Norfolk Standard Time: [
+ Pacific/Norfolk
+ ],
+ North Asia East Standard Time: [
+ Irkutsk
+ ],
+ North Asia Standard Time: [
+ Krasnoyarsk
+ ],
+ North Korea Standard Time: [
+ Asia/Pyongyang
+ ],
+ Omsk Standard Time: [
+ Asia/Omsk
+ ],
+ Pacific SA Standard Time: [
+ Santiago
+ ],
+ Pacific Standard Time: [
+ Pacific Time (US & Canada)
+ ],
+ Pacific Standard Time (Mexico): [
+ Tijuana
+ ],
+ Pakistan Standard Time: [
+ Islamabad,
+ Karachi
+ ],
+ Paraguay Standard Time: [
+ Asuncion
+ ],
+ Qyzylorda Standard Time: [
+ Asia/Qyzylorda
+ ],
+ Romance Standard Time: [
+ Paris
+ ],
+ Russia Time Zone 10: [
+ Srednekolymsk
+ ],
+ Russia Time Zone 11: [
+ Kamchatka
+ ],
+ Russia Time Zone 3: [
+ Samara
+ ],
+ Russian Standard Time: [
+ Moscow,
+ St. Petersburg
+ ],
+ SA Eastern Standard Time: [
+ America/Cayenne
+ ],
+ SA Pacific Standard Time: [
+ Bogota
+ ],
+ SA Western Standard Time: [
+ La Paz
+ ],
+ SE Asia Standard Time: [
+ Bangkok,
+ Hanoi
+ ],
+ Saint Pierre Standard Time: [
+ America/Miquelon
+ ],
+ Sakhalin Standard Time: [
+ Asia/Sakhalin
+ ],
+ Samoa Standard Time: [
+ Samoa
+ ],
+ Sao Tome Standard Time: [
+ Africa/Sao_Tome
+ ],
+ Saratov Standard Time: [
+ Europe/Saratov
+ ],
+ Singapore Standard Time: [
+ Singapore
+ ],
+ South Africa Standard Time: [
+ Pretoria
+ ],
+ South Sudan Standard Time: [
+ Africa/Juba
+ ],
+ Sri Lanka Standard Time: [
+ Sri Jayawardenepura
+ ],
+ Sudan Standard Time: [
+ Africa/Khartoum
+ ],
+ Syria Standard Time: [
+ Asia/Damascus
+ ],
+ Taipei Standard Time: [
+ Taipei
+ ],
+ Tasmania Standard Time: [
+ Hobart
+ ],
+ Tocantins Standard Time: [
+ America/Araguaina
+ ],
+ Tokyo Standard Time: [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ Tomsk Standard Time: [
+ Asia/Tomsk
+ ],
+ Tonga Standard Time: [
+ Nuku'alofa
+ ],
+ Transbaikal Standard Time: [
+ Asia/Chita
+ ],
+ Turkey Standard Time: [
+ Istanbul
+ ],
+ Turks And Caicos Standard Time: [
+ America/Grand_Turk
+ ],
+ US Eastern Standard Time: [
+ Indiana (East)
+ ],
+ US Mountain Standard Time: [
+ Arizona
+ ],
+ UTC: [
+ UTC
+ ],
+ UTC+12: [
+ +12:00
+ ],
+ UTC+13: [
+ +13:00
+ ],
+ UTC-02: [
+ Etc/GMT+2
+ ],
+ UTC-08: [
+ Etc/GMT+8
+ ],
+ UTC-09: [
+ Etc/GMT+9
+ ],
+ UTC-11: [
+ -11:00
+ ],
+ Ulaanbaatar Standard Time: [
+ Ulaanbaatar
+ ],
+ Venezuela Standard Time: [
+ Caracas
+ ],
+ Vladivostok Standard Time: [
+ Vladivostok
+ ],
+ Volgograd Standard Time: [
+ Volgograd
+ ],
+ W. Australia Standard Time: [
+ Perth
+ ],
+ W. Central Africa Standard Time: [
+ Africa/Lagos
+ ],
+ W. Europe Standard Time: [
+ Berlin
+ ],
+ W. Mongolia Standard Time: [
+ Asia/Hovd
+ ],
+ West Asia Standard Time: [
+ Tashkent
+ ],
+ West Bank Standard Time: [
+ Asia/Hebron
+ ],
+ West Pacific Standard Time: [
+ Port Moresby
+ ],
+ Yakutsk Standard Time: [
+ Yakutsk
+ ],
+ Yukon Standard Time: [
+ America/Whitehorse
+ ]
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_Rails_Regional.verified.txt b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_Rails_Regional.verified.txt
new file mode 100644
index 0000000..309c4a2
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.Windows_To_Rails_Regional.verified.txt
@@ -0,0 +1,782 @@
+{
+ (AUS Central Standard Time, 001): [
+ Darwin
+ ],
+ (AUS Eastern Standard Time, 001): [
+ Sydney
+ ],
+ (Afghanistan Standard Time, 001): [
+ Kabul
+ ],
+ (Alaskan Standard Time, 001): [
+ Alaska
+ ],
+ (Aleutian Standard Time, 001): [
+ America/Adak
+ ],
+ (Altai Standard Time, 001): [
+ Asia/Barnaul
+ ],
+ (Arab Standard Time, 001): [
+ Riyadh
+ ],
+ (Arab Standard Time, KW): [
+ Kuwait
+ ],
+ (Arabian Standard Time, 001): [
+ Abu Dhabi,
+ Muscat
+ ],
+ (Arabic Standard Time, 001): [
+ Baghdad
+ ],
+ (Argentina Standard Time, 001): [
+ Buenos Aires
+ ],
+ (Astrakhan Standard Time, 001): [
+ Europe/Astrakhan
+ ],
+ (Atlantic Standard Time, 001): [
+ Atlantic Time (Canada)
+ ],
+ (Aus Central W. Standard Time, 001): [
+ Australia/Eucla
+ ],
+ (Azerbaijan Standard Time, 001): [
+ Baku
+ ],
+ (Azores Standard Time, 001): [
+ Azores
+ ],
+ (Bahia Standard Time, 001): [
+ America/Bahia
+ ],
+ (Bangladesh Standard Time, 001): [
+ Dhaka
+ ],
+ (Belarus Standard Time, 001): [
+ Minsk
+ ],
+ (Bougainville Standard Time, 001): [
+ Pacific/Bougainville
+ ],
+ (Canada Central Standard Time, 001): [
+ Saskatchewan
+ ],
+ (Cape Verde Standard Time, 001): [
+ Cape Verde Is.
+ ],
+ (Caucasus Standard Time, 001): [
+ Yerevan
+ ],
+ (Cen. Australia Standard Time, 001): [
+ Adelaide
+ ],
+ (Central America Standard Time, 001): [
+ Central America
+ ],
+ (Central Asia Standard Time, 001): [
+ Asia/Bishkek
+ ],
+ (Central Asia Standard Time, CN): [
+ Urumqi
+ ],
+ (Central Asia Standard Time, DG): [
+ Indian/Chagos
+ ],
+ (Central Asia Standard Time, IO): [
+ Indian/Chagos
+ ],
+ (Central Brazilian Standard Time, 001): [
+ America/Cuiaba
+ ],
+ (Central Europe Standard Time, 001): [
+ Budapest
+ ],
+ (Central Europe Standard Time, CZ): [
+ Prague
+ ],
+ (Central Europe Standard Time, ME): [
+ Belgrade
+ ],
+ (Central Europe Standard Time, RS): [
+ Belgrade
+ ],
+ (Central Europe Standard Time, SI): [
+ Ljubljana
+ ],
+ (Central Europe Standard Time, SK): [
+ Bratislava
+ ],
+ (Central Europe Standard Time, XK): [
+ Belgrade
+ ],
+ (Central European Standard Time, 001): [
+ Warsaw
+ ],
+ (Central European Standard Time, BA): [
+ Sarajevo
+ ],
+ (Central European Standard Time, HR): [
+ Zagreb
+ ],
+ (Central European Standard Time, MK): [
+ Skopje
+ ],
+ (Central Pacific Standard Time, 001): [
+ Solomon Is.
+ ],
+ (Central Pacific Standard Time, NC): [
+ New Caledonia
+ ],
+ (Central Standard Time (Mexico), 001): [
+ Guadalajara,
+ Mexico City
+ ],
+ (Central Standard Time, 001): [
+ Central Time (US & Canada)
+ ],
+ (Chatham Islands Standard Time, 001): [
+ Chatham Is.
+ ],
+ (China Standard Time, 001): [
+ Beijing
+ ],
+ (China Standard Time, HK): [
+ Hong Kong
+ ],
+ (Cuba Standard Time, 001): [
+ America/Havana
+ ],
+ (Dateline Standard Time, 001): [
+ International Date Line West
+ ],
+ (E. Africa Standard Time, 001): [
+ Nairobi
+ ],
+ (E. Australia Standard Time, 001): [
+ Brisbane
+ ],
+ (E. Europe Standard Time, 001): [
+ Europe/Chisinau
+ ],
+ (E. South America Standard Time, 001): [
+ Brasilia
+ ],
+ (Easter Island Standard Time, 001): [
+ Pacific/Easter
+ ],
+ (Eastern Standard Time (Mexico), 001): [
+ America/Cancun
+ ],
+ (Eastern Standard Time, 001): [
+ Eastern Time (US & Canada)
+ ],
+ (Egypt Standard Time, 001): [
+ Cairo
+ ],
+ (Ekaterinburg Standard Time, 001): [
+ Ekaterinburg
+ ],
+ (FLE Standard Time, 001): [
+ Kyiv
+ ],
+ (FLE Standard Time, AX): [
+ Helsinki
+ ],
+ (FLE Standard Time, BG): [
+ Sofia
+ ],
+ (FLE Standard Time, EE): [
+ Tallinn
+ ],
+ (FLE Standard Time, FI): [
+ Helsinki
+ ],
+ (FLE Standard Time, LT): [
+ Vilnius
+ ],
+ (FLE Standard Time, LV): [
+ Riga
+ ],
+ (Fiji Standard Time, 001): [
+ Fiji
+ ],
+ (GMT Standard Time, 001): [
+ Edinburgh,
+ London
+ ],
+ (GMT Standard Time, IE): [
+ Dublin
+ ],
+ (GMT Standard Time, PT): [
+ Lisbon
+ ],
+ (GTB Standard Time, 001): [
+ Bucharest
+ ],
+ (GTB Standard Time, GR): [
+ Athens
+ ],
+ (Georgian Standard Time, 001): [
+ Tbilisi
+ ],
+ (Greenland Standard Time, 001): [
+ Greenland
+ ],
+ (Greenwich Standard Time, 001): [
+ Africa/Abidjan
+ ],
+ (Greenwich Standard Time, BF): [
+ Africa/Ouagadougou
+ ],
+ (Greenwich Standard Time, GH): [
+ Africa/Accra
+ ],
+ (Greenwich Standard Time, GL): [
+ America/Danmarkshavn
+ ],
+ (Greenwich Standard Time, GM): [
+ Africa/Banjul
+ ],
+ (Greenwich Standard Time, GN): [
+ Africa/Conakry
+ ],
+ (Greenwich Standard Time, GW): [
+ Africa/Bissau
+ ],
+ (Greenwich Standard Time, LR): [
+ Monrovia
+ ],
+ (Greenwich Standard Time, ML): [
+ Africa/Bamako
+ ],
+ (Greenwich Standard Time, MR): [
+ Africa/Nouakchott
+ ],
+ (Greenwich Standard Time, SH): [
+ Atlantic/St_Helena
+ ],
+ (Greenwich Standard Time, SL): [
+ Africa/Freetown
+ ],
+ (Greenwich Standard Time, SN): [
+ Africa/Dakar
+ ],
+ (Greenwich Standard Time, TG): [
+ Africa/Lome
+ ],
+ (Haiti Standard Time, 001): [
+ America/Port-au-Prince
+ ],
+ (Hawaiian Standard Time, 001): [
+ Hawaii
+ ],
+ (India Standard Time, 001): [
+ Chennai,
+ Kolkata,
+ Mumbai,
+ New Delhi
+ ],
+ (Iran Standard Time, 001): [
+ Tehran
+ ],
+ (Israel Standard Time, 001): [
+ Jerusalem
+ ],
+ (Jordan Standard Time, 001): [
+ Asia/Amman
+ ],
+ (Kaliningrad Standard Time, 001): [
+ Kaliningrad
+ ],
+ (Korea Standard Time, 001): [
+ Seoul
+ ],
+ (Libya Standard Time, 001): [
+ Africa/Tripoli
+ ],
+ (Line Islands Standard Time, 001): [
+ Pacific/Kiritimati
+ ],
+ (Lord Howe Standard Time, 001): [
+ Australia/Lord_Howe
+ ],
+ (Magadan Standard Time, 001): [
+ Magadan
+ ],
+ (Magallanes Standard Time, 001): [
+ America/Punta_Arenas
+ ],
+ (Marquesas Standard Time, 001): [
+ Pacific/Marquesas
+ ],
+ (Mauritius Standard Time, 001): [
+ Indian/Mauritius
+ ],
+ (Mauritius Standard Time, RE): [
+ Abu Dhabi,
+ Muscat
+ ],
+ (Mauritius Standard Time, SC): [
+ Abu Dhabi,
+ Muscat
+ ],
+ (Middle East Standard Time, 001): [
+ Asia/Beirut
+ ],
+ (Montevideo Standard Time, 001): [
+ Montevideo
+ ],
+ (Morocco Standard Time, 001): [
+ Casablanca
+ ],
+ (Mountain Standard Time (Mexico), 001): [
+ Mazatlan
+ ],
+ (Mountain Standard Time, 001): [
+ Mountain Time (US & Canada)
+ ],
+ (Myanmar Standard Time, 001): [
+ Rangoon
+ ],
+ (N. Central Asia Standard Time, 001): [
+ Novosibirsk
+ ],
+ (Namibia Standard Time, 001): [
+ Africa/Windhoek
+ ],
+ (Nepal Standard Time, 001): [
+ Kathmandu
+ ],
+ (New Zealand Standard Time, 001): [
+ Auckland,
+ Wellington
+ ],
+ (Newfoundland Standard Time, 001): [
+ Newfoundland
+ ],
+ (Norfolk Standard Time, 001): [
+ Pacific/Norfolk
+ ],
+ (North Asia East Standard Time, 001): [
+ Irkutsk
+ ],
+ (North Asia Standard Time, 001): [
+ Krasnoyarsk
+ ],
+ (North Korea Standard Time, 001): [
+ Asia/Pyongyang
+ ],
+ (Omsk Standard Time, 001): [
+ Asia/Omsk
+ ],
+ (Pacific SA Standard Time, 001): [
+ Santiago
+ ],
+ (Pacific Standard Time (Mexico), 001): [
+ Tijuana
+ ],
+ (Pacific Standard Time, 001): [
+ Pacific Time (US & Canada)
+ ],
+ (Pakistan Standard Time, 001): [
+ Islamabad,
+ Karachi
+ ],
+ (Paraguay Standard Time, 001): [
+ Asuncion
+ ],
+ (Qyzylorda Standard Time, 001): [
+ Asia/Qyzylorda
+ ],
+ (Romance Standard Time, 001): [
+ Paris
+ ],
+ (Romance Standard Time, BE): [
+ Brussels
+ ],
+ (Romance Standard Time, DK): [
+ Copenhagen
+ ],
+ (Romance Standard Time, EA): [
+ Madrid
+ ],
+ (Romance Standard Time, ES): [
+ Madrid
+ ],
+ (Russia Time Zone 10, 001): [
+ Srednekolymsk
+ ],
+ (Russia Time Zone 11, 001): [
+ Kamchatka
+ ],
+ (Russia Time Zone 3, 001): [
+ Samara
+ ],
+ (Russian Standard Time, 001): [
+ Moscow,
+ St. Petersburg
+ ],
+ (SA Eastern Standard Time, 001): [
+ America/Cayenne
+ ],
+ (SA Eastern Standard Time, BR): [
+ America/Fortaleza
+ ],
+ (SA Eastern Standard Time, FK): [
+ Atlantic/Stanley
+ ],
+ (SA Eastern Standard Time, SR): [
+ America/Paramaribo
+ ],
+ (SA Pacific Standard Time, 001): [
+ Bogota
+ ],
+ (SA Pacific Standard Time, PE): [
+ Lima,
+ Quito
+ ],
+ (SA Western Standard Time, 001): [
+ La Paz
+ ],
+ (SA Western Standard Time, AG): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, AI): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, AW): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, BL): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, BQ): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, CA): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, CW): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, DM): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, GD): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, GP): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, GY): [
+ Georgetown
+ ],
+ (SA Western Standard Time, KN): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, LC): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, MF): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, MS): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, PR): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, SX): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, TT): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, VC): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, VG): [
+ Puerto Rico
+ ],
+ (SA Western Standard Time, VI): [
+ Puerto Rico
+ ],
+ (SE Asia Standard Time, 001): [
+ Bangkok,
+ Hanoi
+ ],
+ (SE Asia Standard Time, ID): [
+ Jakarta
+ ],
+ (Saint Pierre Standard Time, 001): [
+ America/Miquelon
+ ],
+ (Sakhalin Standard Time, 001): [
+ Asia/Sakhalin
+ ],
+ (Samoa Standard Time, 001): [
+ Samoa
+ ],
+ (Sao Tome Standard Time, 001): [
+ Africa/Sao_Tome
+ ],
+ (Saratov Standard Time, 001): [
+ Europe/Saratov
+ ],
+ (Singapore Standard Time, 001): [
+ Singapore
+ ],
+ (Singapore Standard Time, BN): [
+ Kuala Lumpur
+ ],
+ (Singapore Standard Time, MY): [
+ Kuala Lumpur
+ ],
+ (South Africa Standard Time, 001): [
+ Pretoria
+ ],
+ (South Africa Standard Time, CD): [
+ Harare
+ ],
+ (South Africa Standard Time, MZ): [
+ Harare
+ ],
+ (South Africa Standard Time, RW): [
+ Harare
+ ],
+ (South Africa Standard Time, ZM): [
+ Harare
+ ],
+ (South Africa Standard Time, ZW): [
+ Harare
+ ],
+ (South Sudan Standard Time, 001): [
+ Africa/Juba
+ ],
+ (Sri Lanka Standard Time, 001): [
+ Sri Jayawardenepura
+ ],
+ (Sudan Standard Time, 001): [
+ Africa/Khartoum
+ ],
+ (Syria Standard Time, 001): [
+ Asia/Damascus
+ ],
+ (Taipei Standard Time, 001): [
+ Taipei
+ ],
+ (Tasmania Standard Time, 001): [
+ Hobart
+ ],
+ (Tocantins Standard Time, 001): [
+ America/Araguaina
+ ],
+ (Tokyo Standard Time, 001): [
+ Osaka,
+ Sapporo,
+ Tokyo
+ ],
+ (Tomsk Standard Time, 001): [
+ Asia/Tomsk
+ ],
+ (Tonga Standard Time, 001): [
+ Nuku'alofa
+ ],
+ (Transbaikal Standard Time, 001): [
+ Asia/Chita
+ ],
+ (Turkey Standard Time, 001): [
+ Istanbul
+ ],
+ (Turks And Caicos Standard Time, 001): [
+ America/Grand_Turk
+ ],
+ (US Eastern Standard Time, 001): [
+ Indiana (East)
+ ],
+ (US Mountain Standard Time, 001): [
+ Arizona
+ ],
+ (UTC+12, 001): [
+ +12:00
+ ],
+ (UTC+12, KI): [
+ Marshall Is.
+ ],
+ (UTC+12, MH): [
+ Marshall Is.
+ ],
+ (UTC+12, NR): [
+ Pacific/Nauru
+ ],
+ (UTC+12, TV): [
+ Pacific/Funafuti
+ ],
+ (UTC+12, UM): [
+ Marshall Is.
+ ],
+ (UTC+12, WF): [
+ Marshall Is.
+ ],
+ (UTC+13, 001): [
+ +13:00
+ ],
+ (UTC+13, KI): [
+ Pacific/Kanton
+ ],
+ (UTC+13, TK): [
+ Tokelau Is.
+ ],
+ (UTC, 001): [
+ UTC
+ ],
+ (UTC-02, 001): [
+ Etc/GMT+2
+ ],
+ (UTC-02, BR): [
+ America/Noronha
+ ],
+ (UTC-08, 001): [
+ Etc/GMT+8
+ ],
+ (UTC-08, PN): [
+ Pacific/Pitcairn
+ ],
+ (UTC-09, 001): [
+ Etc/GMT+9
+ ],
+ (UTC-09, PF): [
+ Pacific/Gambier
+ ],
+ (UTC-11, 001): [
+ -11:00
+ ],
+ (UTC-11, AS): [
+ American Samoa
+ ],
+ (UTC-11, NU): [
+ Pacific/Niue
+ ],
+ (UTC-11, UM): [
+ Midway Island
+ ],
+ (Ulaanbaatar Standard Time, 001): [
+ Ulaanbaatar
+ ],
+ (Venezuela Standard Time, 001): [
+ Caracas
+ ],
+ (Vladivostok Standard Time, 001): [
+ Vladivostok
+ ],
+ (Volgograd Standard Time, 001): [
+ Volgograd
+ ],
+ (W. Australia Standard Time, 001): [
+ Perth
+ ],
+ (W. Central Africa Standard Time, 001): [
+ Africa/Lagos
+ ],
+ (W. Central Africa Standard Time, AO): [
+ Africa/Luanda
+ ],
+ (W. Central Africa Standard Time, BJ): [
+ Africa/Porto-Novo
+ ],
+ (W. Central Africa Standard Time, CD): [
+ Africa/Kinshasa
+ ],
+ (W. Central Africa Standard Time, CF): [
+ Africa/Bangui
+ ],
+ (W. Central Africa Standard Time, CG): [
+ Africa/Brazzaville
+ ],
+ (W. Central Africa Standard Time, CM): [
+ Africa/Douala
+ ],
+ (W. Central Africa Standard Time, DZ): [
+ West Central Africa
+ ],
+ (W. Central Africa Standard Time, GA): [
+ Africa/Libreville
+ ],
+ (W. Central Africa Standard Time, GQ): [
+ Africa/Malabo
+ ],
+ (W. Central Africa Standard Time, NE): [
+ Africa/Niamey
+ ],
+ (W. Central Africa Standard Time, TD): [
+ Africa/Ndjamena
+ ],
+ (W. Central Africa Standard Time, TN): [
+ Africa/Tunis
+ ],
+ (W. Europe Standard Time, 001): [
+ Berlin
+ ],
+ (W. Europe Standard Time, AT): [
+ Vienna
+ ],
+ (W. Europe Standard Time, CH): [
+ Bern,
+ Zurich
+ ],
+ (W. Europe Standard Time, IT): [
+ Rome
+ ],
+ (W. Europe Standard Time, LI): [
+ Bern,
+ Zurich
+ ],
+ (W. Europe Standard Time, LU): [
+ Brussels
+ ],
+ (W. Europe Standard Time, MC): [
+ Paris
+ ],
+ (W. Europe Standard Time, NL): [
+ Amsterdam
+ ],
+ (W. Europe Standard Time, SE): [
+ Stockholm
+ ],
+ (W. Europe Standard Time, SM): [
+ Rome
+ ],
+ (W. Europe Standard Time, VA): [
+ Rome
+ ],
+ (W. Mongolia Standard Time, 001): [
+ Asia/Hovd
+ ],
+ (West Asia Standard Time, 001): [
+ Tashkent
+ ],
+ (West Asia Standard Time, KZ): [
+ Almaty,
+ Astana
+ ],
+ (West Bank Standard Time, 001): [
+ Asia/Hebron
+ ],
+ (West Pacific Standard Time, 001): [
+ Port Moresby
+ ],
+ (West Pacific Standard Time, GU): [
+ Guam
+ ],
+ (West Pacific Standard Time, MP): [
+ Guam
+ ],
+ (Yakutsk Standard Time, 001): [
+ Yakutsk
+ ],
+ (Yukon Standard Time, 001): [
+ America/Whitehorse
+ ]
+}
\ No newline at end of file
diff --git a/test/TimeZoneConverter.Tests/DataVerificationTests.cs b/test/TimeZoneConverter.Tests/DataVerificationTests.cs
new file mode 100644
index 0000000..f123a07
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/DataVerificationTests.cs
@@ -0,0 +1,128 @@
+namespace TimeZoneConverter.Tests;
+
+public class DataVerificationTests
+{
+ [Fact]
+ public Task IANA_To_Windows()
+ {
+ var ianaZones = TZConvert.KnownIanaTimeZoneNames;
+ var allMappings = ianaZones.ToDictionary(
+ ianaId => ianaId,
+ ianaId => TZConvert.TryIanaToWindows(ianaId, out var windowsId) ? windowsId : null)
+ .Sorted();
+ return Verify(allMappings);
+ }
+
+ [Theory]
+ [InlineData(LinkResolution.Default)]
+ [InlineData(LinkResolution.Canonical)]
+ [InlineData(LinkResolution.Original)]
+ public Task Windows_To_IANA(LinkResolution mode)
+ {
+ var windowsZones = TZConvert.KnownWindowsTimeZoneIds;
+ var allMappings = windowsZones.ToDictionary(
+ windowsId => windowsId,
+ windowsId => TZConvert.TryWindowsToIana(windowsId, out var ianaId, mode) ? ianaId : null)
+ .Sorted();
+ return Verify(allMappings).UseParameters(mode);
+ }
+
+ [Theory]
+ [InlineData(LinkResolution.Default)]
+ [InlineData(LinkResolution.Canonical)]
+ [InlineData(LinkResolution.Original)]
+ public Task Windows_To_IANA_Regional(LinkResolution mode)
+ {
+ var windowsZones = TZConvert.KnownWindowsTimeZoneIds;
+
+ var allMappings = windowsZones
+ .SelectMany(windowsId => TestData.Regions.Select(region => (WindowsId: windowsId, Region: region)))
+ .Select(x => (x.WindowsId, x.Region,
+ IanaId: TZConvert.TryWindowsToIana(x.WindowsId, x.Region, out var ianaId, mode) ? ianaId : null))
+ .GroupBy(x => x.WindowsId)
+ .SelectMany(x =>
+ {
+ var primary = x.First(y => y.Region == "001");
+ return x.Where(y => y.Region == primary.Region || y.IanaId != primary.IanaId);
+ })
+ .ToDictionary(x => $"({x.WindowsId}, {x.Region})", x => x.IanaId)
+ .Sorted();
+ return Verify(allMappings).UseParameters(mode);
+ }
+
+ [Fact]
+ public Task Windows_To_Rails()
+ {
+ var windowsZones = TZConvert.KnownWindowsTimeZoneIds;
+ var allMappings = windowsZones.ToDictionary(
+ windowsId => windowsId,
+ windowsId => TZConvert.TryWindowsToRails(windowsId, out var railsIds) ? railsIds : null)
+ .Sorted();
+ return Verify(allMappings);
+ }
+
+ [Fact]
+ public Task Windows_To_Rails_Regional()
+ {
+ var windowsZones = TZConvert.KnownWindowsTimeZoneIds;
+
+ var allMappings = windowsZones
+ .SelectMany(windowsId => TestData.Regions.Select(region => (WindowsId: windowsId, Region: region)))
+ .Select(x => (x.WindowsId, x.Region,
+ RailsIds: TZConvert.TryWindowsToRails(x.WindowsId, x.Region, out var railsIds) ? railsIds : null))
+ .GroupBy(x => x.WindowsId)
+ .SelectMany(x =>
+ {
+ var primary = x.First(y => y.Region == "001");
+ return x.Where(y =>
+ y.Region == primary.Region ||
+ (primary.RailsIds != null && y.RailsIds?.SequenceEqual(primary.RailsIds) is not true)
+ );
+ })
+ .ToDictionary(x => $"({x.WindowsId}, {x.Region})", x => x.RailsIds)
+ .Sorted();
+ return Verify(allMappings);
+ }
+
+ [Fact]
+ public Task Iana_To_Rails()
+ {
+ var ianaZones = TZConvert.KnownIanaTimeZoneNames;
+ var allMappings = ianaZones.ToDictionary(
+ ianaId => ianaId,
+ ianaId => TZConvert.TryIanaToRails(ianaId, out var railsIds) ? railsIds : null)
+ .Sorted();
+ return Verify(allMappings);
+ }
+
+ [Fact]
+ public Task Rails_To_Iana()
+ {
+ var railsZones = TZConvert.KnownRailsTimeZoneNames;
+ var allMappings = railsZones.ToDictionary(
+ railsId => railsId,
+ railsId => TZConvert.TryRailsToIana(railsId, out var ianaId) ? ianaId : null)
+ .Sorted();
+ return Verify(allMappings);
+ }
+
+ [Fact]
+ public Task Rails_To_Windows()
+ {
+ var railsZones = TZConvert.KnownRailsTimeZoneNames;
+ var allMappings = railsZones.ToDictionary(
+ railsId => railsId,
+ railsId => TZConvert.TryRailsToWindows(railsId, out var windowsId) ? windowsId : null)
+ .Sorted();
+ return Verify(allMappings);
+ }
+
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ public Task Iana_Territories(bool fullList)
+ {
+ var territories = TZConvert.GetIanaTimeZoneNamesByTerritory(fullList);
+ return Verify(territories).UseParameters(fullList);
+ }
+}
diff --git a/test/TimeZoneConverter.Tests/IanaToRailsTests.cs b/test/TimeZoneConverter.Tests/IanaToRailsTests.cs
index 8641ad5..9d4a56a 100644
--- a/test/TimeZoneConverter.Tests/IanaToRailsTests.cs
+++ b/test/TimeZoneConverter.Tests/IanaToRailsTests.cs
@@ -1,161 +1,152 @@
-using System.Collections.Generic;
-using System.Linq;
-using Xunit;
using Xunit.Abstractions;
-namespace TimeZoneConverter.Tests
+namespace TimeZoneConverter.Tests;
+
+public class IanaToRailsTests(ITestOutputHelper output)
{
- public class IanaToRailsTests
- {
- private readonly ITestOutputHelper _output;
+ private static IEnumerable UnmappableZones =>
+ [
+ "Africa/Abidjan",
+ "Africa/Accra",
+ "Africa/Bamako",
+ "Africa/Bangui",
+ "Africa/Banjul",
+ "Africa/Bissau",
+ "Africa/Brazzaville",
+ "Africa/Conakry",
+ "Africa/Dakar",
+ "Africa/Douala",
+ "Africa/Freetown",
+ "Africa/Juba",
+ "Africa/Khartoum",
+ "Africa/Kinshasa",
+ "Africa/Lagos",
+ "Africa/Libreville",
+ "Africa/Lome",
+ "Africa/Luanda",
+ "Africa/Malabo",
+ "Africa/Ndjamena",
+ "Africa/Niamey",
+ "Africa/Nouakchott",
+ "Africa/Ouagadougou",
+ "Africa/Porto-Novo",
+ "Africa/Sao_Tome",
+ "Africa/Timbuktu",
+ "Africa/Tripoli",
+ "Africa/Tunis",
+ "Africa/Windhoek",
+ "America/Adak",
+ "America/Araguaina",
+ "America/Atka",
+ "America/Bahia",
+ "America/Belem",
+ "America/Campo_Grande",
+ "America/Cancun",
+ "America/Cayenne",
+ "America/Coyhaique",
+ "America/Cuiaba",
+ "America/Danmarkshavn",
+ "America/Dawson",
+ "America/Fortaleza",
+ "America/Grand_Turk",
+ "America/Havana",
+ "America/Maceio",
+ "America/Miquelon",
+ "America/Noronha",
+ "America/Paramaribo",
+ "America/Port-au-Prince",
+ "America/Punta_Arenas",
+ "America/Recife",
+ "America/Santarem",
+ "America/Whitehorse",
+ "Antarctica/Palmer",
+ "Antarctica/Rothera",
+ "Antarctica/Troll",
+ "Antarctica/Vostok",
+ "Asia/Amman",
+ "Asia/Barnaul",
+ "Asia/Beirut",
+ "Asia/Bishkek",
+ "Asia/Chita",
+ "Asia/Damascus",
+ "Asia/Gaza",
+ "Asia/Hebron",
+ "Asia/Hovd",
+ "Asia/Omsk",
+ "Asia/Pyongyang",
+ "Asia/Qyzylorda",
+ "Asia/Sakhalin",
+ "Asia/Tomsk",
+ "Atlantic/Reykjavik",
+ "Atlantic/St_Helena",
+ "Atlantic/Stanley",
+ "Australia/Eucla",
+ "Australia/LHI",
+ "Australia/Lord_Howe",
+ "Brazil/DeNoronha",
+ "Canada/Yukon",
+ "Chile/EasterIsland",
+ "Cuba",
+ "Etc/GMT-1",
+ "Etc/GMT-12",
+ "Etc/GMT-13",
+ "Etc/GMT-14",
+ "Etc/GMT-6",
+ "Etc/GMT+11",
+ "Etc/GMT+2",
+ "Etc/GMT+3",
+ "Etc/GMT+8",
+ "Etc/GMT+9",
+ "Europe/Astrakhan",
+ "Europe/Chisinau",
+ "Europe/Saratov",
+ "Europe/Tiraspol",
+ "Europe/Ulyanovsk",
+ "Iceland",
+ "Indian/Chagos",
+ "Indian/Mauritius",
+ "Libya",
+ "Pacific/Bougainville",
+ "Pacific/Easter",
+ "Pacific/Enderbury",
+ "Pacific/Funafuti",
+ "Pacific/Gambier",
+ "Pacific/Kanton",
+ "Pacific/Kiritimati",
+ "Pacific/Marquesas",
+ "Pacific/Nauru",
+ "Pacific/Niue",
+ "Pacific/Norfolk",
+ "Pacific/Pitcairn",
+ "US/Aleutian"
+ ];
- public IanaToRailsTests(ITestOutputHelper output)
- {
- _output = output;
- }
+ [Fact]
+ public void Can_Convert_Iana_Zones_To_Rails_Zones()
+ {
+ var errors = new List();
+ var ianaZones = TZConvert.KnownIanaTimeZoneNames.Order();
- [Fact]
- public void Can_Convert_Iana_Zones_To_Rails_Zones()
+ foreach (var ianaZone in ianaZones.Except(UnmappableZones))
{
- var errors = new List();
- IOrderedEnumerable ianaZones = TZConvert.KnownIanaTimeZoneNames.OrderBy(x => x);
-
- foreach (string ianaZone in ianaZones.Except(UnmappableZones))
+ if (TZConvert.TryIanaToRails(ianaZone, out var railsZones))
{
- if (TZConvert.TryIanaToRails(ianaZone, out IList railsZones))
- {
- Assert.NotNull(railsZones);
- Assert.NotEmpty(railsZones);
- }
- else
- {
- errors.Add(ianaZone);
- }
+ Assert.NotNull(railsZones);
+ Assert.NotEmpty(railsZones);
}
-
- int errorsCount = errors.Count;
- if (errorsCount > 0)
+ else
{
- _output.WriteLine("Failed to convert:\n");
- _output.WriteLine(string.Join(",\n", errors.Select(x => $"\"{x}\"")));
+ errors.Add(ianaZone);
}
-
- Assert.Equal(0, errorsCount);
}
- private static IEnumerable UnmappableZones => new[]
+ var errorsCount = errors.Count;
+ if (errorsCount > 0)
{
- "Africa/Abidjan",
- "Africa/Accra",
- "Africa/Bamako",
- "Africa/Bangui",
- "Africa/Banjul",
- "Africa/Bissau",
- "Africa/Brazzaville",
- "Africa/Conakry",
- "Africa/Dakar",
- "Africa/Douala",
- "Africa/Freetown",
- "Africa/Juba",
- "Africa/Khartoum",
- "Africa/Kinshasa",
- "Africa/Lagos",
- "Africa/Libreville",
- "Africa/Lome",
- "Africa/Luanda",
- "Africa/Malabo",
- "Africa/Ndjamena",
- "Africa/Niamey",
- "Africa/Nouakchott",
- "Africa/Ouagadougou",
- "Africa/Porto-Novo",
- "Africa/Sao_Tome",
- "Africa/Timbuktu",
- "Africa/Tripoli",
- "Africa/Tunis",
- "Africa/Windhoek",
- "America/Adak",
- "America/Araguaina",
- "America/Asuncion",
- "America/Atka",
- "America/Bahia",
- "America/Belem",
- "America/Campo_Grande",
- "America/Cancun",
- "America/Cayenne",
- "America/Cuiaba",
- "America/Danmarkshavn",
- "America/Fortaleza",
- "America/Grand_Turk",
- "America/Havana",
- "America/Maceio",
- "America/Miquelon",
- "America/Noronha",
- "America/Paramaribo",
- "America/Port-au-Prince",
- "America/Punta_Arenas",
- "America/Recife",
- "America/Santarem",
- "Antarctica/Palmer",
- "Antarctica/Rothera",
- "Antarctica/Troll",
- "Asia/Amman",
- "Asia/Barnaul",
- "Asia/Beirut",
- "Asia/Chita",
- "Asia/Damascus",
- "Asia/Gaza",
- "Asia/Hebron",
- "Asia/Hovd",
- "Asia/Omsk",
- "Asia/Pyongyang",
- "Asia/Qyzylorda",
- "Asia/Sakhalin",
- "Asia/Tomsk",
- "Atlantic/Reykjavik",
- "Atlantic/St_Helena",
- "Atlantic/Stanley",
- "Australia/Eucla",
- "Australia/LHI",
- "Australia/Lord_Howe",
- "Brazil/DeNoronha",
- "Chile/EasterIsland",
- "Cuba",
- "Etc/GMT+11",
- "Etc/GMT+2",
- "Etc/GMT+3",
- "Etc/GMT+8",
- "Etc/GMT+9",
- "Etc/GMT-1",
- "Etc/GMT-12",
- "Etc/GMT-13",
- "Etc/GMT-14",
- "Europe/Astrakhan",
- "Europe/Chisinau",
- "Europe/Saratov",
- "Europe/Tiraspol",
- "Europe/Ulyanovsk",
- "Iceland",
- "Indian/Mahe",
- "Indian/Mauritius",
- "Indian/Reunion",
- "Libya",
- "Pacific/Bougainville",
- "Pacific/Easter",
- "Pacific/Enderbury",
- "Pacific/Funafuti",
- "Pacific/Gambier",
- "Pacific/Kanton",
- "Pacific/Kiritimati",
- "Pacific/Marquesas",
- "Pacific/Nauru",
- "Pacific/Niue",
- "Pacific/Norfolk",
- "Pacific/Pitcairn",
- "Pacific/Tarawa",
- "Pacific/Wake",
- "Pacific/Wallis",
- "US/Aleutian"
- };
+ output.WriteLine("Failed to convert:\n");
+ output.WriteLine(string.Join(",\n", errors.Select(x => $"\"{x}\"")));
+ }
+
+ Assert.Equal(0, errorsCount);
}
}
diff --git a/test/TimeZoneConverter.Tests/IanaToWindowsTests.cs b/test/TimeZoneConverter.Tests/IanaToWindowsTests.cs
index 18e20cb..5a6fce1 100644
--- a/test/TimeZoneConverter.Tests/IanaToWindowsTests.cs
+++ b/test/TimeZoneConverter.Tests/IanaToWindowsTests.cs
@@ -1,141 +1,227 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Runtime.InteropServices;
-using Xunit;
using Xunit.Abstractions;
-namespace TimeZoneConverter.Tests
+namespace TimeZoneConverter.Tests;
+
+public class IanaToWindowsTests(ITestOutputHelper output)
{
- public class IanaToWindowsTests
+ [SkippableFact]
+ public void Can_Convert_IANA_System_Zones_To_Windows()
{
- private readonly ITestOutputHelper _output;
+ Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "OS is Windows.");
+
+ var errors = 0;
+ var ianaZones = TimeZoneInfo.GetSystemTimeZones().Select(x => x.Id);
- public IanaToWindowsTests(ITestOutputHelper output)
+ string[] unmappable = ["Antarctica/Troll"];
+
+ foreach (var ianaZone in ianaZones.Except(unmappable))
{
- _output = output;
+ if (TZConvert.TryIanaToWindows(ianaZone, out var windowsZone))
+ {
+ Assert.NotNull(windowsZone);
+ Assert.NotEqual(string.Empty, windowsZone);
+ }
+ else
+ {
+ errors++;
+ output.WriteLine($"Failed to convert \"{ianaZone}\"");
+ }
}
- [SkippableFact]
- public void Can_Convert_IANA_System_Zones_To_Windows()
- {
- Skip.If(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "OS is Windows.");
+ Assert.Equal(0, errors);
+ }
- var errors = 0;
- IEnumerable ianaZones = TimeZoneInfo.GetSystemTimeZones().Select(x => x.Id);
+ [Fact]
+ public void Can_Convert_Iana_Zones_To_Windows_Zones()
+ {
+ var errors = 0;
+ ICollection ianaZones = [.. TZConvert.KnownIanaTimeZoneNames];
- string[] unmappable = { "Antarctica/Troll" };
+ string[] unmappable = ["Antarctica/Troll"];
- foreach (string ianaZone in ianaZones.Except(unmappable))
+ foreach (var ianaZone in ianaZones.Except(unmappable))
+ {
+ if (TZConvert.TryIanaToWindows(ianaZone, out var windowsZone))
{
- if (TZConvert.TryIanaToWindows(ianaZone, out string windowsZone))
- {
- Assert.NotNull(windowsZone);
- Assert.NotEqual(string.Empty, windowsZone);
- }
- else
- {
- errors++;
- _output.WriteLine($"Failed to convert \"{ianaZone}\"");
- }
+ Assert.NotNull(windowsZone);
+ Assert.NotEqual(string.Empty, windowsZone);
+ }
+ else
+ {
+ errors++;
+ output.WriteLine($"Failed to convert \"{ianaZone}\"");
}
-
- Assert.Equal(0, errors);
}
- [Fact]
- public void Can_Convert_Iana_Zones_To_Windows_Zones()
- {
- var errors = 0;
- ICollection ianaZones = TZConvert.KnownIanaTimeZoneNames;
+ Assert.Equal(0, errors);
+ }
- string[] unmappable = { "Antarctica/Troll" };
+ [Fact]
+ public void Can_Convert_Asia_Qostanay_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Asia/Qostanay");
+ Assert.Equal("West Asia Standard Time", result);
+ }
- foreach (string ianaZone in ianaZones.Except(unmappable))
- {
- if (TZConvert.TryIanaToWindows(ianaZone, out string windowsZone))
- {
- Assert.NotNull(windowsZone);
- Assert.NotEqual(string.Empty, windowsZone);
- }
- else
- {
- errors++;
- _output.WriteLine($"Failed to convert \"{ianaZone}\"");
- }
- }
+ [Fact]
+ public void Can_Convert_Asia_Qyzylorda_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Asia/Qyzylorda");
+ Assert.Equal("Qyzylorda Standard Time", result);
+ }
- Assert.Equal(0, errors);
- }
+ [Fact]
+ public void Can_Convert_Asia_Kamchatka_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Asia/Kamchatka");
+ Assert.Equal("Russia Time Zone 11", result);
+ }
- [Fact]
- public void Can_Convert_Asia_Qostanay_To_Windows()
- {
- string result = TZConvert.IanaToWindows("Asia/Qostanay");
- Assert.Equal("Central Asia Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_America_Nuuk_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Nuuk");
+ Assert.Equal("Greenland Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_Asia_Qyzylorda_To_Windows()
- {
- string result = TZConvert.IanaToWindows("Asia/Qyzylorda");
- Assert.Equal("Qyzylorda Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_Europe_Skopje_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Europe/Skopje");
+ Assert.Equal("Central European Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_Asia_Kamchatka_To_Windows()
- {
- string result = TZConvert.IanaToWindows("Asia/Kamchatka");
- Assert.Equal("Russia Time Zone 11", result);
- }
+ [Fact]
+ public void Can_Convert_East_Saskatchewan_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Canada/East-Saskatchewan");
+ Assert.Equal("Canada Central Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_America_Nuuk_To_Windows()
- {
- string result = TZConvert.IanaToWindows("America/Nuuk");
- Assert.Equal("Greenland Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_Pacific_New_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("US/Pacific-New");
+ Assert.Equal("Pacific Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_Europe_Skopje_To_Windows()
- {
- string result = TZConvert.IanaToWindows("Europe/Skopje");
- Assert.Equal("Central European Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_Whitehorse_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Whitehorse");
+ Assert.Equal("Yukon Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_East_Saskatchewan_To_Windows()
- {
- string result = TZConvert.IanaToWindows("Canada/East-Saskatchewan");
- Assert.Equal("Canada Central Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_Creston_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Creston");
+ Assert.Equal("US Mountain Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_Pacific_New_To_Windows()
- {
- string result = TZConvert.IanaToWindows("US/Pacific-New");
- Assert.Equal("Pacific Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_Kanton_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Pacific/Kanton");
+ Assert.Equal("UTC+13", result);
+ }
- [Fact]
- public void Can_Convert_Whitehorse_To_Windows()
- {
- string result = TZConvert.IanaToWindows("America/Whitehorse");
- Assert.Equal("Yukon Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_Indianapolis_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Indianapolis");
+ Assert.Equal("US Eastern Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_Creston_To_Windows()
- {
- string result = TZConvert.IanaToWindows("America/Creston");
- Assert.Equal("US Mountain Standard Time", result);
- }
+ [Fact]
+ public void Can_Convert_Indiana_Indianapolis_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Indiana/Indianapolis");
+ Assert.Equal("US Eastern Standard Time", result);
+ }
- [Fact]
- public void Can_Convert_Kanton_To_Windows()
- {
- string result = TZConvert.IanaToWindows("Pacific/Kanton");
- Assert.Equal("UTC+13", result);
- }
+ [Fact]
+ public void Can_Convert_Fort_Wayne_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Fort_Wayne");
+ Assert.Equal("US Eastern Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_East_Indiana_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("US/East-Indiana");
+ Assert.Equal("US Eastern Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Marengo_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Indiana/Marengo");
+ Assert.Equal("US Eastern Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Vevay_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Indiana/Vevay");
+ Assert.Equal("US Eastern Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Calcutta_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Asia/Calcutta");
+ Assert.Equal("India Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Kolkata_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Asia/Kolkata");
+ Assert.Equal("India Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Kyiv_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Europe/Kyiv");
+ Assert.Equal("FLE Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Kiev_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("Europe/Kiev");
+ Assert.Equal("FLE Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Ciudad_Juarez_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Ciudad_Juarez");
+ Assert.Equal("Mountain Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Ojinaga_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Ojinaga");
+ Assert.Equal("Central Standard Time", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Chihuahua_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Chihuahua");
+ Assert.Equal("Central Standard Time (Mexico)", result);
+ }
+
+ [Fact]
+ public void Can_Convert_Mazatlan_To_Windows()
+ {
+ var result = TZConvert.IanaToWindows("America/Mazatlan");
+ Assert.Equal("Mountain Standard Time (Mexico)", result);
}
}
diff --git a/test/TimeZoneConverter.Tests/KnownTimeZonesTests.cs b/test/TimeZoneConverter.Tests/KnownTimeZonesTests.cs
index 01f7aaf..bf688d8 100644
--- a/test/TimeZoneConverter.Tests/KnownTimeZonesTests.cs
+++ b/test/TimeZoneConverter.Tests/KnownTimeZonesTests.cs
@@ -1,55 +1,52 @@
-using Xunit;
+namespace TimeZoneConverter.Tests;
-namespace TimeZoneConverter.Tests
+public class KnownTimeZonesTests
{
- public class KnownTimeZonesTests
- {
- [Fact]
- public void Can_Get_Known_IANA_TimeZones()
- {
- Assert.NotEmpty(TZConvert.KnownIanaTimeZoneNames);
- }
-
- [Fact]
- public void Can_Get_Known_Windows_TimeZones()
- {
- Assert.NotEmpty(TZConvert.KnownWindowsTimeZoneIds);
- }
-
- [Fact]
- public void Can_Get_Known_Rails_TimeZones()
- {
- Assert.NotEmpty(TZConvert.KnownRailsTimeZoneNames);
- }
-
- [Fact]
- public void Known_IANA_TimeZones_Includes_Unmappable_Zones()
- {
- Assert.Contains(TZConvert.KnownIanaTimeZoneNames, x => x == "Antarctica/Troll");
- }
-
- [Fact]
- public void Known_IANA_TimeZones_Excludes_East_Saskatchewan()
- {
- Assert.DoesNotContain(TZConvert.KnownIanaTimeZoneNames, x => x == "Canada/East-Saskatchewan");
- }
-
- [Fact]
- public void Known_IANA_TimeZones_Excludes_Pacific_New()
- {
- Assert.DoesNotContain(TZConvert.KnownIanaTimeZoneNames, x => x == "US/Pacific-New");
- }
-
- [Fact]
- public void Known_Windows_TimeZones_Excludes_Kamchatka()
- {
- Assert.DoesNotContain(TZConvert.KnownWindowsTimeZoneIds, x => x == "Kamchatka Standard Time");
- }
-
- [Fact]
- public void Known_Windows_TimeZones_Excludes_Mid_Atlantic()
- {
- Assert.DoesNotContain(TZConvert.KnownWindowsTimeZoneIds, x => x == "Mid-Atlantic Standard Time");
- }
+ [Fact]
+ public void Can_Get_Known_IANA_TimeZones()
+ {
+ Assert.NotEmpty(TZConvert.KnownIanaTimeZoneNames);
+ }
+
+ [Fact]
+ public void Can_Get_Known_Windows_TimeZones()
+ {
+ Assert.NotEmpty(TZConvert.KnownWindowsTimeZoneIds);
+ }
+
+ [Fact]
+ public void Can_Get_Known_Rails_TimeZones()
+ {
+ Assert.NotEmpty(TZConvert.KnownRailsTimeZoneNames);
+ }
+
+ [Fact]
+ public void Known_IANA_TimeZones_Includes_Unmappable_Zones()
+ {
+ Assert.Contains(TZConvert.KnownIanaTimeZoneNames, x => x == "Antarctica/Troll");
+ }
+
+ [Fact]
+ public void Known_IANA_TimeZones_Excludes_East_Saskatchewan()
+ {
+ Assert.DoesNotContain(TZConvert.KnownIanaTimeZoneNames, x => x == "Canada/East-Saskatchewan");
+ }
+
+ [Fact]
+ public void Known_IANA_TimeZones_Excludes_Pacific_New()
+ {
+ Assert.DoesNotContain(TZConvert.KnownIanaTimeZoneNames, x => x == "US/Pacific-New");
+ }
+
+ [Fact]
+ public void Known_Windows_TimeZones_Excludes_Kamchatka()
+ {
+ Assert.DoesNotContain(TZConvert.KnownWindowsTimeZoneIds, x => x == "Kamchatka Standard Time");
+ }
+
+ [Fact]
+ public void Known_Windows_TimeZones_Excludes_Mid_Atlantic()
+ {
+ Assert.DoesNotContain(TZConvert.KnownWindowsTimeZoneIds, x => x == "Mid-Atlantic Standard Time");
}
}
diff --git a/test/TimeZoneConverter.Tests/MiscTests.cs b/test/TimeZoneConverter.Tests/MiscTests.cs
new file mode 100644
index 0000000..6ee5591
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/MiscTests.cs
@@ -0,0 +1,73 @@
+using Xunit.Abstractions;
+
+namespace TimeZoneConverter.Tests;
+
+public class MiscTests()
+{
+#pragma warning disable CS8625
+
+ [Fact]
+ public void No_Exception_From_TryGetTimeZoneInfo()
+ {
+ Assert.False(TZConvert.TryGetTimeZoneInfo(null, out var _));
+ Assert.False(TZConvert.TryGetTimeZoneInfo("", out var _));
+ Assert.False(TZConvert.TryGetTimeZoneInfo(" ", out var _));
+ Assert.False(TZConvert.TryGetTimeZoneInfo("blah", out var _));
+ }
+
+ [Fact]
+ public void No_Exception_From_TryIanaToRails()
+ {
+ Assert.False(TZConvert.TryIanaToRails(null, out var _));
+ Assert.False(TZConvert.TryIanaToRails("", out var _));
+ Assert.False(TZConvert.TryIanaToRails(" ", out var _));
+ Assert.False(TZConvert.TryIanaToRails("blah", out var _));
+ }
+
+ [Fact]
+ public void No_Exception_From_TryIanaToWindows()
+ {
+ Assert.False(TZConvert.TryIanaToWindows(null, out var _));
+ Assert.False(TZConvert.TryIanaToWindows("", out var _));
+ Assert.False(TZConvert.TryIanaToWindows(" ", out var _));
+ Assert.False(TZConvert.TryIanaToWindows("blah", out var _));
+ }
+
+ [Fact]
+ public void No_Exception_From_TryRailsToIana()
+ {
+ Assert.False(TZConvert.TryRailsToIana(null, out var _));
+ Assert.False(TZConvert.TryRailsToIana("", out var _));
+ Assert.False(TZConvert.TryRailsToIana(" ", out var _));
+ Assert.False(TZConvert.TryRailsToIana("blah", out var _));
+ }
+
+ [Fact]
+ public void No_Exception_From_TryRailsToWindows()
+ {
+ Assert.False(TZConvert.TryRailsToWindows(null, out var _));
+ Assert.False(TZConvert.TryRailsToWindows("", out var _));
+ Assert.False(TZConvert.TryRailsToWindows(" ", out var _));
+ Assert.False(TZConvert.TryRailsToWindows("blah", out var _));
+ }
+
+ [Fact]
+ public void No_Exception_From_TryWindowsToIana()
+ {
+ Assert.False(TZConvert.TryWindowsToIana(null, out var _));
+ Assert.False(TZConvert.TryWindowsToIana("", out var _));
+ Assert.False(TZConvert.TryWindowsToIana(" ", out var _));
+ Assert.False(TZConvert.TryWindowsToIana("blah", out var _));
+ }
+
+ [Fact]
+ public void No_Exception_From_TryWindowsToRails()
+ {
+ Assert.False(TZConvert.TryWindowsToRails(null, out var _));
+ Assert.False(TZConvert.TryWindowsToRails("", out var _));
+ Assert.False(TZConvert.TryWindowsToRails(" ", out var _));
+ Assert.False(TZConvert.TryWindowsToRails("blah", out var _));
+ }
+
+#pragma warning restore CS8625
+}
diff --git a/test/TimeZoneConverter.Tests/ModuleInit.cs b/test/TimeZoneConverter.Tests/ModuleInit.cs
new file mode 100644
index 0000000..c7e0d12
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/ModuleInit.cs
@@ -0,0 +1,23 @@
+using System.Runtime.CompilerServices;
+
+namespace TimeZoneConverter.Tests
+{
+ public static class ModuleInit
+ {
+ [ModuleInitializer]
+ public static void Init()
+ {
+ VerifierSettings.AutoVerify(includeBuildServer: false);
+ }
+ }
+}
+
+#if NETFRAMEWORK
+namespace System.Runtime.CompilerServices
+{
+ [AttributeUsage(AttributeTargets.Method, Inherited = false)]
+ public sealed class ModuleInitializerAttribute : Attribute
+ {
+ }
+}
+#endif
diff --git a/test/TimeZoneConverter.Tests/RailsToIanaTests.cs b/test/TimeZoneConverter.Tests/RailsToIanaTests.cs
index 68b8572..5d088d0 100644
--- a/test/TimeZoneConverter.Tests/RailsToIanaTests.cs
+++ b/test/TimeZoneConverter.Tests/RailsToIanaTests.cs
@@ -1,39 +1,27 @@
-using System.Collections.Generic;
-using Xunit;
using Xunit.Abstractions;
-namespace TimeZoneConverter.Tests
+namespace TimeZoneConverter.Tests;
+
+public class RailsToIanaTests(ITestOutputHelper output)
{
- public class RailsToIanaTests
+ [Fact]
+ public void Can_Convert_Rails_Zones_To_Iana_Zones()
{
- private readonly ITestOutputHelper _output;
-
- public RailsToIanaTests(ITestOutputHelper output)
- {
- _output = output;
- }
-
- [Fact]
- public void Can_Convert_Rails_Zones_To_Iana_Zones()
+ var errors = 0;
+ foreach (var railsZone in (ICollection)[.. TZConvert.KnownRailsTimeZoneNames])
{
- var errors = 0;
- ICollection railsZones = TZConvert.KnownRailsTimeZoneNames;
-
- foreach (string railsZone in railsZones)
+ if (TZConvert.TryRailsToIana(railsZone, out var ianaZone))
{
- if (TZConvert.TryRailsToIana(railsZone, out string ianaZone))
- {
- Assert.NotNull(ianaZone);
- Assert.NotEqual(string.Empty, ianaZone);
- }
- else
- {
- errors++;
- _output.WriteLine($"Failed to convert \"{railsZone}\"");
- }
+ Assert.NotNull(ianaZone);
+ Assert.NotEqual(string.Empty, ianaZone);
+ }
+ else
+ {
+ errors++;
+ output.WriteLine($"Failed to convert \"{railsZone}\"");
}
-
- Assert.Equal(0, errors);
}
+
+ Assert.Equal(0, errors);
}
}
diff --git a/test/TimeZoneConverter.Tests/TestData.cs b/test/TimeZoneConverter.Tests/TestData.cs
new file mode 100644
index 0000000..d997b17
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/TestData.cs
@@ -0,0 +1,22 @@
+namespace TimeZoneConverter.Tests;
+
+internal static class TestData
+{
+ public static readonly string[] Regions =
+ [
+ "001", "AD", "AE", "AF", "AG", "AI", "AL", "AM", "AO", "AR", "AS", "AT", "AU", "AW", "AX", "AZ", "BA", "BB",
+ "BD", "BE", "BF", "BG", "BH", "BI", "BJ", "BL", "BM", "BN", "BO", "BQ", "BR", "BS", "BT", "BW", "BY", "BZ",
+ "CA", "CC", "CD", "CF", "CG", "CH", "CI", "CK", "CL", "CM", "CN", "CO", "CR", "CU", "CV", "CW", "CX", "CY",
+ "CZ", "DE", "DG", "DJ", "DK", "DM", "DO", "DZ", "EA", "EC", "EE", "EG", "EH", "ER", "ES", "ET", "FI", "FJ",
+ "FK", "FM", "FO", "FR", "GA", "GB", "GD", "GE", "GF", "GG", "GH", "GI", "GL", "GM", "GN", "GP", "GQ", "GR",
+ "GT", "GU", "GW", "GY", "HK", "HN", "HR", "HT", "HU", "IC", "ID", "IE", "IL", "IM", "IN", "IO", "IQ", "IR",
+ "IS", "IT", "JE", "JM", "JO", "JP", "KE", "KG", "KH", "KI", "KM", "KN", "KP", "KR", "KW", "KY", "KZ", "LA",
+ "LB", "LC", "LI", "LK", "LR", "LS", "LT", "LU", "LV", "LY", "MA", "MC", "MD", "ME", "MF", "MG", "MH", "MK",
+ "ML", "MM", "MN", "MO", "MP", "MQ", "MR", "MS", "MT", "MU", "MV", "MW", "MX", "MY", "MZ", "NA", "NC", "NE",
+ "NF", "NG", "NI", "NL", "NO", "NP", "NR", "NU", "NZ", "OM", "PA", "PE", "PF", "PG", "PH", "PK", "PL", "PM",
+ "PN", "PR", "PS", "PT", "PW", "PY", "QA", "RE", "RO", "RS", "RU", "RW", "SA", "SB", "SC", "SD", "SE", "SG",
+ "SH", "SI", "SJ", "SK", "SL", "SM", "SN", "SO", "SR", "SS", "ST", "SV", "SX", "SY", "SZ", "TC", "TD", "TG",
+ "TH", "TJ", "TK", "TL", "TM", "TN", "TO", "TR", "TT", "TV", "TW", "TZ", "UA", "UG", "UM", "US", "UY", "UZ",
+ "VA", "VC", "VE", "VG", "VI", "VN", "VU", "WF", "WS", "XK", "YE", "YT", "ZA", "ZM", "ZW"
+ ];
+}
diff --git a/test/TimeZoneConverter.Tests/TestHelpers.cs b/test/TimeZoneConverter.Tests/TestHelpers.cs
new file mode 100644
index 0000000..4cc5ba2
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/TestHelpers.cs
@@ -0,0 +1,13 @@
+namespace TimeZoneConverter.Tests;
+
+public static class TestHelpers
+{
+ public static SortedDictionary Sorted(
+ this IDictionary dictionary) =>
+ new(dictionary, StringComparer.Ordinal);
+
+ public static SortedDictionary Sorted(
+ this IDictionary dictionary,
+ IComparer comparer) where TKey : notnull =>
+ new(dictionary, comparer);
+}
diff --git a/test/TimeZoneConverter.Tests/TimeZoneConverter.Tests.csproj b/test/TimeZoneConverter.Tests/TimeZoneConverter.Tests.csproj
index 781e905..9049ffb 100644
--- a/test/TimeZoneConverter.Tests/TimeZoneConverter.Tests.csproj
+++ b/test/TimeZoneConverter.Tests/TimeZoneConverter.Tests.csproj
@@ -1,21 +1,12 @@
-
+
- net6.0
+ net8.0;net9.0
+ $(TargetFrameworks);net48
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
diff --git a/test/TimeZoneConverter.Tests/TimeZoneInfoPerfTests.cs b/test/TimeZoneConverter.Tests/TimeZoneInfoPerfTests.cs
index 07cd275..b5a2f92 100644
--- a/test/TimeZoneConverter.Tests/TimeZoneInfoPerfTests.cs
+++ b/test/TimeZoneConverter.Tests/TimeZoneInfoPerfTests.cs
@@ -1,33 +1,56 @@
-using System;
using System.Diagnostics;
-using Xunit;
-namespace TimeZoneConverter.Tests
+#if NETFRAMEWORK
+using System.Runtime.InteropServices;
+#endif
+
+namespace TimeZoneConverter.Tests;
+
+public class TimeZoneInfoPerfTests : IClassFixture
{
- public class TimeZoneInfoPerfTests
+ public TimeZoneInfoPerfTests(Fixture _)
{
- [Fact]
- public void GetTimeZoneInfo_WithIANAZone_1Million_ReturnsInUnder1Second()
- {
- var sw = Stopwatch.StartNew();
+ }
- for (var i = 0; i < 1000000; i++)
- TZConvert.GetTimeZoneInfo("Europe/Warsaw");
+ [Fact]
+ public void GetTimeZoneInfo_WithIANAZone_1Million_ReturnsInUnder5Seconds()
+ {
+ var sw = Stopwatch.StartNew();
- sw.Stop();
- Assert.True(sw.Elapsed < TimeSpan.FromSeconds(1));
+ for (var i = 0; i < 1000000; i++)
+ {
+ TZConvert.GetTimeZoneInfo("Europe/Warsaw");
}
- [Fact]
- public void GetTimeZoneInfo_WithWindowsZone_1Million_ReturnsInUnder1Second()
+ sw.Stop();
+ Assert.True(sw.Elapsed < TimeSpan.FromSeconds(5), $"Actual Time: {sw.Elapsed}");
+ }
+
+ [SkippableFact]
+ public void GetTimeZoneInfo_WithWindowsZone_1Million_ReturnsInUnder5Seconds()
+ {
+#if NETFRAMEWORK
+ // This test is much slower on Mono. Skip for now.
+ Skip.If(RuntimeInformation.FrameworkDescription.Contains("Mono"));
+#endif
+ var sw = Stopwatch.StartNew();
+
+ for (var i = 0; i < 1000000; i++)
{
- var sw = Stopwatch.StartNew();
+ TZConvert.GetTimeZoneInfo("Pacific Standard Time");
+ }
- for (var i = 0; i < 1000000; i++)
- TZConvert.GetTimeZoneInfo("Pacific Standard Time");
+ sw.Stop();
+ Assert.True(sw.Elapsed < TimeSpan.FromSeconds(5), $"Actual Time: {sw.Elapsed}");
+ }
- sw.Stop();
- Assert.True(sw.Elapsed < TimeSpan.FromSeconds(1));
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class Fixture
+ {
+ public Fixture()
+ {
+ // This is just to ensure that we've initialized before starting our tests
+ _ = TZConvert.KnownIanaTimeZoneNames;
}
}
}
diff --git a/test/TimeZoneConverter.Tests/TimeZoneInfoTests.cs b/test/TimeZoneConverter.Tests/TimeZoneInfoTests.cs
index 274f6c1..04bc76f 100644
--- a/test/TimeZoneConverter.Tests/TimeZoneInfoTests.cs
+++ b/test/TimeZoneConverter.Tests/TimeZoneInfoTests.cs
@@ -1,25 +1,157 @@
-using System;
-using Xunit;
+using System.Globalization;
+using System.Runtime.InteropServices;
-namespace TimeZoneConverter.Tests
+namespace TimeZoneConverter.Tests;
+
+public class TimeZoneInfoTests
{
- public class TimeZoneInfoTests
+ [Fact]
+ public void CanGetUtcTimeZone()
+ {
+ var tz = TZConvert.GetTimeZoneInfo("UTC");
+
+ Assert.Equal(TimeZoneInfo.Utc, tz);
+ }
+
+ [Fact]
+ public void CanGetEasternTimeZone_LowerCase()
+ {
+ var tz1 = TZConvert.GetTimeZoneInfo("eastern standard time");
+ var tz2 = TZConvert.GetTimeZoneInfo("Eastern Standard Time");
+
+ Assert.Equal(tz2.Id, tz1.Id);
+ }
+
+ [Fact]
+ public void CanGetAllKnownWindowsTimeZones()
{
- [Fact]
- public void CanGetUtcTimeZone()
+ foreach (var id in TZConvert.KnownWindowsTimeZoneIds)
{
- TimeZoneInfo tz = TZConvert.GetTimeZoneInfo("UTC");
+ var result = TZConvert.TryGetTimeZoneInfo(id, out _);
+ Assert.True(result, $"Windows time zone \"{id}\" or an equivalent was not found.");
+ }
+ }
- Assert.Equal(TimeZoneInfo.Utc, tz);
+ [Fact]
+ public void CanGetAllKnownIANATimeZones()
+ {
+ var names = TZConvert.KnownIanaTimeZoneNames.ToList();
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // Don't attempt unmappable zones
+ names.Remove("Antarctica/Troll");
}
- [Fact]
- public void CanGetEasternTimeZone_LowerCase()
+ foreach (var name in names)
{
- TimeZoneInfo tz1 = TZConvert.GetTimeZoneInfo("eastern standard time");
- TimeZoneInfo tz2 = TZConvert.GetTimeZoneInfo("Eastern Standard Time");
+ var result = TZConvert.TryGetTimeZoneInfo(name, out _);
+ Assert.True(result, $"IANA time zone \"{name}\" or an equivalent was not found.");
+ }
+ }
+
+ [Fact]
+ public void CanGetAntarcticaTroll()
+ {
+ var tz = TZConvert.GetTimeZoneInfo("Antarctica/Troll");
+ Assert.NotNull(tz);
+ Assert.Equal(TimeSpan.Zero, tz.BaseUtcOffset);
- Assert.Equal(tz2.Id, tz1.Id);
+ if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
+ {
+ // This is the custom info we set
+ Assert.Equal("(UTC+00:00) Troll Station, Antarctica", tz.DisplayName);
+ Assert.Equal("Greenwich Mean Time", tz.StandardName);
+ Assert.Equal("Central European Summer Time", tz.DaylightName);
}
+
+ var dto1 = DateTimeOffset.Parse("2020-01-01T00:00:00Z", CultureInfo.InvariantCulture);
+ var dto2 = DateTimeOffset.Parse("2020-07-01T00:00:00Z", CultureInfo.InvariantCulture);
+
+ var converted1 = TimeZoneInfo.ConvertTime(dto1, tz);
+ var converted2 = TimeZoneInfo.ConvertTime(dto2, tz);
+
+ var expected1 = DateTimeOffset.Parse("2020-01-01T00:00:00+00:00", CultureInfo.InvariantCulture);
+ var expected2 = DateTimeOffset.Parse("2020-07-01T02:00:00+02:00", CultureInfo.InvariantCulture);
+
+ Assert.Equal(expected1.DateTime, converted1.DateTime);
+ Assert.Equal(expected1.Offset, converted1.Offset);
+ Assert.Equal(expected2.DateTime, converted2.DateTime);
+ Assert.Equal(expected2.Offset, converted2.Offset);
+ }
+
+ [Fact]
+ public void CanGetIndiaStandardTime()
+ {
+ var tz = TZConvert.GetTimeZoneInfo("India Standard Time");
+ Assert.NotNull(tz);
+ }
+
+ [Fact]
+ public void CanGetArgentinaStandardTime()
+ {
+ var tz = TZConvert.GetTimeZoneInfo("Argentina Standard Time");
+ Assert.NotNull(tz);
+ }
+
+ [Fact]
+ public void CanGetIanaCanonicalNameForAlias()
+ {
+ var result = TZConvert.TryGetIanaCanonicalName("Europe/Jersey", out var canonicalIanaName);
+
+ Assert.True(result, $"{nameof(TZConvert.TryGetIanaCanonicalName)} should succeed for alias.");
+ Assert.Equal("Europe/London", canonicalIanaName);
+ }
+
+ [Fact]
+ public void CanGetIanaCanonicalNameForCanonicalName()
+ {
+ var result = TZConvert.TryGetIanaCanonicalName("Africa/Maputo", out var canonicalIanaName);
+
+ Assert.True(result, $"{nameof(TZConvert.TryGetIanaCanonicalName)} should succeed for canonical time zone name.");
+ Assert.Equal("Africa/Maputo", canonicalIanaName);
+ }
+
+ [Theory]
+ [InlineData(null)]
+ [InlineData("")]
+ [InlineData(" ")]
+ [InlineData("NOT-A-TIME-ZONE")]
+ public void CannotGetIanaCanonicalNameForUnknownOrInvalidName(string? name)
+ {
+ var result = TZConvert.TryGetIanaCanonicalName(name, out _);
+
+ Assert.False(result, $"{nameof(TZConvert.TryGetIanaCanonicalName)} should fail for invalid or unknown time zone name.");
+ }
+
+ [Fact]
+ public void CanGetIanaCanonicalNameForAllKnownIanaTimeZones()
+ {
+ var names = TZConvert.KnownIanaTimeZoneNames.ToList();
+
+ foreach (var name in names)
+ {
+ var result = TZConvert.TryGetIanaCanonicalName(name, out _);
+
+ Assert.True(result, $"{nameof(TZConvert.TryGetIanaCanonicalName)} should succeed for \"{name}\".");
+ }
+ }
+
+ [Theory]
+ [InlineData("Australia/Brisbane")]
+ [InlineData("Antarctica/Troll")]
+ [InlineData("America/Adak")]
+ public void CanFindCanonicalTimeZoneInCanonicalNames(string name)
+ {
+ var result = TZConvert.KnownIanaCanonicalNames.Contains(name);
+
+ Assert.True(result, $"{nameof(TZConvert.KnownIanaCanonicalNames)} should contain \"{name}\".");
+ }
+
+ [Fact]
+ public void CannotFindAliasInCanonicalNames()
+ {
+ var result = TZConvert.KnownIanaCanonicalNames.Contains("Australia/Queensland");
+
+ Assert.False(result, $"{nameof(TZConvert.KnownIanaCanonicalNames)} should not contain \"Australia/Queensland\".");
}
}
diff --git a/test/TimeZoneConverter.Tests/TimeZoneTerritoriesTests.cs b/test/TimeZoneConverter.Tests/TimeZoneTerritoriesTests.cs
new file mode 100644
index 0000000..034662d
--- /dev/null
+++ b/test/TimeZoneConverter.Tests/TimeZoneTerritoriesTests.cs
@@ -0,0 +1,93 @@
+namespace TimeZoneConverter.Tests;
+
+public class TimeZoneTerritoriesTests
+{
+ [Fact]
+ public void Can_Get_Known_IANA_TimeZone_Territories()
+ {
+ var territories = TZConvert.GetIanaTimeZoneNamesByTerritory();
+ Assert.NotEmpty(territories);
+ }
+
+ [Fact]
+ public void Territories_Does_Not_Include_001()
+ {
+ var territories = TZConvert.GetIanaTimeZoneNamesByTerritory();
+ Assert.False(territories.ContainsKey("001"));
+ }
+
+ [Fact]
+ public void Can_Get_Known_IANA_TimeZones_in_USA()
+ {
+ var territories = TZConvert.GetIanaTimeZoneNamesByTerritory(true);
+ Assert.True(territories.TryGetValue("US", out var zoneIds));
+ Assert.NotEmpty(zoneIds);
+
+ // The main 8 zones:
+ Assert.Contains("America/New_York", zoneIds);
+ Assert.Contains("America/Chicago", zoneIds);
+ Assert.Contains("America/Denver", zoneIds);
+ Assert.Contains("America/Phoenix", zoneIds);
+ Assert.Contains("America/Los_Angeles", zoneIds);
+ Assert.Contains("America/Anchorage", zoneIds);
+ Assert.Contains("America/Adak", zoneIds);
+ Assert.Contains("Pacific/Honolulu", zoneIds);
+
+ // Other zones:
+ Assert.Contains("America/Boise", zoneIds);
+ Assert.Contains("America/Detroit", zoneIds);
+ Assert.Contains("America/Indiana/Indianapolis", zoneIds);
+ Assert.Contains("America/Indiana/Knox", zoneIds);
+ Assert.Contains("America/Indiana/Marengo", zoneIds);
+ Assert.Contains("America/Indiana/Petersburg", zoneIds);
+ Assert.Contains("America/Indiana/Tell_City", zoneIds);
+ Assert.Contains("America/Indiana/Vevay", zoneIds);
+ Assert.Contains("America/Indiana/Vincennes", zoneIds);
+ Assert.Contains("America/Indiana/Winamac", zoneIds);
+ Assert.Contains("America/Juneau", zoneIds);
+ Assert.Contains("America/Kentucky/Louisville", zoneIds);
+ Assert.Contains("America/Kentucky/Monticello", zoneIds);
+ Assert.Contains("America/Menominee", zoneIds);
+ Assert.Contains("America/Metlakatla", zoneIds);
+ Assert.Contains("America/Nome", zoneIds);
+ Assert.Contains("America/North_Dakota/Beulah", zoneIds);
+ Assert.Contains("America/North_Dakota/Center", zoneIds);
+ Assert.Contains("America/North_Dakota/New_Salem", zoneIds);
+ Assert.Contains("America/Sitka", zoneIds);
+ Assert.Contains("America/Yakutat", zoneIds);
+ }
+
+ [Fact]
+ public void USA_IANA_TimeZones_Does_Not_Contain_Other_Territories_Zones()
+ {
+ var territories = TZConvert.GetIanaTimeZoneNamesByTerritory();
+ Assert.True(territories.TryGetValue("US", out var zoneIds));
+ Assert.NotEmpty(zoneIds);
+ Assert.DoesNotContain("Europe/London", zoneIds);
+ }
+
+ [Fact]
+ public void USA_IANA_TimeZones_Do_Not_Appear_In_Other_Territories()
+ {
+ var territories = TZConvert.GetIanaTimeZoneNamesByTerritory();
+ Assert.True(territories.TryGetValue("US", out var usaZoneIds));
+ Assert.NotEmpty(usaZoneIds);
+
+ foreach (var territory in territories.Keys)
+ {
+ if (territory == "US")
+ continue;
+
+ Assert.True(territories.TryGetValue(territory, out var territoryZoneIds));
+ Assert.NotEmpty(usaZoneIds);
+
+ foreach (var usaZoneName in usaZoneIds)
+ {
+ if (usaZoneName == "Pacific/Honolulu")
+ continue;
+
+ Assert.DoesNotContain(usaZoneName, territoryZoneIds);
+ }
+ }
+ }
+}
diff --git a/test/TimeZoneConverter.Tests/WindowsToIanaTests.cs b/test/TimeZoneConverter.Tests/WindowsToIanaTests.cs
index a30a38a..de64ec2 100644
--- a/test/TimeZoneConverter.Tests/WindowsToIanaTests.cs
+++ b/test/TimeZoneConverter.Tests/WindowsToIanaTests.cs
@@ -1,125 +1,191 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
using System.Runtime.InteropServices;
-using Xunit;
using Xunit.Abstractions;
-namespace TimeZoneConverter.Tests
+namespace TimeZoneConverter.Tests;
+
+public class WindowsToIanaTests(ITestOutputHelper output)
{
- public class WindowsToIanaTests
+ [SkippableFact]
+ public void Can_Convert_Windows_System_Zones_To_Iana()
{
- private readonly ITestOutputHelper _output;
+ Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "OS is not Windows.");
- public WindowsToIanaTests(ITestOutputHelper output)
+ var errors = 0;
+ foreach (var windowsZone in TimeZoneInfo.GetSystemTimeZones().Select(x => x.Id))
{
- _output = output;
+ if (TZConvert.TryWindowsToIana(windowsZone, out var ianaZone))
+ {
+ Assert.NotNull(ianaZone);
+ Assert.NotEqual(string.Empty, ianaZone);
+ }
+ else
+ {
+ errors++;
+ output.WriteLine($"Failed to convert \"{windowsZone}\"");
+ }
}
- [SkippableFact]
- public void Can_Convert_Windows_System_Zones_To_Iana()
- {
- Skip.IfNot(RuntimeInformation.IsOSPlatform(OSPlatform.Windows), "OS is not Windows.");
-
- var errors = 0;
- IEnumerable windowsZones = TimeZoneInfo.GetSystemTimeZones().Select(x => x.Id);
+ Assert.Equal(0, errors);
+ }
- foreach (string windowsZone in windowsZones)
+ [Fact]
+ public void Can_Convert_Windows_Zones_To_Iana_Golden_Zones()
+ {
+ var errors = 0;
+ foreach (var windowsZone in (ICollection)[.. TZConvert.KnownWindowsTimeZoneIds])
+ {
+ if (TZConvert.TryWindowsToIana(windowsZone, out var ianaZone))
{
- if (TZConvert.TryWindowsToIana(windowsZone, out string ianaZone))
- {
- Assert.NotNull(ianaZone);
- Assert.NotEqual(string.Empty, ianaZone);
- }
- else
- {
- errors++;
- _output.WriteLine($"Failed to convert \"{windowsZone}\"");
- }
+ Assert.NotNull(ianaZone);
+ Assert.NotEqual(string.Empty, ianaZone);
+ }
+ else
+ {
+ errors++;
+ output.WriteLine($"Failed to convert \"{windowsZone}\"");
}
-
- Assert.Equal(0, errors);
}
- [Fact]
- public void Can_Convert_Windows_Zones_To_Iana_Golden_Zones()
- {
- var errors = 0;
- ICollection windowsZones = TZConvert.KnownWindowsTimeZoneIds;
+ Assert.Equal(0, errors);
+ }
- foreach (string windowsZone in windowsZones)
- {
- if (TZConvert.TryWindowsToIana(windowsZone, out string ianaZone))
- {
- Assert.NotNull(ianaZone);
- Assert.NotEqual(string.Empty, ianaZone);
- }
- else
- {
- errors++;
- _output.WriteLine($"Failed to convert \"{windowsZone}\"");
- }
- }
+ [Fact]
+ public void Can_Convert_Windows_Zones_To_Iana_Regional_Zones()
+ {
+ var result1 = TZConvert.WindowsToIana("Central Europe Standard Time", "CZ");
+ Assert.Equal("Europe/Prague", result1);
- Assert.Equal(0, errors);
- }
+ var result2 = TZConvert.WindowsToIana("Central Europe Standard Time", "foo");
+ Assert.Equal("Europe/Budapest", result2);
- [Fact]
- public void Can_Convert_Windows_Zones_To_Iana_Regional_Zones()
- {
- string result1 = TZConvert.WindowsToIana("Central Europe Standard Time", "CZ");
- Assert.Equal("Europe/Prague", result1);
+ var result3 = TZConvert.WindowsToIana("Central Europe Standard Time");
+ Assert.Equal("Europe/Budapest", result3);
+ }
- string result2 = TZConvert.WindowsToIana("Central Europe Standard Time", "foo");
- Assert.Equal("Europe/Budapest", result2);
+ [Fact]
+ public void Can_Convert_UTC_Aliases()
+ {
+ var result1 = TZConvert.WindowsToIana("UTC");
+ Assert.Equal("Etc/UTC", result1);
- string result3 = TZConvert.WindowsToIana("Central Europe Standard Time");
- Assert.Equal("Europe/Budapest", result3);
+ var utcAliases = "Etc/UTC Etc/UCT Etc/Universal Etc/Zulu UCT UTC Universal Zulu".Split();
+ var gmtAliases = "Etc/GMT Etc/GMT+0 Etc/GMT-0 Etc/GMT0 Etc/Greenwich GMT GMT+0 GMT-0 GMT0 Greenwich".Split();
+ foreach (var alias in utcAliases.Concat(gmtAliases))
+ {
+ var result2 = TZConvert.IanaToWindows(alias);
+ Assert.Equal(alias + ":UTC", alias + ":" + result2);
}
+ }
- [Fact]
- public void Can_Convert_UTC_Aliases()
- {
- string result1 = TZConvert.WindowsToIana("UTC");
- Assert.Equal("Etc/UTC", result1);
+ [Fact]
+ public void Can_Convert_Asia_RTZ11_To_IANA()
+ {
+ var result = TZConvert.WindowsToIana("Russia Time Zone 11");
+ Assert.Equal("Asia/Kamchatka", result);
+ }
- string[] utcAliases = "Etc/UTC Etc/UCT Etc/Universal Etc/Zulu UCT UTC Universal Zulu".Split();
- string[] gmtAliases = "Etc/GMT Etc/GMT+0 Etc/GMT-0 Etc/GMT0 Etc/Greenwich GMT GMT+0 GMT-0 GMT0 Greenwich".Split();
- IEnumerable aliases = utcAliases.Concat(gmtAliases);
+ [Fact]
+ public void Can_Convert_Yukon_Standard_Time_To_IANA()
+ {
+ var result = TZConvert.WindowsToIana("Yukon Standard Time");
+ Assert.Equal("America/Whitehorse", result);
+ }
- foreach (string alias in aliases)
- {
- string result2 = TZConvert.IanaToWindows(alias);
- Assert.Equal(alias + ":UTC", alias + ":" + result2);
- }
- }
+ [Fact]
+ public void Can_Convert_Kamchatka_Standard_Time_To_IANA()
+ {
+ var result = TZConvert.WindowsToIana("Kamchatka Standard Time");
+ Assert.Equal("Asia/Kamchatka", result);
+ }
- [Fact]
- public void Can_Convert_Asia_RTZ11_To_IANA()
- {
- string result = TZConvert.WindowsToIana("Russia Time Zone 11");
- Assert.Equal("Asia/Kamchatka", result);
- }
+ [Fact]
+ public void Can_Convert_Mid_Atlantic_Standard_Time_To_IANA()
+ {
+ var result = TZConvert.WindowsToIana("Mid-Atlantic Standard Time");
+ Assert.Equal("Etc/GMT+2", result);
+ }
- [Fact]
- public void Can_Convert_Yukon_Standard_Time_To_IANA()
- {
- string result = TZConvert.WindowsToIana("Yukon Standard Time");
- Assert.Equal("America/Whitehorse", result);
- }
+ [Fact]
+ public void Can_Convert_SA_Western_Standard_Time_To_IANA_With_Default_Mode()
+ {
+ var result = TZConvert.WindowsToIana("SA Western Standard Time", "AG");
+ Assert.Equal("America/Antigua", result);
+ }
- [Fact]
- public void Can_Convert_Kamchatka_Standard_Time_To_IANA()
- {
- string result = TZConvert.WindowsToIana("Kamchatka Standard Time");
- Assert.Equal("Asia/Kamchatka", result);
- }
+ [Fact]
+ public void Can_Convert_SA_Western_Standard_Time_To_IANA_With_Canonical_Mode()
+ {
+ var result = TZConvert.WindowsToIana("SA Western Standard Time", "AG", LinkResolution.Canonical);
+ Assert.Equal("America/Puerto_Rico", result);
+ }
- [Fact]
- public void Can_Convert_Mid_Atlantic_Standard_Time_To_IANA()
- {
- string result = TZConvert.WindowsToIana("Mid-Atlantic Standard Time");
- Assert.Equal("Etc/GMT+2", result);
- }
+ [Fact]
+ public void Can_Convert_SA_Western_Standard_Time_To_IANA_With_Original_Mode()
+ {
+ var result = TZConvert.WindowsToIana("SA Western Standard Time", "AG", LinkResolution.Original);
+ Assert.Equal("America/Antigua", result);
+ }
+
+ [Fact]
+ public void Can_Convert_India_Standard_Time_To_IANA_With_Default_Mode()
+ {
+ var result = TZConvert.WindowsToIana("India Standard Time");
+ Assert.Equal("Asia/Kolkata", result);
+ }
+
+ [Fact]
+ public void Can_Convert_India_Standard_Time_To_IANA_With_Canonical_Mode()
+ {
+ var result = TZConvert.WindowsToIana("India Standard Time", LinkResolution.Canonical);
+ Assert.Equal("Asia/Kolkata", result);
+ }
+
+ [Fact]
+ public void Can_Convert_India_Standard_Time_To_IANA_With_Original_Mode()
+ {
+ var result = TZConvert.WindowsToIana("India Standard Time", LinkResolution.Original);
+ Assert.Equal("Asia/Calcutta", result);
+ }
+
+ [Fact]
+ public void Can_Convert_UTCPlus13_To_IANA_With_Default_Mode()
+ {
+ var result = TZConvert.WindowsToIana("UTC+13", "KI");
+ Assert.Equal("Pacific/Kanton", result);
+ }
+
+ [Fact]
+ public void Can_Convert_UTCPlus13_To_IANA_With_Canonical_Mode()
+ {
+ var result = TZConvert.WindowsToIana("UTC+13", "KI", LinkResolution.Canonical);
+ Assert.Equal("Pacific/Kanton", result);
+ }
+
+ [Fact]
+ public void Can_Convert_UTCPlus13_To_IANA_With_Original_Mode()
+ {
+ var result = TZConvert.WindowsToIana("UTC+13", "KI", LinkResolution.Original);
+ Assert.Equal("Pacific/Enderbury", result);
+ }
+
+ [Fact]
+ public void Can_Convert_MountainStandardTimeMexico_To_IANA_With_Default_Mode()
+ {
+ var result = TZConvert.WindowsToIana("Mountain Standard Time (Mexico)");
+ Assert.Equal("America/Mazatlan", result);
+ }
+
+ [Fact]
+ public void Can_Convert_MountainStandardTimeMexico_To_IANA_With_Canonical_Mode()
+ {
+ var result = TZConvert.WindowsToIana("Mountain Standard Time (Mexico)", LinkResolution.Canonical);
+ Assert.Equal("America/Mazatlan", result);
+ }
+
+ [Fact]
+ public void Can_Convert_MountainStandardTimeMexico_To_IANA_With_Original_Mode()
+ {
+ var result = TZConvert.WindowsToIana("Mountain Standard Time (Mexico)", LinkResolution.Original);
+ Assert.Equal("America/Mazatlan", result);
}
}