From 92192ac5b6cf0b15db18740d43a986418c4f46db Mon Sep 17 00:00:00 2001 From: Dennis Date: Sun, 5 Oct 2014 03:46:18 +0200 Subject: [PATCH] Time strings now converted correctly - Removed all System.TimeSpan's - Created a new Folder 'Utils' - Created a new class 'TimeStringConverter' with two sub-classes Earth-/KerbinTimeStringConverter Fixes #192 --- src/RemoteTech/RTUtil.cs | 85 +++------- src/RemoteTech/RemoteTech.csproj | 3 +- src/RemoteTech/UI/AttitudeFragment.cs | 10 +- src/RemoteTech/UI/QueueFragment.cs | 10 +- src/RemoteTech/Utils/TimeStringConverter.cs | 169 ++++++++++++++++++++ 5 files changed, 196 insertions(+), 81 deletions(-) create mode 100644 src/RemoteTech/Utils/TimeStringConverter.cs diff --git a/src/RemoteTech/RTUtil.cs b/src/RemoteTech/RTUtil.cs index 9e68a0021..dc82e9f32 100644 --- a/src/RemoteTech/RTUtil.cs +++ b/src/RemoteTech/RTUtil.cs @@ -18,8 +18,6 @@ public static partial class RTUtil { public static double GameTime { get { return Planetarium.GetUniversalTime(); } } - public const int DaysInAYear = 365; - public static readonly String[] DistanceUnits = { "", "k", "M", "G", "T" }, ClassDescripts = { "Short-Planetary (SP)", @@ -28,50 +26,21 @@ public static readonly String[] "Short-Interplanetary (SI)", "Medium-Interplanetary (MI)", "Long-Interplanetary (LI)"}; - - private static readonly Regex mDurationRegex = new Regex( - String.Format("{0}?{1}?{2}?{3}?{4}?", - @"(?:(?\d*\.?\d+)\s*s[a-z]*[,\s]*)", - @"(?:(?\d*\.?\d+)\s*m[a-z]*[,\s]*)", - @"(?:(?\d*\.?\d+)\s*h[a-z]*[,\s]*)", - @"(?:(?\d*\.?\d+)\s*d[a-z]*[,\s]*)", - @"(?:(?\d*\.?\d+)\s*y[a-z]*[,\s]*)")); - - public static bool TryParseDuration(String duration, out TimeSpan time) + + public static double TryParseDuration(String duration) { - time = new TimeSpan(); - MatchCollection matches = mDurationRegex.Matches(duration); - foreach (Match match in matches) + TimeStringConverter time; + + if (GameSettings.KERBIN_TIME == true) { - if (match.Groups["seconds"].Success) - { - time += TimeSpan.FromSeconds(Double.Parse(match.Groups["seconds"].Value)); - } - if (match.Groups["minutes"].Success) - { - time += TimeSpan.FromMinutes(Double.Parse(match.Groups["minutes"].Value)); - } - if (match.Groups["hours"].Success) - { - time += TimeSpan.FromHours(Double.Parse(match.Groups["hours"].Value)); - } - if (match.Groups["days"].Success) - { - time += TimeSpan.FromDays(Double.Parse(match.Groups["days"].Value)); - } - if (match.Groups["years"].Success) - { - time += TimeSpan.FromDays(Double.Parse(match.Groups["years"].Value) * DaysInAYear); - } + time = new KerbinTimeStringConverter(); } - if (time.TotalSeconds == 0) + else { - double parsedDouble; - bool result = Double.TryParse(duration, out parsedDouble); - time = TimeSpan.FromSeconds(result ? parsedDouble : 0); - return result; + time = new EarthTimeStringConverter(); } - return true; + + return time.parseString(duration); } public static void ScreenMessage(String msg) @@ -121,33 +90,25 @@ public static float Format180To360(float degrees) } } + /// + /// + /// + /// + /// public static String FormatDuration(double duration) { - var time = TimeSpan.FromSeconds(duration); - var s = new StringBuilder(); - if (time.TotalDays / DaysInAYear >= 1) - { - s.Append(Math.Floor(time.TotalDays / DaysInAYear)); - s.Append("y"); - } - if (time.TotalDays % DaysInAYear >= 1) - { - s.Append(Math.Floor(time.TotalDays % DaysInAYear)); - s.Append("d"); - } - if (time.Hours > 0) + TimeStringConverter time; + + if (GameSettings.KERBIN_TIME == true) { - s.Append(time.Hours); - s.Append("h"); + time = new KerbinTimeStringConverter(); } - if (time.Minutes > 0) + else { - s.Append(time.Minutes); - s.Append("m"); + time = new EarthTimeStringConverter(); } - s.Append((time.Seconds + time.Milliseconds / 1000.0f).ToString("F2")); - s.Append("s"); - return s.ToString(); + + return time.parseDouble(duration); } /// diff --git a/src/RemoteTech/RemoteTech.csproj b/src/RemoteTech/RemoteTech.csproj index e2687ab23..a939753f2 100644 --- a/src/RemoteTech/RemoteTech.csproj +++ b/src/RemoteTech/RemoteTech.csproj @@ -1,4 +1,4 @@ - + @@ -119,6 +119,7 @@ + diff --git a/src/RemoteTech/UI/AttitudeFragment.cs b/src/RemoteTech/UI/AttitudeFragment.cs index a28e362b3..c2938095d 100644 --- a/src/RemoteTech/UI/AttitudeFragment.cs +++ b/src/RemoteTech/UI/AttitudeFragment.cs @@ -49,15 +49,7 @@ private float Roll private double Duration { - get - { - TimeSpan duration; - if (!RTUtil.TryParseDuration(mDuration, out duration)) - { - duration = new TimeSpan(); - } - return duration.TotalSeconds; - } + get { return RTUtil.TryParseDuration(mDuration); } set { mDuration = RTUtil.FormatDuration(value); } } diff --git a/src/RemoteTech/UI/QueueFragment.cs b/src/RemoteTech/UI/QueueFragment.cs index cca0f3c9e..b1ff4f521 100644 --- a/src/RemoteTech/UI/QueueFragment.cs +++ b/src/RemoteTech/UI/QueueFragment.cs @@ -16,15 +16,7 @@ public class QueueFragment : IFragment private double Delay { - get - { - TimeSpan delay; - if (!RTUtil.TryParseDuration(mExtraDelay, out delay)) - { - delay = new TimeSpan(); - } - return Math.Max(delay.TotalSeconds, 0); - } + get { return RTUtil.TryParseDuration(mExtraDelay); } set { mExtraDelay = value.ToString(); } } diff --git a/src/RemoteTech/Utils/TimeStringConverter.cs b/src/RemoteTech/Utils/TimeStringConverter.cs new file mode 100644 index 000000000..e01f9696f --- /dev/null +++ b/src/RemoteTech/Utils/TimeStringConverter.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; + +namespace RemoteTech +{ + /// + /// This class converts time strings like "1d 2m 2s" into a + /// double value as seconds and also vice versa, based on + /// earth time. + /// + class EarthTimeStringConverter : TimeStringConverter + { + /// + /// Define the base seconds for days, hours and minutes + /// + public EarthTimeStringConverter() + { + this.SecondsPerDay = 86400; + this.SecondsPerHour = 3600; + this.SecondsPerMinute = 60; + } + } + + /// + /// This class converts time strings like "1d 2m 2s" into a + /// double value as seconds and also vice versa, based on + /// kerbin time. + /// + class KerbinTimeStringConverter : TimeStringConverter + { + /// + /// Define the base seconds for days, hours and minutes + /// + public KerbinTimeStringConverter() + { + this.SecondsPerDay = 21600; + this.SecondsPerHour = 3600; + this.SecondsPerMinute = 60; + } + } + + /// + /// This class converts time strings like "1d 2m 2s" into a + /// double value as seconds and also vice versa. + /// + abstract class TimeStringConverter + { + /// + /// Constant value for the days per year + /// + public const int DAYS_PER_YEAR = 365; + /// + /// Get the seconds for one year + /// + protected uint SecondsPerYear { get { return TimeStringConverter.DAYS_PER_YEAR * this.SecondsPerDay; } } + /// + /// Get the seconds for one day + /// + protected uint SecondsPerDay; + /// + /// Get the seconds for one hour + /// + protected uint SecondsPerHour; + /// + /// Get the seconds for one minute + /// + protected uint SecondsPerMinute; + /// + /// Expression for parsing the time string + /// + private static readonly Regex DurationRegex = new Regex( + String.Format("{0}?{1}?{2}?{3}?{4}?", + @"(?:(?\d*\.?\d+)\s*s[a-z]*[,\s]*)", + @"(?:(?\d*\.?\d+)\s*m[a-z]*[,\s]*)", + @"(?:(?\d*\.?\d+)\s*h[a-z]*[,\s]*)", + @"(?:(?\d*\.?\d+)\s*d[a-z]*[,\s]*)", + @"(?:(?\d*\.?\d+)\s*y[a-z]*[,\s]*)")); + + /// + /// This method will parse a time string like "1d 2m 3s" and returns the + /// seconds for this string. If no matching string was found with the + /// "DurationRegex" the return value will be 0. + /// + /// time string like "1d 2m 3s". Possible values: 0y 0d 0h 0m 0s + /// Given time string converted in seconds + public Double parseString(String duration) + { + Double timeInSeconds = 0; + MatchCollection matches = TimeStringConverter.DurationRegex.Matches(duration); + + foreach (Match match in matches) + { + if (match.Groups["seconds"].Success) + { + timeInSeconds += Double.Parse(match.Groups["seconds"].Value); + } + if (match.Groups["minutes"].Success) + { + timeInSeconds += Double.Parse(match.Groups["minutes"].Value) * this.SecondsPerMinute; + } + if (match.Groups["hours"].Success) + { + timeInSeconds += Double.Parse(match.Groups["hours"].Value) * this.SecondsPerHour; + } + if (match.Groups["days"].Success) + { + timeInSeconds += Double.Parse(match.Groups["days"].Value) * this.SecondsPerDay; + } + if (match.Groups["years"].Success) + { + timeInSeconds += Double.Parse(match.Groups["years"].Value) * this.SecondsPerYear; + } + } + + return timeInSeconds; + } + + /// + /// This method will parse a time as seconds and returns the time string of this. + /// + /// Time as seconds + /// Given time as seconds converted to a time string like "1d 2m 3s" + public String parseDouble(Double duration) + { + Double time = duration; + StringBuilder s = new StringBuilder(); + + // extract years + if (time >= this.SecondsPerYear) + time = this.calcFromSecondsToSring(time, s, this.SecondsPerYear, "y"); + + // extract days + if (time >= this.SecondsPerDay) + time = this.calcFromSecondsToSring(time, s, this.SecondsPerDay, "d"); + + // extract hours + if (time >= this.SecondsPerHour) + time = this.calcFromSecondsToSring(time, s, this.SecondsPerHour, "h"); + + // extract minutes + if (time >= this.SecondsPerMinute) + time = this.calcFromSecondsToSring(time, s, this.SecondsPerMinute, "m"); + + // kill the micro seconds + s.Append(time.ToString("F2")); + s.Append("s"); + + return s.ToString(); + } + + /// + /// This method extracts the time segments + /// + /// Seconds to convert + /// Stringbuilder to appand to + /// Base for the calculation + /// Will be appand to the string builder + /// The remaining seconds + private Double calcFromSecondsToSring(Double time, StringBuilder appandTo, uint baseSeconds, String prefix) + { + appandTo.Append(Math.Floor(time / baseSeconds)); + appandTo.Append(prefix); + return (time % baseSeconds); + } + } +}