Converting String to time and back again - c#

I am converting a fractional hour value in this format '00.000' to a hour and minute format. So that '02.500' will be '02:30' and I also have to do this in reverse.
I built a test to see how this will work,
<%
TimeSpan tspan;
TimeSpan tspan2;
string TimeString;
string TimeString2;
string Converted;
double ConvTime;
for (int HH = 0; HH < 24; HH++)
{
for (int M1 = 0; M1 < 6; M1++)
{
for (int M2 = 0; M2 < 10; M2++)
{
TimeString = HH.ToString() + ":" + M1.ToString() + M2.ToString();
// Convert Time String to Fractional Hours
tspan = TimeSpan.Parse(TimeString);
ConvTime = Convert.ToDouble(tspan.TotalHours);
Converted = String.Format("{0:00.000}", ConvTime);
// Convert Fractional Hour String to Time String
tspan2 = TimeSpan.FromHours(Convert.ToDouble(Converted));
TimeString2 = string.Format("{0:D1}:{1:D2}", tspan2.Hours, tspan2.Minutes);
Response.Write(TimeString + " = ");
Response.Write(Converted + " = ");
Response.Write(TimeString2 + "<br>");
}
}
}
%>
The problem I am having is that when I convert to a string I loose the remainder form the converstion, which throws off the value when converting back.
Here is the output for the first 10 seconds.
0:00 = 00.000 = 0:00
0:01 = 00.017 = 0:01
0:02 = 00.033 = 0:01
0:03 = 00.050 = 0:03
0:04 = 00.067 = 0:04
0:05 = 00.083 = 0:04
0:06 = 00.100 = 0:06
0:07 = 00.117 = 0:07
0:08 = 00.133 = 0:07
0:09 = 00.150 = 0:09
0:10 = 00.167 = 0:10
as you can see what I started with is not always what I end up with.
How can I correctly convert a time value string "HH:MM" to a fractional string "00.000" and back again correctly.
Thanks
EDIT:
I tried this,
TimeString = "02:02";
Converted = TimeSpan.Parse(TimeString).TotalHours.ToString("00.000");
tspan2 = TimeSpan.FromHours(Convert.ToDouble(Converted));
TimeString2 = string.Format("{0:D1}:{1:D2}", tspan2.Hours, tspan2.Minutes);
But I get Converted = "02.033" and TimeString2 = "2:01". It should equal "2:02". I'm thinking that I'm loosing the remainder when I force it to "00.000".

To convert a string to a hours, use this:
string time = "1:30";
double hours = TimeSpan.Parse(time).TotalHours; // -> 1.5
For the reverse, you can use this:
double hours = 1.5;
string time = TimeSpan.FromHours(hours).ToString(); // -> "00:01:30"

Why don't you just use DateTime.Parse?

//Parse both strings to TimeSpan
var ts = TimeSpan.FromHours(Double.Parse("02.500"));
var ts2 = TimeSpan.Parse("02:30");
//Convert a TimeSpan to string format
var firstFormat = ts.Hours.ToString.PadLeft(2, '0')
+ ":" + ts.Minutes.ToString.PadLeft(2, '0');
//Result: 02:30
var secondFormat = ts.TotalHours.ToString("00.000");
//Result: 02.500

Related

Time where minutes are not counted in a C# assertion snippet for an appium test

I am attempting to ensure that hours are not off minutes I am not too concerned with but can't seem to break them off the code. Is there a way to allow the assertion to be 10 minutes off?
public void DeviceTimeAssertion()
{
IWebElement TimeTitle = _driver.FindElementByXPath("
(//android.widget.TextView[#content-desc='xpathvalue'])[1]");
string Time = DateTime.Now.ToString("MM/dd/yy h:mm tt");
//string Time = DateTime.Now.ToString("MM/dd/yy h:mm");
string ActText = TimeTitle.Text;
string ExpectedTime = "Check-in: " + Time;
//if (ExpText.Equals(ActText))
Assert.AreEqual(ExpectedTime, ActText);
I think you need to do that with actual DateTime objects. You can try to do that:
var time = DateTime.Now;
var actText = TimeTitle.Text;
var isTime = DateTime.TryParse(actText.Split(' ')[1], out var actTime)
if(isTime)
{
var diff = TimeSpan.FromMinutes(10);
Assert.IsTrue(time + diff > actTime && time - diff < actTime);
}
else
{
throw new ArgumentException("There was no Time in the text :(");
}
Hope that helps

How to sort a List<String> in descending order as fast as possible

I am trying to find a way to sort a List as fast as possible. I know about "bucket sort" which I will use(I think?). But before doing that. I think I am looking for the fastest possible clean algorithm first, - and then use that in bucket sort?
The strings looks like below where I add 100.000 elements in a loop:
-0,awb/aje - ddfas/asa - asoo/qwa
-1,awb/aje - ddfas/asa - asoo/qwa
-2,awb/aje - ddfas/asa - asoo/qwa
So I want to sort in a descending order for the first comma delimited argument which is a double like: -0, -1, -2 etc..
I have tried 3 Approaches where only the Approach 1 actually sorts correctly. Approach 2 and 3 do not sort entirely correctly in a descending order numeric wise.
So the approach 1 which sorts correctly do this in 30 seconds.
The thing is that I will have about 3 Million elements and not only 100.000 like in this example which then should take at least 900 seconds or more.
My question is how can we sort 100.000 or more correctly 3 million elements as fast as possible?
Running: sortingtestBENCHMARKS() will show the results
public void sortingtestBENCHMARKS()
{
List<String> dataLIST = new List<String>(); List<String> sortedLIST = new List<String>(); String resultString = ""; int index = 0;
DateTime starttime = DateTime.Now; DateTime endtime = DateTime.Now; TimeSpan span = new TimeSpan();
for (double i = 0; i < 100000; i+=1)
{
dataLIST.Add("-" + i + "," + "awb/aje" + " - " + "ddfas/asa" + " - " + "asoo/qwa");
}
dataLIST = shuffle(dataLIST);
/*--------------------------------------------------------------------------*/
//APPROACH 1: 30 seconds (Sorts correctly in descending order)
starttime = DateTime.Now;
dataLIST = sortLIST(dataLIST);
endtime = DateTime.Now;
span = endtime - starttime;
resultString = "Approach 1: " + span.TotalSeconds;
dataLIST = shuffle(dataLIST);
/*--------------------------------------------------------------------------*/
//APPROACH 2: 55 seconds (Sorts INcorrectly in descending order)
starttime = DateTime.Now;
for (int i = 0; i < dataLIST.Count; i++)
{
index = sortedLIST.BinarySearch(dataLIST[i]);
if (index < 0)
{
sortedLIST.Insert(~index, dataLIST[i]);
}
}
endtime = DateTime.Now;
span = endtime - starttime;
resultString = resultString + "\nApproach 2: " + span.TotalSeconds;
/*--------------------------------------------------------------------------*/
//APPROACH 3: 2 seconds (Sorts INcorrectly in descending order)
starttime = DateTime.Now;
dataLIST.Sort(); //1.6 seconds
endtime = DateTime.Now;
span = endtime - starttime;
resultString = resultString + "\nApproach 3: " + span.TotalSeconds;
/*--------------------------------------------------------------------------*/
MessageBox.Show("Elapsed Times:\n\n" + resultString);
}
List<String> sortLIST(List<String> theLIST)
{
System.Threading.Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo("en-US");
theLIST.Sort(new Comparison<String>((a, b) =>
{
int result = 0;
double ad = 0;
double bd = 0;
NumberFormatInfo provider = new NumberFormatInfo();
provider.NumberGroupSeparator = ",";
provider.NumberDecimalSeparator = ".";
provider.NumberGroupSizes = new int[] { 5 };
ad = Convert.ToDouble(a.Replace("a", "").Replace("c", "").Split(',')[0], provider);
bd = Convert.ToDouble(b.Replace("a", "").Replace("c", "").Split(',')[0], provider);
if (ad < bd)
{
result = 1;
}
else if (ad > bd)
{
result = -1;
}
return result;
}));
return theLIST;
}
List<String> shuffle(List<String> list)
{
var randomizedList = new List<String>();
var rnd = new Random();
while (list.Count != 0)
{
var index = rnd.Next(0, list.Count);
randomizedList.Add(list[index]);
list.RemoveAt(index);
}
return randomizedList;
}
It seems to me that you can just split your string on the , character, strip the - off the first item in the split array, and then use OrderBy on that result:
var sorted = dataLIST.OrderBy(i => double.Parse(i.Split(',')[0].TrimStart('-'))).ToList();
I made a copy of your code and then used the one working method you have and compared it to running an OrderBy on the split string method mentioned above. The OrderBy/Split method is a little more than 30 times faster.
public static void sortingtestBENCHMARKS()
{
var dataLIST = new List<string>();
// Create the list
for (var i = 0; i < 100000; i ++)
{
dataLIST.Add("-" + i + "," + "awb/aje" + " - " + "ddfas/asa" + " - " + "asoo/qwa");
}
// Shuffle the list
dataLIST = shuffle(dataLIST);
// Make two copies of the same shuffled list
var copy1 = dataLIST.ToList();
var copy2 = dataLIST.ToList();
// Use a stopwatch for measuring time when benchmark testing
var stopwatch = new Stopwatch();
/*--------------------------------------------------------------------------*/
//APPROACH 1: 2.83 seconds (Sorts correctly in descending order)
stopwatch.Start();
copy2 = sortLIST(copy2);
stopwatch.Stop();
Console.WriteLine($"sortLIST method: {stopwatch.Elapsed.TotalSeconds} seconds");
/*--------------------------------------------------------------------------*/
//APPROACH 2: 0.09 seconds (Sorts correctly in descending order)
stopwatch.Restart();
copy1 = copy1.OrderBy(i => double.Parse(i.Split(',')[0].TrimStart('-'))).ToList();
stopwatch.Stop();
Console.WriteLine($"OrderBy method: {stopwatch.Elapsed.TotalSeconds} seconds");
// Ensure that the lists are sorted identically
Console.WriteLine($"Lists are the same: {copy1.SequenceEqual(copy2)}");
}
Output
var sortedList = theLIST.OrderByDescending(s=>s);
You should optimize the inner loop as hard as you can, because most of the processing time is spent there. I suggest implementing the string tokenizer yourself, since you only need the first token and the string is very uniform. The second optimization you might have is multiply all the number with -1 so sorting the list in reverse order is straightforward. Something like this:
private static double getNumberFromString(String s){
int posFirstComma=0;
for (; posFirstComma<s.length() && s.charAt(posFirstComma)!=','; posFirstComma++);
return Convert.toDouble(s.subString(0, posFirstComma)*(-1);
}
myData.sort(new Comparision<String>((a,b)=> getNumberFromString(a)-getNumberFromString(b));
I personally won't touch the sort algorithm in the library itself because it is already thoroughly optimized. Just optimize everything in the for loop.

calculate difference between two dates using c#

I'm trying to calculate difference between two dates, my code is given below
DateTime daterenew = DateTime.Parse(drow.ItemArray.GetValue(16).ToString()); //18/01/2017
DateTime datecurrent = DateTime.Parse(DateTime.Now.ToString("dd/MM/yyyy"));
renewstatuslbl.Text = ((daterenew - datecurrent).Days) + " Day(s) remains";
But I'm getting an error
"String was not recognized as a valid DateTime."
I would simplify that:
var daterenew = DateTime.ParseExact("18/01/2017", "dd/MM/yyyy", CultureInfo.InvariantCulture);
var res = ((daterenew - DateTime.Today).Days) + " Day(s) remains";
Note, that DateTime.Now != DateTime.Today.
Try something like this
string dateString = drow.ItemArray.GetValue(16).ToString();
DateTime daterenew = DateTime.ParseExact(dateString, "dd/MM/yyyy", CultureInfo.InvariantCulture);
renewstatuslbl.Text = string.Format("{0} Day(s) remains", (daterenew - DateTime.Now).TotalDays);
Idea is in ParseExact where you can set up format for your date in drow.ItemArray
Also look at TotalDays
Assuming your drow.ItemArray.GetValue(16).ToString()format is always dd/MM/yyyy. Use ParseExact
DateTime daterenew = DateTime.ParseExact(drow.ItemArray.GetValue(16).ToString(), "dd/MM/yyyy", null); //18/01/2017
//DateTime datecurrent = DateTime.Parse(DateTime.Now.ToString("dd/MM/yyyy"));
DateTime datecurrent = DateTime.Now;
renewstatuslbl.Text = ((daterenew - datecurrent).Days) + " Day(s) remains";
The format of the date , causes the error. 18/01/2017
https://msdn.microsoft.com/en-us/library/az4se3k1(v=vs.110).aspx
example I used "yyyy/MM/dd"
//DateTime daterenew = DateTime.Parse("18/01/2017"); //18/01/2017
DateTime daterenew = DateTime.Parse("2017.01.18"); //18/01/2017
DateTime datecurrent = DateTime.Parse(DateTime.Now.ToString("dd/MM/yyyy"));
object renewstatuslbl = ((daterenew - datecurrent).Days) + " Day(s) remains";
thus, I think you can change the string date format first of the value before inserting to drow.ItemArray
enter codenamespace FineCalculation
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
DateTime date01 = date1.Value;
DateTime date02 = date2.Value;
TimeSpan timeSpan = date02 - date01;
int days = Convert.ToInt16(timeSpan.TotalDays);
double fine = 0;
if(days < 30)
{
fine = days * 0.5;
}else if(days > 30 && days < 60)
{
fine = days * 0.5 * 0.75;
}else if(days > 60)
{
fine = days * 0.5 * 0.75 * 1;
}
MessageBox.Show("For "+ days + " days fine is " + fine.ToString());
}
}
} here

double.ToString() return wrong value in C#

I have double variable and its value is :
double d = 0.000000000000056843418860808015;
when i print this variable its print wrong.
d.ToString();
Output : "5.6843418860808E-14"
How to resolve this?
Well if you want to have an output without the exponential notation you need to format your string:
d.toString("F25");
This will give you the "correct" number with up to 25 fractional digits.
0,0000000000000568434188608
Edit: Complete list of formats and conversions are available here and snapshot for you is below.
Original value: 1054.32179
F: 1054.32
F0: 1054
F1: 1054.3
F2: 1054.32
F3: 1054.322
double d = 0.000000000000056843418860808015;
var str = d.ToString("G17");
var value = str.Split('E')[0];
var zeros = Int32.Parse(str.Split('E')[1]);
var outputString = "";
zeros = Math.Abs(zeros);
var addstring = "0.";
for (var i = 0; i < zeros - 1; i++)
{
addstring += '0';
}
value = value.Remove(1, 1);
value = addstring + value;

How can I subtract datetimes to give the results in the format I require?

I'm trying to subtract between two dateTimes in a way that I'll see all totaled hours.(including mm and ss if theres any)
for Example:
TimeSpan j = DateTime.Parse("06/05/2015 12:00:00").Subtract(DateTime.Parse("04/05/2015 14:00:00"));
I want to return a string that contains "46:00:00"
TimeSpan j = DateTime.Parse("06/05/2015 12:00:00").Subtract(DateTime.Parse("05/05/2015 12:00:00"));
I want to return a string that contains "24:00:00"
TimeSpan j = DateTime.Parse("06/05/2015 12:00:00").Subtract(DateTime.Parse("05/05/2015 18:00:00"));
I want to return a string that contains "18:00:00"
You can use TimeSpan.TotalHours and String.Format:
string result = string.Format("{0:D2}:{1:D2}:{2:D2}", (int)j.TotalHours, j.Minutes, j.Seconds);
The cast to int is needed to remove the fractional part from the TotalHours.
The D2 ensures that you always get two digits like 00 even if the minute part is 0.
MSDN: The "D" (or decimal) format specifier
Try Something like this,
I have done only for your first condition
DateTime d1 = Convert.ToDateTime( "06/05/2015 12:00:00");
DateTime d2 = Convert.ToDateTime( "04/05/2015 14:00:00");
TimeSpan j = d1 - d2;
string ti = (j.TotalHours + " : " + j.TotalMinutes + " : " + j.TotalSeconds).ToString();
i have done something like:
TimeSpan j = DateTime.Parse("06/05/2015 12:00:00").Subtract(DateTime.Parse("04/05/2015 14:00:00"));
int i = 0;
if(j.Days >= 1)
{
i = j.Days * 24;
i = i + j.Hours;
}
string s = String.Concat(i.ToString(), ":", j.Minutes.ToString(), ":", j.Seconds.ToString());

Categories

Resources