mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-14 08:24:16 +09:00
[utils,doc] update timezone sync procedure
* add new C# utility to generate timezone mappings * update procedure to follow for updating timezones * remove obsolete TimeZones.csx script * update generated files with new tool
This commit is contained in:
@@ -1,12 +1,22 @@
|
||||
On an up to date windows machine run the following scripts (from checkout root):
|
||||
On an up to date windows machine run the following binary after a build with -DWITH_TIMEZONE_UPDATER=ON (from build directory):
|
||||
|
||||
csi.exe scripts/TimeZones.csx
|
||||
csi.exe scripts/WindowsZones.csx
|
||||
tzextract <path to source>\winpr\libwinpr\timezone
|
||||
|
||||
After running the scripts check
|
||||
* winpr/libwinpr/timezone/TimeZones.c
|
||||
* git clang-format -f to eliminate formatting changes
|
||||
* winpr/libwinpr/timezone/WindowsZones.c
|
||||
for changes.
|
||||
|
||||
Commit if the definitions changed and create a pull request at
|
||||
https://github.com/FreeRDP/FreeRDP
|
||||
on any machine run the following script from checkout root:
|
||||
|
||||
./scripts/update-windows-zones.py
|
||||
|
||||
After running the scripts check
|
||||
* git clang-format -f to eliminate formatting changes
|
||||
* winpr/libwinpr/timezone/WindowsZones.c
|
||||
for changes.
|
||||
|
||||
Commit if the definitions changed:
|
||||
1. run `git clang-format -f` on these changed files
|
||||
2. commit these changes
|
||||
3. create a pull request at https://github.com/FreeRDP/FreeRDP
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Time Zone Redirection Table Generator
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
/* Run with ' csi scripts/TimeZones.csx' from freerdp checkout root */
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Globalization;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
struct SYSTEM_TIME_ENTRY
|
||||
{
|
||||
public UInt16 wYear;
|
||||
public UInt16 wMonth;
|
||||
public UInt16 wDayOfWeek;
|
||||
public UInt16 wDay;
|
||||
public UInt16 wHour;
|
||||
public UInt16 wMinute;
|
||||
public UInt16 wSecond;
|
||||
public UInt16 wMilliseconds;
|
||||
};
|
||||
|
||||
struct TIME_ZONE_RULE_ENTRY
|
||||
{
|
||||
public long TicksStart;
|
||||
public long TicksEnd;
|
||||
public Int32 DaylightDelta;
|
||||
public SYSTEM_TIME_ENTRY StandardDate;
|
||||
public SYSTEM_TIME_ENTRY DaylightDate;
|
||||
};
|
||||
|
||||
struct TIME_ZONE_ENTRY
|
||||
{
|
||||
public string Id;
|
||||
public Int32 Bias;
|
||||
public bool SupportsDST;
|
||||
public string DisplayName;
|
||||
public string StandardName;
|
||||
public string DaylightName;
|
||||
public string RuleTable;
|
||||
public UInt32 RuleTableCount;
|
||||
};
|
||||
|
||||
int i;
|
||||
UInt32 index;
|
||||
const string file = @"winpr/libwinpr/timezone/TimeZones.c";
|
||||
TimeZoneInfo.AdjustmentRule[] rules;
|
||||
StreamWriter stream = new StreamWriter(file, false);
|
||||
ReadOnlyCollection<TimeZoneInfo> timeZones = TimeZoneInfo.GetSystemTimeZones();
|
||||
|
||||
Console.WriteLine("Updating " + file);
|
||||
stream.WriteLine("/* ");
|
||||
stream.WriteLine(" * Automatically generated with scripts/TimeZones.csx");
|
||||
stream.WriteLine(" */ ");
|
||||
stream.WriteLine();
|
||||
|
||||
stream.WriteLine("#include \"TimeZones.h\"");
|
||||
stream.WriteLine();
|
||||
|
||||
index = 0;
|
||||
|
||||
foreach (TimeZoneInfo timeZone in timeZones)
|
||||
{
|
||||
rules = timeZone.GetAdjustmentRules();
|
||||
|
||||
if ((!timeZone.SupportsDaylightSavingTime) || (rules.Length < 1))
|
||||
{
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
|
||||
stream.WriteLine("static const TIME_ZONE_RULE_ENTRY TimeZoneRuleTable_{0}[] =", index);
|
||||
stream.WriteLine("{");
|
||||
|
||||
i = 0;
|
||||
foreach (TimeZoneInfo.AdjustmentRule rule in rules)
|
||||
{
|
||||
DateTime time;
|
||||
TIME_ZONE_RULE_ENTRY tzr;
|
||||
TimeZoneInfo.TransitionTime transition;
|
||||
|
||||
tzr.TicksStart = rule.DateEnd.ToUniversalTime().Ticks;
|
||||
tzr.TicksEnd = rule.DateStart.ToUniversalTime().Ticks;
|
||||
tzr.DaylightDelta = (Int32)rule.DaylightDelta.TotalMinutes;
|
||||
|
||||
transition = rule.DaylightTransitionEnd;
|
||||
time = transition.TimeOfDay;
|
||||
|
||||
tzr.StandardDate.wYear = (UInt16)0;
|
||||
tzr.StandardDate.wMonth = (UInt16)transition.Month;
|
||||
tzr.StandardDate.wDayOfWeek = (UInt16)transition.DayOfWeek;
|
||||
tzr.StandardDate.wDay = (UInt16)transition.Week;
|
||||
tzr.StandardDate.wHour = (UInt16)time.Hour;
|
||||
tzr.StandardDate.wMinute = (UInt16)time.Minute;
|
||||
tzr.StandardDate.wSecond = (UInt16)time.Second;
|
||||
tzr.StandardDate.wMilliseconds = (UInt16)time.Millisecond;
|
||||
|
||||
transition = rule.DaylightTransitionStart;
|
||||
time = transition.TimeOfDay;
|
||||
|
||||
tzr.DaylightDate.wYear = (UInt16)0;
|
||||
tzr.DaylightDate.wMonth = (UInt16)transition.Month;
|
||||
tzr.DaylightDate.wDayOfWeek = (UInt16)transition.DayOfWeek;
|
||||
tzr.DaylightDate.wDay = (UInt16)transition.Week;
|
||||
tzr.DaylightDate.wHour = (UInt16)time.Hour;
|
||||
tzr.DaylightDate.wMinute = (UInt16)time.Minute;
|
||||
tzr.DaylightDate.wSecond = (UInt16)time.Second;
|
||||
tzr.DaylightDate.wMilliseconds = (UInt16)time.Millisecond;
|
||||
|
||||
stream.Write("\t{");
|
||||
stream.Write(" {0}ULL, {1}ULL, {2},", tzr.TicksStart, tzr.TicksEnd, tzr.DaylightDelta);
|
||||
|
||||
stream.Write(" { ");
|
||||
stream.Write("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}",
|
||||
tzr.StandardDate.wYear, tzr.StandardDate.wMonth, tzr.StandardDate.wDayOfWeek,
|
||||
tzr.StandardDate.wDay, tzr.StandardDate.wHour, tzr.StandardDate.wMinute,
|
||||
tzr.StandardDate.wSecond, tzr.StandardDate.wMilliseconds);
|
||||
stream.Write(" }, ");
|
||||
|
||||
stream.Write("{ ");
|
||||
stream.Write("{0}, {1}, {2}, {3}, {4}, {5}, {6}, {7}",
|
||||
tzr.DaylightDate.wYear, tzr.DaylightDate.wMonth, tzr.DaylightDate.wDayOfWeek,
|
||||
tzr.DaylightDate.wDay, tzr.DaylightDate.wHour, tzr.DaylightDate.wMinute,
|
||||
tzr.DaylightDate.wSecond, tzr.DaylightDate.wMilliseconds);
|
||||
stream.Write(" },");
|
||||
|
||||
if (++i < rules.Length)
|
||||
stream.WriteLine(" },");
|
||||
else
|
||||
stream.WriteLine(" }");
|
||||
}
|
||||
|
||||
stream.WriteLine("};");
|
||||
stream.WriteLine();
|
||||
index++;
|
||||
}
|
||||
|
||||
index = 0;
|
||||
stream.WriteLine("const TIME_ZONE_ENTRY TimeZoneTable[] =");
|
||||
stream.WriteLine("{");
|
||||
|
||||
foreach (TimeZoneInfo timeZone in timeZones)
|
||||
{
|
||||
TIME_ZONE_ENTRY tz;
|
||||
TimeSpan offset = timeZone.BaseUtcOffset;
|
||||
|
||||
rules = timeZone.GetAdjustmentRules();
|
||||
|
||||
tz.Id = timeZone.Id;
|
||||
tz.Bias = -(Int32)offset.TotalMinutes;
|
||||
|
||||
tz.SupportsDST = timeZone.SupportsDaylightSavingTime;
|
||||
|
||||
tz.DisplayName = timeZone.DisplayName;
|
||||
tz.StandardName = timeZone.StandardName;
|
||||
tz.DaylightName = timeZone.DaylightName;
|
||||
|
||||
if ((!tz.SupportsDST) || (rules.Length < 1))
|
||||
{
|
||||
tz.RuleTableCount = 0;
|
||||
tz.RuleTable = "NULL";
|
||||
}
|
||||
else
|
||||
{
|
||||
tz.RuleTableCount = (UInt32)rules.Length;
|
||||
tz.RuleTable = "TimeZoneRuleTable_" + index;
|
||||
}
|
||||
|
||||
stream.WriteLine("\t{");
|
||||
|
||||
stream.WriteLine("\t\t\"{0}\", {1}, {2}, \"{3}\",",
|
||||
tz.Id, tz.Bias, tz.SupportsDST ? "TRUE" : "FALSE", tz.DisplayName);
|
||||
|
||||
stream.WriteLine("\t\t\"{0}\", \"{1}\",", tz.StandardName, tz.DaylightName);
|
||||
stream.WriteLine("\t\t{0}, {1}", tz.RuleTable, tz.RuleTableCount);
|
||||
|
||||
index++;
|
||||
|
||||
if ((int)index < timeZones.Count)
|
||||
stream.WriteLine("\t},");
|
||||
else
|
||||
stream.WriteLine("\t}");
|
||||
}
|
||||
stream.WriteLine("};");
|
||||
stream.WriteLine();
|
||||
stream.WriteLine("const size_t TimeZoneTableNrElements = ARRAYSIZE(TimeZoneTable);");
|
||||
stream.WriteLine();
|
||||
|
||||
stream.Close();
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
/* Automatically generated by tzextract */
|
||||
|
||||
#include "TimeZoneNameMap.h"
|
||||
|
||||
const TimeZoneNameMapEntry TimeZoneNameMap[] = {
|
||||
@@ -286,4 +288,5 @@ const TimeZoneNameMapEntry TimeZoneNameMap[] = {
|
||||
{ "Line Islands Standard Time", "Line Islands Standard Time", "(UTC+14:00) Kiritimati Island",
|
||||
"Line Islands Daylight Time", "Pacific/Kiritimati" },
|
||||
};
|
||||
|
||||
const size_t TimeZoneNameMapSize = ARRAYSIZE(TimeZoneNameMap);
|
||||
|
||||
@@ -112,9 +112,9 @@ static const char* map_fallback(const char* iana, TimeZoneNameType type)
|
||||
if (!iana)
|
||||
return NULL;
|
||||
|
||||
for (size_t x = 0; x < WindowsTimeZoneIdTableNrElements; x++)
|
||||
for (size_t x = 0; x < WindowsZonesNrElements; x++)
|
||||
{
|
||||
const WINDOWS_TZID_ENTRY* const entry = &WindowsTimeZoneIdTable[x];
|
||||
const WINDOWS_TZID_ENTRY* const entry = &WindowsZones[x];
|
||||
if (strcmp(entry->tzid, iana) == 0)
|
||||
return entry->windows;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -12,7 +12,7 @@ typedef struct
|
||||
const char* tzid;
|
||||
} WINDOWS_TZID_ENTRY;
|
||||
|
||||
extern const WINDOWS_TZID_ENTRY WindowsTimeZoneIdTable[];
|
||||
extern const size_t WindowsTimeZoneIdTableNrElements;
|
||||
extern const WINDOWS_TZID_ENTRY WindowsZones[];
|
||||
extern const size_t WindowsZonesNrElements;
|
||||
|
||||
#endif /* WINPR_WINDOWS_ZONES_H_ */
|
||||
|
||||
27
winpr/libwinpr/timezone/utils/CMakeLists.txt
Normal file
27
winpr/libwinpr/timezone/utils/CMakeLists.txt
Normal file
@@ -0,0 +1,27 @@
|
||||
cmake_minimum_required(VERSION 3.13)
|
||||
|
||||
if(POLICY CMP0091)
|
||||
cmake_policy(SET CMP0091 NEW)
|
||||
endif()
|
||||
|
||||
project(tzextract VERSION 1.0.0 LANGUAGES CSharp)
|
||||
|
||||
set(CMAKE_CSharp_FLAGS "/langversion:10")
|
||||
set(CMAKE_DOTNET_TARGET_FRAMEWORK "net6.0")
|
||||
set(CMAKE_DOTNET_SDK "Microsoft.NET.Sdk")
|
||||
|
||||
add_executable(${PROJECT_NAME}
|
||||
tzextract.cs
|
||||
)
|
||||
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY WIN32_EXECUTABLE FALSE)
|
||||
|
||||
set_property(TARGET ${PROJECT_NAME} PROPERTY VS_DOTNET_REFERENCES
|
||||
"System"
|
||||
"System.Collections.Generic"
|
||||
"System.IO"
|
||||
"System.Net.Http"
|
||||
"System.Linq"
|
||||
"System.Threading"
|
||||
"System.Threading.Tasks"
|
||||
)
|
||||
172
winpr/libwinpr/timezone/utils/tzextract.cs
Normal file
172
winpr/libwinpr/timezone/utils/tzextract.cs
Normal file
@@ -0,0 +1,172 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using System.Xml.Schema;
|
||||
|
||||
internal class Program
|
||||
{
|
||||
private static string app = AppDomain.CurrentDomain.FriendlyName;
|
||||
private static TextWriter stderr = Console.Error;
|
||||
private static TextWriter stdout = Console.Out;
|
||||
|
||||
private static void usage()
|
||||
{
|
||||
stderr.WriteLine("Usage:");
|
||||
stderr.WriteLine(app + " <path to output files>");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
private static bool writeZoneMap(string path)
|
||||
{
|
||||
string fname = "TimeZoneNameMap";
|
||||
string fpath = Path.Combine(path, fname + ".c");
|
||||
|
||||
using (StreamWriter fs = new StreamWriter(fpath))
|
||||
{
|
||||
fs.WriteLine("/* Automatically generated by " + app + " */");
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("#include \"" + fname + ".h\"");
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("const " + fname + "Entry " + fname + "[] ={");
|
||||
|
||||
foreach (System.TimeZoneInfo tz in System.TimeZoneInfo.GetSystemTimeZones())
|
||||
{
|
||||
string iana;
|
||||
System.TimeZoneInfo.TryConvertWindowsIdToIanaId(tz.Id, out iana);
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.Append("{ \"");
|
||||
sb.Append(tz.Id);
|
||||
sb.Append("\", \"");
|
||||
sb.Append(tz.StandardName);
|
||||
sb.Append("\", \"");
|
||||
sb.Append(tz.DisplayName);
|
||||
sb.Append("\", \"");
|
||||
sb.Append(tz.DaylightName);
|
||||
sb.Append("\", \"");
|
||||
sb.Append(iana);
|
||||
sb.Append("\" },");
|
||||
fs.WriteLine(sb.ToString());
|
||||
}
|
||||
|
||||
fs.WriteLine("};");
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("const size_t " + fname + "Size = ARRAYSIZE(" + fname + ");");
|
||||
fs.WriteLine("");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void onValidation(object sender, ValidationEventArgs e)
|
||||
{
|
||||
switch (e.Severity)
|
||||
{
|
||||
case XmlSeverityType.Warning:
|
||||
case XmlSeverityType.Error:
|
||||
stderr.WriteLine(e.ToString());
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
private static bool updateWindowsIanaMap(string path)
|
||||
{
|
||||
string url =
|
||||
"https://raw.githubusercontent.com/unicode-org/cldr/main/common/supplemental/windowsZones.xml";
|
||||
string fname = "WindowsZones";
|
||||
string fpath = Path.Combine(path, fname + ".c");
|
||||
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(url);
|
||||
|
||||
stdout.WriteLine("Downloaded and parsed XML from '" + url + "'");
|
||||
|
||||
ValidationEventHandler handler = new ValidationEventHandler(onValidation);
|
||||
// doc.Validate(handler);
|
||||
|
||||
XmlNodeList versions = doc.SelectNodes("//supplementalData/version");
|
||||
XmlNodeList zones = doc.SelectNodes("//supplementalData/windowsZones/mapTimezones");
|
||||
XmlNodeList mzones =
|
||||
doc.SelectNodes("//supplementalData/windowsZones/mapTimezones/mapZone");
|
||||
|
||||
using (StreamWriter fs = new StreamWriter(fpath))
|
||||
{
|
||||
fs.WriteLine("/* Automatically generated by " + app);
|
||||
fs.WriteLine(" *");
|
||||
fs.WriteLine(" * url " + url);
|
||||
|
||||
foreach (XmlNode version in versions)
|
||||
{
|
||||
XmlNode nr = version.Attributes.GetNamedItem("number");
|
||||
fs.WriteLine(" * version: " + nr.InnerText);
|
||||
}
|
||||
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("#include \"" + fname + ".h\"");
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("const \" + fname + \"Entry \" + fname + \"[] ={");
|
||||
|
||||
foreach (XmlNode node in zones)
|
||||
{
|
||||
XmlNode over = node.Attributes.GetNamedItem("otherVersion");
|
||||
XmlNode tver = node.Attributes.GetNamedItem("typeVersion");
|
||||
fs.WriteLine(" * mapTimezones: otherVersion: " + over.InnerText +
|
||||
", typeVersion: " + tver.InnerText);
|
||||
}
|
||||
|
||||
fs.WriteLine(" */");
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("#include \"" + fname + ".h\"");
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("const WINDOWS_TZID_ENTRY " + fname + "IdTable[] = {");
|
||||
|
||||
foreach (XmlNode mzone in mzones)
|
||||
{
|
||||
XmlAttributeCollection attrs = mzone.Attributes;
|
||||
XmlNode wzid = attrs.GetNamedItem("other");
|
||||
XmlNode territory = attrs.GetNamedItem("territory");
|
||||
XmlNode iana = attrs.GetNamedItem("type");
|
||||
fs.WriteLine("\t{ \"" + iana.InnerText + "\", \"" + wzid.InnerText + "\" }, // " +
|
||||
territory.InnerText);
|
||||
}
|
||||
|
||||
fs.WriteLine("};");
|
||||
fs.WriteLine("");
|
||||
fs.WriteLine("const size_t " + fname + "NrElements = ARRAYSIZE(" + fname + ");");
|
||||
}
|
||||
stdout.WriteLine("Finished update");
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (args.Length == 0)
|
||||
{
|
||||
stderr.WriteLine("Missing arguments!");
|
||||
usage();
|
||||
}
|
||||
|
||||
DirectoryInfo info = new DirectoryInfo(args[0]);
|
||||
if (!info.Exists)
|
||||
{
|
||||
stderr.WriteLine("Path '" + info.FullName + "' does not exist");
|
||||
usage();
|
||||
}
|
||||
|
||||
if (!writeZoneMap(info.FullName))
|
||||
return;
|
||||
|
||||
updateWindowsIanaMap(info.FullName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
stderr.WriteLine(e.ToString());
|
||||
Environment.Exit(-23);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user