Como converter a duração ISO 8601 em TimeSpan em VB.Net?
Pergunta
Existe um método de biblioteca padrão que converte uma string que tem duração no padrão ISO 8601 Duration (também usado em XSD para sua duration
type) no objeto .NET TimeSpan?
Por exemplo, P0DT1H0M0S que representa a duração de uma hora, é convertido em New TimeSpan(0,1,0,0,0).
Existe um conversor reverso que funciona da seguinte maneira:Xml.xmlconvert.toString (novo timespan (0,1,0,0,0)) A expressão acima retornará P0DT1H0M0S.
Solução
Isso irá converter de xs:duration para TimeSpan:
System.Xml.XmlConvert.ToTimeSpan("P0DT1H0M0S")
Ver http://msdn.microsoft.com/en-us/library/system.xml.xmlconvert.totimespan.aspx
Outras dicas
Uma pequena palavra de cautela - XmlConvert.ToTimeSpan() é um pouco engraçado quando se trabalha com meses e anos.A classe TimeSpan não possui membros de mês ou ano, provavelmente porque sua duração varia.No entanto, ToTimeSpan() aceitará alegremente uma string de duração com valores de mês ou ano e adivinhar por duração, em vez de lançar uma exceção.Observar:
PS C:\Users\troll> [Reflection.Assembly]::LoadWithPartialName("System.Xml")
GAC Version Location
--- ------- --------
True v2.0.50727 C:\Windows\assembly\GAC_MSIL\System.Xml\2.0.0.0__b77a5c561934e089\System.Xml.dll
PS C:\Users\troll> [System.Xml.XmlConvert]::ToTimeSpan("P1M")
Days : 30
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 25920000000000
TotalDays : 30
TotalHours : 720
TotalMinutes : 43200
TotalSeconds : 2592000
TotalMilliseconds : 2592000000
PS C:\Users\troll> [System.Xml.XmlConvert]::ToTimeSpan("P1Y")
Days : 365
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 0
Ticks : 315360000000000
TotalDays : 365
TotalHours : 8760
TotalMinutes : 525600
TotalSeconds : 31536000
TotalMilliseconds : 31536000000
PS C:\Users\troll>
Como disse o troll sujo @ima, o TimeSpan sempre traduz anos como 365 dias e meses como 30 dias.
TimeSpan ts = System.Xml.XmlConvert.ToTimeSpan("P5Y");
DateTime now = new DateTime(2008,2,29);
Console.WriteLine(now + ts); // 27/02/2013 0:00:00
Para resolvê -lo, você deve adicionar cada campo individualmente, em vez de usar o Timespan.
DateTime now = new DateTime (2008, 2, 29);
string duration = "P1Y";
Regex expr =
new Regex (@"(-?)P((\d{1,4})Y)?((\d{1,4})M)?((\d{1,4})D)?(T((\d{1,4})H)?((\d{1,4})M)?((\d{1,4}(\.\d{1,3})?)S)?)?", RegexOptions.Compiled | RegexOptions.CultureInvariant);
bool positiveDuration = false == (input [0] == '-');
MatchCollection matches = expr.Matches (duration);
var g = matches [0];
Func<int,int> getNumber = x => {
if (g.Groups.Count < x || string.IsNullOrEmpty (g.Groups [x].ToString ())) {
return 0;
}
int a = int.Parse (g.Groups [x].ToString ());
return PositiveDuration ? a : a * -1;
};
now.AddYears (getNumber (3));
now.AddMonths (getNumber (5));
now.AddDays (getNumber (7));
now.AddHours (getNumber (10));
now.AddMinutes (getNumber (12));
now.AddSeconds (getNumber (14));
Console.WriteLine (now); // 28/02/2012 0:00:00