Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use invariant culture for all numeric conversions #5

Merged
merged 1 commit into from
Jun 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions src/Gemstone.COMTRADE/AnalogChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -153,21 +153,21 @@ public AnalogChannel(string lineImage, int version = 1999, bool targetFloatingPo
if (parts.Length < 10 || !useRelaxedValidation && parts.Length != 10 && parts.Length != 13)
throw new InvalidOperationException($"Unexpected number of line image elements for analog channel definition: {parts.Length} - expected 10 or 13{Environment.NewLine}Image = {lineImage}");

Index = int.Parse(parts[0].Trim());
Index = int.Parse(parts[0].Trim(), CultureInfo.InvariantCulture);
Name = parts[1];
Units = parts[4]; // Assign Units before PhaseID
PhaseID = parts[2];
CircuitComponent = parts[3];
Multiplier = double.Parse(parts[5].Trim());
Adder = double.Parse(parts[6].Trim());
Skew = double.Parse(parts[7].Trim());
MinValue = double.Parse(parts[8].Trim());
MaxValue = double.Parse(parts[9].Trim());
Multiplier = double.Parse(parts[5].Trim(), CultureInfo.InvariantCulture);
Adder = double.Parse(parts[6].Trim(), CultureInfo.InvariantCulture);
Skew = double.Parse(parts[7].Trim(), CultureInfo.InvariantCulture);
MinValue = double.Parse(parts[8].Trim(), CultureInfo.InvariantCulture);
MaxValue = double.Parse(parts[9].Trim(), CultureInfo.InvariantCulture);

if (parts.Length >= 13)
{
PrimaryRatio = double.Parse(parts[10].Trim());
SecondaryRatio = double.Parse(parts[11].Trim());
PrimaryRatio = double.Parse(parts[10].Trim(), CultureInfo.InvariantCulture);
SecondaryRatio = double.Parse(parts[11].Trim(), CultureInfo.InvariantCulture);
ScalingIdentifier = parts[12].Trim()[0];
}
}
Expand Down Expand Up @@ -561,7 +561,7 @@ public override string ToString()
// An,ch_id,ph,ccbm,uu,a,b,skew,min,max
List<string> values = new()
{
Index.ToString(),
Index.ToString(CultureInfo.InvariantCulture),
Name ?? string.Empty,
PhaseID,
CircuitComponent ?? string.Empty,
Expand Down
9 changes: 5 additions & 4 deletions src/Gemstone.COMTRADE/DigitalChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

using System;
using System.Collections.Generic;
using System.Globalization;
using Gemstone.StringExtensions;
#if NETSTANDARD
using Newtonsoft.Json;
Expand Down Expand Up @@ -79,15 +80,15 @@ public DigitalChannel(string lineImage, int version = 1999, bool useRelaxedValid

if (parts.Length >= 5)
{
Index = int.Parse(parts[0].Trim());
Index = int.Parse(parts[0].Trim(), CultureInfo.InvariantCulture);
Name = parts[1];
PhaseID = parts[2];
CircuitComponent = parts[3];
NormalState = parts[4].Trim().ParseBoolean();
}
else
{
Index = int.Parse(parts[0].Trim());
Index = int.Parse(parts[0].Trim(), CultureInfo.InvariantCulture);
Name = parts[1];
NormalState = parts[2].Trim().ParseBoolean();
}
Expand Down Expand Up @@ -203,7 +204,7 @@ public override string ToString()
// Dn,ch_id,ph,ccbm,y
values = new List<string>
{
Index.ToString(),
Index.ToString(CultureInfo.InvariantCulture),
Name ?? string.Empty,
PhaseID ?? string.Empty,
CircuitComponent ?? string.Empty,
Expand All @@ -215,7 +216,7 @@ public override string ToString()
// Dn,ch_id,y
values = new List<string>
{
Index.ToString(),
Index.ToString(CultureInfo.InvariantCulture),
Name ?? string.Empty,
NormalState ? "1" : "0"
};
Expand Down
7 changes: 4 additions & 3 deletions src/Gemstone.COMTRADE/Parser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
//******************************************************************************************************

using System;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
Expand Down Expand Up @@ -402,7 +403,7 @@ private bool ReadNextAscii()
}

// Parse row of data
uint sample = uint.Parse(elems[0]);
uint sample = uint.Parse(elems[0], CultureInfo.InvariantCulture);

// Capture initial sample index - this handles cases where sample index does not start at zero
if (m_initialSample == uint.MaxValue)
Expand All @@ -426,7 +427,7 @@ private bool ReadNextAscii()

// Fall back on specified microsecond time
if (Timestamp == DateTime.MinValue)
Timestamp = new DateTime(Ticks.FromMicroseconds(double.Parse(elems[1]) * m_schema!.TimeFactor) + m_schema.StartTime.Value);
Timestamp = new DateTime(Ticks.FromMicroseconds(double.Parse(elems[1], CultureInfo.InvariantCulture) * m_schema!.TimeFactor) + m_schema.StartTime.Value);

// Apply timestamp offset to restore UTC timezone
if (AdjustToUTC)
Expand All @@ -438,7 +439,7 @@ private bool ReadNextAscii()
// Parse all record values
for (int i = 0; i < Values.Length; i++)
{
Values[i] = double.Parse(elems[i + 2]);
Values[i] = double.Parse(elems[i + 2], CultureInfo.InvariantCulture);

if (i < m_schema!.AnalogChannels?.Length)
Values[i] = AdjustValue(Values[i], i);
Expand Down
14 changes: 11 additions & 3 deletions src/Gemstone.COMTRADE/SampleRate.cs
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public SampleRate(string lineImage, bool useRelaxedValidation = false)
if (parts.Length < 2 || (!useRelaxedValidation && parts.Length != 2))
throw new InvalidOperationException($"Unexpected number of line image elements for sample rate definition: {parts.Length} - expected 2{Environment.NewLine}Image = {lineImage}");

Rate = double.Parse(parts[0].Trim());
EndSample = long.Parse(parts[1].Trim());
Rate = double.Parse(parts[0].Trim(), CultureInfo.InvariantCulture);
EndSample = long.Parse(parts[1].Trim(), CultureInfo.InvariantCulture);
}

#endregion
Expand All @@ -76,7 +76,15 @@ public SampleRate(string lineImage, bool useRelaxedValidation = false)
/// Converts <see cref="SampleRate"/> to its string format.
/// </summary>
public override string ToString() => // samp,endsamp
$"{Rate.ToString(CultureInfo.InvariantCulture)},{EndSample}";
Format($"{Rate},{EndSample}");

#endregion

#region [ Static ]

// Static Methods
private static string Format(FormattableString formattableString) =>
formattableString.ToString(CultureInfo.InvariantCulture);

#endregion
}
Expand Down
40 changes: 20 additions & 20 deletions src/Gemstone.COMTRADE/Schema.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ public Schema(string fileName, bool useRelaxedValidation)
DeviceID = parts[1].Trim();

if (parts.Length >= 3 && !string.IsNullOrWhiteSpace(parts[2]))
Version = int.Parse(parts[2].Trim());
Version = int.Parse(parts[2].Trim(), CultureInfo.InvariantCulture);
else
Version = 1991;

Expand All @@ -258,9 +258,9 @@ public Schema(string fileName, bool useRelaxedValidation)
if (parts.Length < 3 || (!useRelaxedValidation && parts.Length != 3))
throw new InvalidOperationException($"Unexpected number of line image elements for second configuration file line: {parts.Length} - expected 3{Environment.NewLine}Image = {lines[lineNumber - 1]}");

int totalChannels = int.Parse(parts[0].Trim());
int totalAnalogChannels = int.Parse(parts[1].Trim().Split('A')[0]);
int totalDigitalChannels = int.Parse(parts[2].Trim().Split('D')[0]);
int totalChannels = int.Parse(parts[0].Trim(), CultureInfo.InvariantCulture);
int totalAnalogChannels = int.Parse(parts[1].Trim().Split('A')[0], CultureInfo.InvariantCulture);
int totalDigitalChannels = int.Parse(parts[2].Trim().Split('D')[0], CultureInfo.InvariantCulture);

if (totalChannels != totalAnalogChannels + totalDigitalChannels)
throw new InvalidOperationException($"Total defined channels must equal the sum of the total number of analog and digital channel definitions.{Environment.NewLine}Image = {lines[lineNumber - 1]}");
Expand All @@ -280,10 +280,10 @@ public Schema(string fileName, bool useRelaxedValidation)
DigitalChannels = digitalChannels.ToArray();

// Parse line frequency
NominalFrequency = double.Parse(lines[lineNumber++]);
NominalFrequency = double.Parse(lines[lineNumber++], CultureInfo.InvariantCulture);

// Parse total number of sample rates
int totalSampleRates = int.Parse(lines[lineNumber++]);
int totalSampleRates = int.Parse(lines[lineNumber++], CultureInfo.InvariantCulture);

if (totalSampleRates == 0)
totalSampleRates = 1;
Expand All @@ -310,7 +310,7 @@ public Schema(string fileName, bool useRelaxedValidation)
AnalogChannels = analogLineImages.Select(lineImage => new AnalogChannel(lineImage, Version, targetFloatingPoint, useRelaxedValidation)).ToArray();

// Parse time factor
TimeFactor = lineNumber < lines.Length ? double.Parse(lines[lineNumber++]) : 1;
TimeFactor = lineNumber < lines.Length ? double.Parse(lines[lineNumber++], CultureInfo.InvariantCulture) : 1;

// Parse time information line
if (lineNumber < lines.Length)
Expand Down Expand Up @@ -339,10 +339,10 @@ public Schema(string fileName, bool useRelaxedValidation)
parts = lines[lineNumber/*++*/].Split(',');

if (parts.Length > 0)
TimeQualityIndicatorCode = (TimeQualityIndicatorCode)byte.Parse(parts[0], NumberStyles.HexNumber);
TimeQualityIndicatorCode = (TimeQualityIndicatorCode)byte.Parse(parts[0], NumberStyles.HexNumber, CultureInfo.InvariantCulture);

if (parts.Length > 1)
LeapSecondIndicator = (LeapSecondIndicator)byte.Parse(parts[1]);
LeapSecondIndicator = (LeapSecondIndicator)byte.Parse(parts[1], CultureInfo.InvariantCulture);
}
}

Expand Down Expand Up @@ -523,11 +523,11 @@ public string FileImage
{
StringBuilder fileImage = new();

void appendLine(string line)
void appendLine(FormattableString line)
{
// The standard .NET "Environment.NewLine" constant can just be a line feed on some operating systems,
// but the COMTRADE standard requires that end of line markers be both a carriage return and line feed.
fileImage.Append(line);
fileImage.Append(line.ToString(CultureInfo.InvariantCulture));
fileImage.Append(Writer.CRLF);
}

Expand All @@ -539,17 +539,17 @@ void appendLine(string line)

// Write analog definitions
for (int i = 0; i < TotalAnalogChannels; i++)
appendLine(AnalogChannels![i].ToString());
appendLine($"{AnalogChannels![i]}");

// Write digital definitions
for (int i = 0; i < TotalDigitalChannels; i++)
appendLine(DigitalChannels![i].ToString());
appendLine($"{DigitalChannels![i]}");

// Write line frequency
appendLine(NominalFrequency.ToString(CultureInfo.InvariantCulture));
appendLine($"{NominalFrequency}");

// Write total number of sample rates (zero signifies no fixed sample rates)
appendLine(TotalSampleRates.ToString());
appendLine($"{TotalSampleRates}");

int totalSampleRates = TotalSampleRates;

Expand All @@ -558,18 +558,18 @@ void appendLine(string line)

// Write sample rates
for (int i = 0; i < totalSampleRates; i++)
appendLine(SampleRates![i].ToString());
appendLine($"{SampleRates![i]}");

// Write timestamps
appendLine(StartTime.ToString());
appendLine(TriggerTime.ToString());
appendLine($"{StartTime}");
appendLine($"{TriggerTime}");

// Write file type
appendLine(FileType.ToString().ToUpper());
appendLine($"{FileType.ToString().ToUpper()}");

// Write time factor
if (Version >= 1999)
appendLine(TimeFactor.ToString(CultureInfo.InvariantCulture));
appendLine($"{TimeFactor}");

// Write per data set time info and state
if (Version >= 2013)
Expand Down
18 changes: 14 additions & 4 deletions src/Gemstone.COMTRADE/TimeOffset.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@


using System;
using System.Globalization;

#if NETSTANDARD
using Newtonsoft.Json;
#else
Expand Down Expand Up @@ -76,14 +78,14 @@ public TimeOffset(string lineImage)
switch (parts.Length)
{
case 1:
validFormat = int.TryParse(lineImage, out hours);
validFormat = int.TryParse(lineImage, NumberStyles.Integer, CultureInfo.InvariantCulture, out hours);
break;
case 2:
{
validFormat = int.TryParse(parts[0], out hours);
validFormat = int.TryParse(parts[0], NumberStyles.Integer, CultureInfo.InvariantCulture, out hours);

if (validFormat)
validFormat = int.TryParse(parts[1], out minutes);
validFormat = int.TryParse(parts[1], NumberStyles.Integer, CultureInfo.InvariantCulture, out minutes);
break;
}
default:
Expand Down Expand Up @@ -167,7 +169,15 @@ public long TickOffset
/// Converts <see cref="TimeOffset"/> to its string format.
/// </summary>
public override string ToString() =>
NotApplicable ? "x" : $"{Hours}h{Minutes:00}";
NotApplicable ? "x" : Format($"{Hours}h{Minutes:00}");

#endregion

#region [ Static ]

// Static Methods
private static string Format(FormattableString formattableString) =>
formattableString.ToString(CultureInfo.InvariantCulture);

#endregion
}
Expand Down
15 changes: 13 additions & 2 deletions src/Gemstone.COMTRADE/Timestamp.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ public Timestamp(string lineImage)

if (parts.Length == 4)
{
double.TryParse(parts[^1], out milliseconds);
TryParse(parts[^1], out milliseconds);
parts = new[] { parts[0], parts[1], parts[2] };
}

double.TryParse(parts[^1], out double seconds);
TryParse(parts[^1], out double seconds);

seconds += milliseconds;

Expand Down Expand Up @@ -97,5 +97,16 @@ public override string ToString() =>
Value.ToString("dd/MM/yyyy,HH:mm:ss.ffffff", CultureInfo.InvariantCulture);

#endregion

#region [ Static ]

// Static Methods
private static bool TryParse(string s, out double result)
{
NumberStyles style = NumberStyles.Float | NumberStyles.AllowThousands;
return double.TryParse(s, style, CultureInfo.InvariantCulture, out result);
}

#endregion
}
}
Loading
Loading