Skip to content

Commit

Permalink
Time strings now converted correctly
Browse files Browse the repository at this point in the history
- Removed all System.TimeSpan's
- Created a new Folder 'Utils'
- Created a new class 'TimeStringConverter' with two sub-classes
Earth-/KerbinTimeStringConverter

Fixes RemoteTechnologiesGroup#192
  • Loading branch information
Peppie84 committed Oct 5, 2014
1 parent 5514f27 commit 92192ac
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 81 deletions.
85 changes: 23 additions & 62 deletions src/RemoteTech/RTUtil.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)",
Expand All @@ -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}?",
@"(?:(?<seconds>\d*\.?\d+)\s*s[a-z]*[,\s]*)",
@"(?:(?<minutes>\d*\.?\d+)\s*m[a-z]*[,\s]*)",
@"(?:(?<hours>\d*\.?\d+)\s*h[a-z]*[,\s]*)",
@"(?:(?<days>\d*\.?\d+)\s*d[a-z]*[,\s]*)",
@"(?:(?<years>\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)
Expand Down Expand Up @@ -121,33 +90,25 @@ public static float Format180To360(float degrees)
}
}

/// <summary>
///
/// </summary>
/// <param name="duration"></param>
/// <returns></returns>
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);
}

/// <summary>
Expand Down
3 changes: 2 additions & 1 deletion src/RemoteTech/RemoteTech.csproj
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Import Project="$(MSBuildExtensionsPath)\ExtensionPack\$(MSBuildToolsVersion)\MSBuild.ExtensionPack.tasks" />
Expand Down Expand Up @@ -119,6 +119,7 @@
<Compile Include="UI\QueueFragment.cs" />
<Compile Include="UI\SatelliteFragment.cs" />
<Compile Include="UI\TimeWarpDecorator.cs" />
<Compile Include="Utils\TimeStringConverter.cs" />
<Compile Include="VesselSatellite.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
10 changes: 1 addition & 9 deletions src/RemoteTech/UI/AttitudeFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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); }
}

Expand Down
10 changes: 1 addition & 9 deletions src/RemoteTech/UI/QueueFragment.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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(); }
}

Expand Down
169 changes: 169 additions & 0 deletions src/RemoteTech/Utils/TimeStringConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace RemoteTech
{
/// <summary>
/// This class converts time strings like "1d 2m 2s" into a
/// double value as seconds and also vice versa, based on
/// earth time.
/// </summary>
class EarthTimeStringConverter : TimeStringConverter
{
/// <summary>
/// Define the base seconds for days, hours and minutes
/// </summary>
public EarthTimeStringConverter()
{
this.SecondsPerDay = 86400;
this.SecondsPerHour = 3600;
this.SecondsPerMinute = 60;
}
}

/// <summary>
/// This class converts time strings like "1d 2m 2s" into a
/// double value as seconds and also vice versa, based on
/// kerbin time.
/// </summary>
class KerbinTimeStringConverter : TimeStringConverter
{
/// <summary>
/// Define the base seconds for days, hours and minutes
/// </summary>
public KerbinTimeStringConverter()
{
this.SecondsPerDay = 21600;
this.SecondsPerHour = 3600;
this.SecondsPerMinute = 60;
}
}

/// <summary>
/// This class converts time strings like "1d 2m 2s" into a
/// double value as seconds and also vice versa.
/// </summary>
abstract class TimeStringConverter
{
/// <summary>
/// Constant value for the days per year
/// </summary>
public const int DAYS_PER_YEAR = 365;

This comment has been minimized.

Copy link
@Starstrider42

Starstrider42 Oct 5, 2014

This is NOT true, in either Kerbin or Earth days. See http://wiki.kerbalspaceprogram.com/wiki/Kerbin.

This comment has been minimized.

Copy link
@Peppie84

Peppie84 Oct 5, 2014

Author Owner

oh ok so we ever calculated the wrong time, i only copied this part from RTUtil.cs:21

/// <summary>
/// Get the seconds for one year
/// </summary>
protected uint SecondsPerYear { get { return TimeStringConverter.DAYS_PER_YEAR * this.SecondsPerDay; } }
/// <summary>
/// Get the seconds for one day
/// </summary>
protected uint SecondsPerDay;
/// <summary>
/// Get the seconds for one hour
/// </summary>
protected uint SecondsPerHour;
/// <summary>
/// Get the seconds for one minute
/// </summary>
protected uint SecondsPerMinute;
/// <summary>
/// Expression for parsing the time string
/// </summary>
private static readonly Regex DurationRegex = new Regex(
String.Format("{0}?{1}?{2}?{3}?{4}?",
@"(?:(?<seconds>\d*\.?\d+)\s*s[a-z]*[,\s]*)",
@"(?:(?<minutes>\d*\.?\d+)\s*m[a-z]*[,\s]*)",
@"(?:(?<hours>\d*\.?\d+)\s*h[a-z]*[,\s]*)",
@"(?:(?<days>\d*\.?\d+)\s*d[a-z]*[,\s]*)",
@"(?:(?<years>\d*\.?\d+)\s*y[a-z]*[,\s]*)"));

This comment has been minimized.

Copy link
@Starstrider42

Starstrider42 Oct 5, 2014

Does this mean that seconds will be first and years will be last? KSP convention is usually the opposite...

This comment has been minimized.

Copy link
@Peppie84

Peppie84 Oct 5, 2014

Author Owner

No it does not, its only the old code to parse the "text string"


/// <summary>
/// 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.
/// </summary>
/// <param name="duration">time string like "1d 2m 3s". Possible values: 0y 0d 0h 0m 0s</param>
/// <returns>Given time string converted in seconds</returns>
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;
}

/// <summary>
/// This method will parse a time as seconds and returns the time string of this.
/// </summary>
/// <param name="duration">Time as seconds</param>
/// <returns>Given time as seconds converted to a time string like "1d 2m 3s"</returns>
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();
}

/// <summary>
/// This method extracts the time segments
/// </summary>
/// <param name="time">Seconds to convert</param>
/// <param name="appandTo">Stringbuilder to appand to</param>
/// <param name="baseSeconds">Base for the calculation</param>
/// <param name="prefix">Will be appand to the string builder</param>
/// <returns>The remaining seconds</returns>
private Double calcFromSecondsToSring(Double time, StringBuilder appandTo, uint baseSeconds, String prefix)
{
appandTo.Append(Math.Floor(time / baseSeconds));
appandTo.Append(prefix);
return (time % baseSeconds);
}
}
}

3 comments on commit 92192ac

@Starstrider42
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why have a separate Utils/ folder instead of putting it in SimpleTypes/? Or why isn't RTUtils in Utils/? It seems a little inconsistent.

@Peppie84
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this class as a "type" it's only a functional class, that was my reason to put this class into a new folder named "Utils".

@Peppie84
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I changed some things: ecc0b4c

Please sign in to comment.