Trochę się zakręciłem w problemie i potrzebuje czyjegoś spojrzenia z zewnątrz, będę wdzięczny za podpowiedzi.
Opis Problemu:
Pobieram z pliku tekstowego wartość czasu wyrażonego dziesiętnie np. '0,25', '7,67', '0,33333', '0,044'. Taka postać tekstowa tej wartości czasu, ma różną liczbę cyfr po przecinku, może mieć dokładność od 0 do 5 miejsc po przecinku, w zależności od tego co to za czas przygotowania/realizacji/nakładania/itp.
Ale jest tak że np. czas realizacji w całym systemie może być reprezentowany przez 'double' z dokładnością do 5ciu miejsc po przecinku a w niektórych przypadkach w pliku tekstowym z którego importuje dane, ma dokładność 2 miejsc po przecinku, i to jest ok, czasami tak bywa np. 15min to '0,25'. (Nie mam wpływu na plik tekstowy i nie uzyskam tam wartości '0,25000' dla 15minut.)
Następnie konwertuję taki czas na 'double' w obiekcie który czyta ten plik i w tym obiekcie buduję swój obiekt 'CzasScala' do którego konstruktora podaje już 'double' a nie 'string' (potrzebuje takiego obiektu do obliczeń, edycji i wyswietlania tego czasu w różnych formatach w programie).
public class CzasScala : IComparable<CzasScala>
{
public int Dokladnosc_CzasDec_PoPrzecinku { get; private set; }
public CzasScala(double d, int dokladnoscPoPrzecinku)
{
Dokladnosc_CzasDec_PoPrzecinku = dokladnoscPoPrzecinku;
UstawNaPodstawieDziesietnej(d);
}
public double GodzinDziesietnie
{
get { return _godzinDziesietnie; }
set { UstawNaPodstawieDziesietnej(value); }
}
private double _godzinDziesietnie;
public int SumaSekund
{
get { return _sumaSekund; }
set { UstawNaPodstawieSumySekund(value); }
}
private int _sumaSekund;
public TimeSpan CzasStandard
{
get { return _czasStandard; }
set { UstawNaPodstawieDateTime(value); }
}
private TimeSpan _czasStandard;
private void UstawNaPodstawieDziesietnej(double d)
{
_sumaSekund = WyliczSekundy(d);
WyliczSkladoweZSumySekund(_sumaSekund);
}
private int WyliczSekundy(double d)
{
return (int)(d * 3600d);
}
private void WyliczSkladoweZSumySekund(int s)
{
_czasH = (_sumaSekund / 3600);
_czasM = (_sumaSekund % 3600 / 60);
_czasS = (_sumaSekund % 3600 % 60);
_godzinDziesietnie = Math.Round((double)s / 3600d, Dokladnosc_CzasDec_PoPrzecinku);
_czasStandard = new TimeSpan(_czasH, _czasM, _czasS);
}
//pozostala czesc klasy
I teraz problem, jeżeli opakuje taki czas realizacji '0,044' w 'CzasScala' i przeprowadzę na nim jakieś obliczenia lub edycje do postaci np. '0,3784' to dalej w programie wyeksportuje go do pliku tekstowego w takiej właśnie formie '0,3784' i to jest ok, tak ma być. Ale jeżeli pobiorę czas realizacji w formie '0,044' i nic z nim nie zrobię w programie to chciałbym go wyeksportować w postaci identycznej jak pobrałem czyli '0,044' a teraz wg tego co robi mój program, nie ruszony czas zapisuje mi w formie '0,04389' a tak nie chce.
Wiem ze problem leży w metodzie 'WyliczSkladoweZSumySekund' i doszedłem w 'Consoli' jak uzyskać to co chce, po prostu ustawiając właściwość w klasie musze ją ustawiać z dokładnością taką z jaką przychodzi z tekstu, ale jedyny sposób jaki wymyśliłem żeby pobierać dokładność po przecinku wartości która przychodzi to Split(',') i pobranie długości ostatniego stringa z uzyskanej tablicy stringów - ale to mi się wydaje za grubo. Jest jakiś inny rozsądny sposób aby uzyskać efekt o jaki mi chodzi? Może cos zamiast 'Math.Round'
static void Main(string[] args)
{
//odczytana, docelowaDokladnoscPoPrzecinku, sumaSekund, Gdzin, Minut,Sekund, CultureInfo
//[DataRow(15.35 , 2, 55260, 15, 21, 0, "en-US")]
//[DataRow(0.044 , 4, 158 , 0, 2, 38, "en-US")]
//[DataRow(0.064 , 2, 230 , 0, 3, 50, "en-US")]
//[DataRow(0.0645 , 2, 232 , 0, 3, 52, "en-US")]
CultureInfo.CurrentCulture = new CultureInfo("en-US", false);
double d = 0.044;
int sekund = 158;
int dokladnoscDocelowa = 5;
double sekundDouble = (double)sekund;
double tymczasowa = Math.Round(sekundDouble / 3600d, 3); //tu na sztywno podaje dokladnosc 3 miejsc po przecinku (bo 0.044)
double _godzinDziesietnie = Math.Round(tymczasowa, dokladnosc);
Console.WriteLine($"Przypadek dla {d}");
Console.WriteLine();
Console.WriteLine($"Sekund = '{sekund}'\t\n" +
$"dokladnosc: '{dokladnosc}' miejsc po przecinku, \t\n" +
$"wartość uzyskana Double = '{_godzinDziesietnie}'");
Console.ReadLine();
}
Problem uwidocznił się w programie i dlatego żeby zacząć go rozwiązywać zacząłem tworzyć testy jednostkowe.
// doubleH_IN, poPrzecinkuIN, SUMAsekundOUT, godzinOUT, minutOUT , sekundOUT, culture
[DataTestMethod]
[DataRow(3.5, 2, 12600, 3, 30, 0, "en-US")]
[DataRow(0.25, 2, 900, 0, 15, 0, "en-US")]
[DataRow(0.17, 4, 612, 0, 10, 12, "en-US")]
[DataRow(15.35, 2, 55260, 15, 21, 0, "en-US")]
[DataRow(0.044, 5, 158, 0, 2, 38, "en-US")]
[DataRow(0.064, 2, 230, 0, 3, 50, "en-US")]
[DataRow(0.0645, 2, 232, 0, 3, 52, "en-US")]
[DataRow(0.33333, 5, 1200, 0, 20, 0, "en-US")]
[DataRow(0.66666, 2, 2400, 0, 40, 0, "en-US")]
[DataRow(0.66, 1, 2376, 0, 39, 36, "en-US")]
[DataRow(0.67, 1, 2412, 0, 40, 12, "en-US")]
[DataRow(0.00001, 0, 0, 0, 0, 0, "en-US")]
public void TestKonstruktora_DoubleInt_CultureEN_TestUstawianiaWszsytkichPol(double d, int i,
int sumaSekundResult, int godzinResult, int minutResult, int sekundResult, string cultureInfo)
{
CultureInfo.CurrentCulture = new CultureInfo(cultureInfo, false);
CzasScala czas = new CzasScala(d, i);
TimeSpan tsResult = new TimeSpan(godzinResult, minutResult, sekundResult);
Assert.AreEqual(sumaSekundResult, czas.SumaSekund, $"blad w 'SumaSekund' spodziewalem sie {sumaSekundResult} a otrzymalem {czas.SumaSekund}");
Assert.AreEqual(d, czas.GodzinDziesietnie, $"blad w 'GodzinaDziesietnie' spodziewalem sie {d} a otrzymalem {czas.GodzinDziesietnie}");
Assert.AreEqual(tsResult, czas.CzasStandard, $"blad w 'TimeSpan', spodziewalem sie {tsResult} a otrzymalem {czas.CzasStandard}");
}
Ale jeżeli pobiorę czas realizacji w formie '0,044' i nic z nim nie zrobię w programie to chciałbym go wyeksportować w postaci identycznej jak pobrałem czyli '0,044' a teraz wg tego co robi mój program, nie ruszony czas zapisuje mi w formie '0,04389' a tak nie chce.
- Twoja klasa do ułamków odczyta0,044
jako44/1000
i zapisze44/1000
skonwertowane do ułamka dziesiętnego. Nie tracisz precyzji, więc osiągasz zamierzony efekt.