我從另一臺機器格式時區信息:轉換一個POSIX風格的時區在C#.NET來的TimeZoneInfo
"CET-1CEST,M3.5.0/2,M10.5.0/3"
(POSIX風格的時區)
我需要解析這一點,並轉換成這一個c# .net TimeZoneInfo class
。
有沒有辦法做到這一點?
我從另一臺機器格式時區信息:轉換一個POSIX風格的時區在C#.NET來的TimeZoneInfo
"CET-1CEST,M3.5.0/2,M10.5.0/3"
(POSIX風格的時區)
我需要解析這一點,並轉換成這一個c# .net TimeZoneInfo class
。
有沒有辦法做到這一點?
我將根據其格式解析它:http://www.ibm.com/developerworks/aix/library/au-aix-posix/
也許你也可以考慮:http://nodatime.org/ - 我目前不知道他們是否支持此功能。
下面的代碼應該做的伎倆。
請記住,雖然這會給你一個有效的TimeZoneInfo
對象,它確實將而不是映射到現有的Windows時區。您可以使用各種轉換功能,例如TimeZoneInfo.ConvertTime
,但不要指望它神奇地知道PST8PDT
應與"Pacific Standard Time"
對齊。
public static TimeZoneInfo PosixToTzi(string posixTz)
{
var parts = posixTz.Split(',');
var zoneparts = Regex.Split(parts[0], @"([0-9\+\-\.]+)");
double baseOffsetHours;
if (zoneparts.Length > 1)
{
if (!Double.TryParse(zoneparts[1], out baseOffsetHours))
throw new FormatException();
}
else
{
// recognize RFC822 time zone abbreviations
switch (zoneparts[0].ToUpper())
{
case "UT":
case "UTC":
case "GMT":
baseOffsetHours = 0;
break;
case "EDT":
baseOffsetHours = 4;
break;
case "EST":
case "CDT":
baseOffsetHours = 5;
break;
case "CST":
case "MDT":
baseOffsetHours = 6;
break;
case "MST":
case "PDT":
baseOffsetHours = 7;
break;
case "PST":
baseOffsetHours = 8;
break;
default:
throw new FormatException();
}
}
double dstOffsetHours = baseOffsetHours - 1;
if (zoneparts.Length == 4)
{
if (!Double.TryParse(zoneparts[3], out dstOffsetHours))
throw new FormatException();
}
var baseOffset = TimeSpan.FromHours(-baseOffsetHours);
var dstDelta = TimeSpan.FromHours(baseOffsetHours - dstOffsetHours);
var rules = new List<TimeZoneInfo.AdjustmentRule>();
if (parts.Length == 3)
{
var rule = TimeZoneInfo.AdjustmentRule.CreateAdjustmentRule(
DateTime.MinValue.Date, DateTime.MaxValue.Date, dstDelta,
ParsePosixTransition(parts[1]), ParsePosixTransition(parts[2]));
rules.Add(rule);
}
return TimeZoneInfo.CreateCustomTimeZone(posixTz, baseOffset, parts[0], zoneparts[0],
zoneparts[zoneparts.Length == 3 ? 2 : 0], rules.ToArray());
}
private static TimeZoneInfo.TransitionTime ParsePosixTransition(string transition)
{
var parts = transition.Split('/');
if (parts.Length > 2)
throw new FormatException();
double hours = 0;
if (parts.Length == 2)
{
if (!Double.TryParse(parts[1], out hours))
throw new FormatException();
}
var time = DateTime.MinValue.AddHours(hours);
if (transition.StartsWith("M", StringComparison.OrdinalIgnoreCase))
{
var dateParts = parts[0].Substring(1).Split('.');
if (dateParts.Length > 3)
throw new FormatException();
int month;
if (!Int32.TryParse(dateParts[0], out month))
throw new FormatException();
int week;
if (!Int32.TryParse(dateParts[1], out week))
throw new FormatException();
int dow;
if (!Int32.TryParse(dateParts[2], out dow))
throw new FormatException();
return TimeZoneInfo.TransitionTime.CreateFloatingDateRule(time, month, week, (DayOfWeek) dow);
}
if (transition.StartsWith("J", StringComparison.OrdinalIgnoreCase))
{
int dayNum;
if (!Int32.TryParse(parts[0].Substring(1), out dayNum))
throw new FormatException();
var date = DateTime.MinValue.AddDays(dayNum);
return TimeZoneInfo.TransitionTime.CreateFixedDateRule(time, date.Month, date.Day);
}
throw new FormatException();
}
根據這篇文章:http://www.ibm.com/developerworks/aix/library/au-aix-posix/一POSIX時間等 「CST6CDT,M3.2.0/2:00:00,M11.1.0/2:00:00」 有下列規格:
,日期在Mm.n.d格式,其中:
好了,基於這些信息,並可能在的TimeZoneInfo類中找到的調整規則,你可以使用此代碼來進行轉換:
public static TimeZoneInfo ConvertPosixToTimeZoneInfo(string posix)
{
string[] tokens = posix.Split(',');
tokens[0] = tokens[0].Replace("/", ".");
var match = Regex.Match(tokens[0], @"[-+]?[0-9]*\.?[0-9]+").Value;
var ticks = (long)(decimal.Parse(match, CultureInfo.InvariantCulture) * 60) * 600000000;
var baseOffset = new TimeSpan(ticks);
var systemTimeZones = TimeZoneInfo.GetSystemTimeZones().Where(t => t.BaseUtcOffset == baseOffset).ToList();
var startRuleTokens = tokens[1].TrimStart('M').Split('/');
var startDateRuleTokens = startRuleTokens[0].Split('.');
var startTimeRuleTokens = startRuleTokens[1].Split(':');
var endRuleTokens = tokens[2].TrimStart('M').Split('/');
var endDateRuleTokens = endRuleTokens[0].Split('.');
var endTimeRuleTokens = endRuleTokens[1].Split(':');
int? targetIndex = null;
for (int i = 0; i < systemTimeZones.Count; i++)
{
var adjustmentRules = systemTimeZones[i].GetAdjustmentRules();
foreach (var rule in adjustmentRules)
{
if (rule.DaylightTransitionStart.Month == int.Parse(startDateRuleTokens[0]) &&
rule.DaylightTransitionStart.Week == int.Parse(startDateRuleTokens[1]) &&
rule.DaylightTransitionStart.DayOfWeek == (DayOfWeek)int.Parse(startDateRuleTokens[2]) &&
rule.DaylightTransitionStart.TimeOfDay.Hour == int.Parse(startTimeRuleTokens[0]) &&
rule.DaylightTransitionStart.TimeOfDay.Minute == int.Parse(startTimeRuleTokens[1]) &&
rule.DaylightTransitionStart.TimeOfDay.Second == int.Parse(startTimeRuleTokens[2]) &&
rule.DaylightTransitionEnd.Month == int.Parse(endDateRuleTokens[0]) &&
rule.DaylightTransitionEnd.Week == int.Parse(endDateRuleTokens[1]) &&
rule.DaylightTransitionEnd.DayOfWeek == (DayOfWeek)int.Parse(endDateRuleTokens[2]) &&
rule.DaylightTransitionEnd.TimeOfDay.Hour == int.Parse(endTimeRuleTokens[0]) &&
rule.DaylightTransitionEnd.TimeOfDay.Minute == int.Parse(endTimeRuleTokens[1]) &&
rule.DaylightTransitionEnd.TimeOfDay.Second == int.Parse(endTimeRuleTokens[2]))
{
targetIndex = i;
break;
}
}
}
if (targetIndex.HasValue)
return systemTimeZones[targetIndex.Value];
return null;
}
解析POSIX以獲得'standard.Offset','daylight.Offset','toDaylight.Date'和'toStandard.Date',然後您需要遍歷可用的'TimeZoneInfo'來查找匹配項。如果沒有匹配,則再次重複忽略這兩個日期。如果你得到多個比賽,那麼你需要選擇一個。如果你沒有匹配,那麼它可能是一個常識字符串而不是'POSIX'字符串。 :) – 2015-02-20 01:07:22