convert string "172406" to integers 17, 24, 06 fast - c#

I need to convert fast the string in format "HHmmss" to DateTime or integers. I've tested such code:
Console.WriteLine("decoding " + text);
long microseconds = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
Console.WriteLine("start time " + microseconds);
field = DateTime.ParseExact(text, "HHmmss", null);
microseconds = sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L));
Console.WriteLine("finish time " + microseconds);
and the output is
decoding 172400
start time 121
finish time 244
decoding 172400
start time 236
finish time 383
decoding 172400
start time 116
finish time 416
decoding 172400
start time 235
finish time 421
decoding 172359
start time 149
finish time 323
so in average about 150 microseconds. What's a lot of time, i'm writing HFT software and the best HFT has in average 10 microseconds "tick-to-trade" time (this includes everything!). I understand that using c# this is imposible however i still think that 150 microseconds is too much even using c#.
Now I want to use another algorithm, however I don't know how to "extract" integers from the text:
field = new DateTime(DateTime.Now.Year, DateTime.Now.Month, DateTime.Now.Day, /*extract hour, min, sec from text*/)
What can you suggest and what would be the fastest way?
Please do not ask why I'm care about perfomance instead just suggest how to do that faster.
Results:
Using DateTime.ParseExact(text, "HHmmss", null) about 6-8 ticks
Using TimeSpan ts = TimeSpan.ParseExact(text, "hhmmss", null); about 3-4 ticks
Using int hour = 10 * text[0] + text[1] - 11 * '0';... about 0 ticks
Acutally much less than 0 ticks if using loop for measurements. Actually it was found that last version is 100 times faster than other.
Code:
long startMicroseconds = sw.ElapsedTicks /*/ (Stopwatch.Frequency / (1000L * 1000L))*/;
//TimeSpan ts = TimeSpan.ParseExact(text, "hhmmss", null);
//int hour = 10 * text[0] + text[1] - 11 * '0';
//int minute = 10 * text[2] + text[3] - 11 * '0';
//int second = 10 * text[4] + text[5] - 11 * '0';
field = DateTime.ParseExact(text, "HHmmss", null);
long finishMicroseconds = sw.ElapsedTicks /*/ (Stopwatch.Frequency / (1000L * 1000L))*/;
Console.WriteLine("elappsed " + (finishMicroseconds - startMicroseconds));

This approach doesn't use any string substring or parsing methods. It uses only indexing and simple arithmetic:
int hour = (s[0] - '0') * 10 + s[1] - '0';
int minute = (s[2] - '0') * 10 + s[3] - '0';
int second = (s[4] - '0') * 10 + s[5] - '0';
This next version is probably even faster because the calculation has been partially evaulated to help the compiler. As a result it is slightly harder to read and understand:
int hour = s[0] * 10 + s[1] - '0' * 11;
int minute = s[2] * 10 + s[3] - '0' * 11;
int second = s[4] * 10 + s[5] - '0' * 11;
For kicks you might also want to see if this is even faster, though I suspect that this code will be the same as the previous version:
int hour = s[0] * 10 + s[1] - 528;
int minute = s[2] * 10 + s[3] - 528;
int second = s[4] * 10 + s[5] - 528;

If you really want performance instead of readability you can work with raw chars directly:
hour = 10*s[0] + s[1] - 11*'0';
minute = 10*s[2] + s[3] - 11*'0';
second = 10*s[4] + s[5] - 11*'0';
btw. DateTime.Now is quite slow because it needs to convert the current time to the local time-zone. You should use DateTime.UtcNow instead. On my comp DateTime.UtcNow costs 9ns, DateTime.Now costs 900ns.
You also should fetch DateTime.UtcNow only once, else you get a race-condition.

Is this really too slow?
TimeSpan ts = TimeSpan.ParseExact("172406", "hhmmss", null);
int hh = ts.Hours;
int mm = ts.Minutes;
int ss = ts.Seconds;
It is at least easy to understand.

Related

is there any solution to find the time span between two time duration

I have two times like 100:45 and 395:50
I need to find the subtraction and addition between these two times in the asp.net web application
I will expect like this 100:45+395:50=496:35 and 100:45-395:50=295:05
assuming the times are given in a string. then you can split the times to get the equivalent minutes. now it becomes a simple mathematics problem and now perform addition and subtraction accordingly.
string time = "100:45";
string[] parts = time.Split(':');
int hours = int.Parse(parts[0]);
int minutes = int.Parse(parts[1]);
int totalMinutes = hours * 60 + minutes;
so for your case
int mins1 = 100 * 60 + 45;
int mins2 = 395 * 60 + 50;
int totalMinutes = mins1 + mins2;
int totalHours = totalMinutes / 60;
int remainingMinutes = totalMinutes % 60;
string sum = $"{totalHours}:{remainingMinutes}";
use the same concept to get the subtraction as well.
You can convert times to TimeSpan.FromMinutes and to get the desired output using TimeSpan.TotalHours and TimeSpan.Minutes
string s1 = "100:45";
string s2 = "395:50";
TimeSpan spWorkMin = TimeSpan.FromMinutes(int.Parse(s1.Split(':')[0]) * 60 +
int.Parse(s2.Split(':')[0]) * 60 +
int.Parse(s1.Split(':')[1]) +
int.Parse(s2.Split(':')[1]));
var sum =string.Format("{0:00}:{1:00}", (int)tSum.TotalHours, tSum.Minutes);//496:35
TimeSpan tsub = TimeSpan.FromMinutes(int.Parse(s1.Split(':')[0]) * 60 -
int.Parse(s2.Split(':')[0]) * 60 +
int.Parse(s1.Split(':')[1]) -
int.Parse(s2.Split(':')[1]));
var subtract = string.Format("{0:00}:{1:00}", Math.Abs((int)tsub.TotalHours),Math.Abs(tsub.Minutes)); //295:05
TimeSpan do the trick
TimeSpan ts1 = new TimeSpan(0, 100, 45);
TimeSpan ts2 = new TimeSpan(0, 395, 50);
var tsResult = ts1 + ts2;
string outPut = string.Format("{0}:{1}", Math.Floor(tsResult.TotalMinutes), tsResult.Seconds);

Milliseconds to the highest possible time value before reaching 0,xx

I would like to write a converter from milliseconds to the highest possible time value before reaching a 0,x value.
Let me clarify this with examples.
Let's assume you have 1500ms this should result in 1,5secs, because its the highest possible digit value not resulting in 0,x.
So different examples would be
10ms = 10,0ms
100ms = 100,0ms
1000ms = 1,0sec
10000ms = 10,0sec
100000ms = 1,6min
1000000ms = 16,0min
10000000ms = 2,7hours
(The method should more or less be endless, so from hours to days, to weeks, to months, to years, to decades and so on...)
Is there a .net method for this?
Something like the following
public static string ConversionMethod(UInt64 ms)
{
// change output format as needed
string format = "######.###";
var cutoffs = new List<UInt64>() {
1000, // second
60000, // minute
3600000, // hour
86400000, // day
604800000, // week = day * 7
2592000000, // month = day * 30
31536000000, // year = day * 365
315360000000, // decade = year * 10
3153600000000, // century = decade * 10 (100 years)
31536000000000, // millenia = century * 10 (1000 years)
31536000000000000 // megayear = year * 100000
// 18446744073709551615 // UInt64 MaxValue
// 31536000000000000000 // gigayear = year * 100000000
};
var postfix = new List<String>() {
"second",
"minute",
"hour",
"day",
"week",
"month",
"year",
"decade",
"century",
"millenia",
"megayear"
};
// The above are listed from smallest to largest for easy reading,
// but the comparisons need to be made from largest to
// smallest (in the loop below)
cutoffs.Reverse();
postfix.Reverse();
int count = 0;
foreach (var cutoff in cutoffs)
{
if (ms > cutoff)
{
return ((decimal)((decimal)ms / (decimal)cutoff)).ToString(format) + " " + postfix[count];
}
count++;
}
return ms + " ms";
}
Conversion for the fraction is a bit dirty, might want to clean that up. Also, you'll have to decide how you want to handle leap years (and leap seconds), etc.
While not the final solution, maybe TimeSpan can help you achieve what you are looking for.
It is to be noted however, TimeSpan supports only up to TotalDays.
var timespan = TimeSpan.FromMilliseconds(1500);
var seconds = timespan.TotalSeconds; // equals: 1.5
It seems the TimeSpan class is the closest thing that meets your need, but clearly it's not exactly what you want. My take on it would look something like this:
public static string ScientificNotationTimespan(int milliseconds)
{
var timeSpan = new TimeSpan(0, 0, 0, 0, milliseconds);
var totalDays = timeSpan.TotalDays;
if (totalDays < 7)
{
if (timeSpan.TotalDays > 1) return timeSpan.TotalDays.ToString() + " days";
if (timeSpan.TotalHours > 1) return timeSpan.TotalHours.ToString() + " hours";
if (timeSpan.TotalMinutes > 1) return timeSpan.TotalMinutes.ToString() + " minutes";
if (timeSpan.TotalSeconds > 1) return timeSpan.TotalSeconds.ToString() + " seconds";
return milliseconds.ToString() + "milliseconds";
}
var weeks = totalDays / 7;
//How long is a month? 28, 29, 30 or 31 days?
var years = totalDays / 365;
if (years < 1) return weeks.ToString() + " weeks";
var decades = years / 10;
if (decades < 1) return years.ToString() + " years";
var centuries = decades / 10;
if (centuries < 1) return decades.ToString() + " decades";
var millenia = centuries / 10;
if (millenia < 1) return centuries.ToString() + " centuries";
return millenia.ToString() + " millenia";
}
Here is solution for years, months using DateTime and Gregorian calendar (meaning leap years, calendar months). Then it uses the TimeSpan solution as already submitted.
static string ToMostNonZeroTime(long ms) {
const int hundretsNanosecondsInMillisecond = 10000;
long ticks = (long)ms * hundretsNanosecondsInMillisecond;
var dt = new DateTime(ticks);
if((dt.Year - 1) > 0) { // starts with 1
double daysToYear = (dt.DayOfYear - 1) * 1.0 / (DateTime.IsLeapYear(dt.Year) ? 366 : 365);
daysToYear += dt.Year - 1;
return $"{daysToYear:0.0} years";
}
if((dt.Month - 1) > 0) {
double daysToMonth = (dt.Day - 1) * 1.0 / DateTime.DaysInMonth(dt.Year, dt.Month);
daysToMonth += dt.Day - 1;
return $"{daysToMonth:0.0} months";
}
// can use TimeSpan then:
var ts = TimeSpan.FromMilliseconds(ms);
if(ts.TotalDays >= 1)
return $"{ts.TotalDays:0.0} days";
if(ts.TotalHours >= 1)
return $"{ts.TotalHours:0.0} hours";
if(ts.TotalMinutes >= 1)
return $"{ts.TotalMinutes:0.0} minutes";
if(ts.TotalSeconds >= 1)
return $"{ts.TotalSeconds:0.0} seconds";
return $"{ms} milliseconds";
}
It prints
100ms: 100 milliseconds
1000ms: 1.0 seconds
10000ms: 10.0 seconds
100000ms: 1.7 minutes
1000000ms: 16.7 minutes
10000000ms: 2.8 hours
100000000ms: 1.2 days
1000000000ms: 11.6 days
20000000000ms: 19.6 months
200000000000ms: 6.3 years
Have a look at https://ideone.com/QZHOM4

Julian Date to DateTime INCLUDING HOURS AND MINUTE

I'm trying to convert a Julian Date which includes hours minutes and seconds to a DateTime in C#.
This is the number: 2457285.7795969
I can calculate the DateTime excluding the hours and the minutes with this function.
public static DateTime FromJulian(long julianDate)
{
long L = julianDate + 68569;
long N = (long)((4 * L) / 146097);
L = L - ((long)((146097 * N + 3) / 4));
long I = (long)((4000 * (L + 1) / 1461001));
L = L - (long)((1461 * I) / 4) + 31;
long J = (long)((80 * L) / 2447);
int Day = (int)(L - (long)((2447 * J) / 80));
L = (long)(J / 11);
int Month = (int)(J + 2 - 12 * L);
int Year = (int)(100 * (N - 49) + I + L);
return new DateTime(Year, Month, Day);
}
It should be as simple as:
public static DateTime FromJulian(double julianDate)
{
return new DateTime(
(long)((julianDate - 1721425.5) * TimeSpan.TicksPerDay),
DateTimeKind.Utc);
}
As you can see, 1721425.5 is the so-called Gregorian epoch, i.e. the value the Julian date had at the beginning of the proleptic Gregorian calendar, at 0001 January 1, 00:00:00.0000000, where the .NET DateTime has its origin.
EDIT: If you want to make sure your method throws an exception on "extreme" inputs instead of returning an invalid value, do this:
public static DateTime FromJulian(double julianDate)
{
return new DateTime(
checked((long)((julianDate - 1721425.5) * TimeSpan.TicksPerDay)),
DateTimeKind.Utc);
}
Note that we do the multiplication with the double operator *(double, double) overload (built-in in C#). This gives an error as little as possible. The conversion from double to long will throw in checked context if the double is outside the range of long. If that conversion goes well, the DateTime constructor may throw if the value of the long is out of range for a .NET DateTime.
NEW EDIT: Inspired by another thread (Convert DateTime to Julian Date in C# (ToOADate Safe?)) you can also work out a very simple solution using DateTime.FromOADate. However, see another Stack Overflow post by myself on precision short-comings of the FromOADate method.
Is this what you are looking for: Convert Julian Date with Time (H/m/s) to Date Time in C#?
Applying that answer, converting your value of 2457285.7795969 results in 9/19/2015 11:42:37 PM.
Before Ladi answered with what I was looking for....
double L = DateTime.Now.ToOADate() + 2415018.5 + 68569;
double HMS = L-(int)L-0.5;
int Hours = (int)(24*HMS);
HMS=HMS - (double)(Hours/24.0);
int Mins = (int)(24*60*HMS);
HMS=HMS - (double)(Mins/(24.0*60));
int Secs = (int)(24*60*60*HMS);
long N = (long)((4 * L) / 146097);
L = L - ((long)((146097 * N + 3) / 4));
long I = (long)((4000 * (L + 1) / 1461001));
L = L - (long)((1461 * I) / 4) + 31;
long J = (long)((80 * L) / 2447);
int Day = (int)(L - (long)((2447 * J) / 80));
L = (long)(J / 11);
int Month = (int)(J + 2 - 12 * L);
int Year = (int)(100 * (N - 49) + I + L);
DateTime test = new DateTime(Year, Month, Day);
Console.WriteLine("Hours-"+Hours);
Console.WriteLine("Mins-" + Mins);
Console.WriteLine("Secs-"+ Secs);
Console.WriteLine(test);
Console.WriteLine(DateTime.Now.ToString());

Calculating APR

So, as the title says I need to calculate the APR for a loan. I have the following:
apr = (rate * ((Math.Pow((1 + rate), duration))) /
((Math.Pow((1 + rate), duration)) - 1)) -
(installment / (loanamount - extracost));
But its not returning the correct value. I also tried another version of that equation with even worse results:
apr = ((loanamount + extracost) * rate * Math.Pow((1 + rate), duration)) / (Math.Pow((1 + rate),duration) - 1);
The calculations are all wrong. I tried adjusting some parenthesis and checking the order of operations. Any help would be greatly appreciated!
Maybe it sounds like cheating, but I just used the existing VB financial library .NET has. Its for annuities so you have to make the payment a negative number.
Term is full number of payments(i.e. 15 year mortgage has 180 payments so 180)
Payment is payment per (so monthly payment amt... x -1)
Starting Amount = original loan amount with no fees
double apr = Microsoft.VisualBasic.Financial.Rate(term,-payment,originalLoanAmt)
Then just multiply by the answer by the annual # of payments (if monthly then 12) or if you want the % expressed as a number like 3.25%, then multiply by 100 as well.
**note you have to add a reference to Microsoft.VisualBasic assembly.
You're calculating the payment amount given duration as the number of payments. That's not the APR. Here's what I'm seeing:
double apr, loanamount = 3000d, extracost = 7000d, rate = 0.05;
int duration = 1;
apr = ((loanamount + extracost) * rate * Math.Pow((1 + rate), duration)) / (Math.Pow((1 + rate),duration) - 1);
Console.WriteLine(apr);
duration = 2;
apr = ((loanamount + extracost) * rate * Math.Pow((1 + rate), duration)) / (Math.Pow((1 + rate),duration) - 1);
Console.WriteLine(apr);
duration = 3;
apr = ((loanamount + extracost) * rate * Math.Pow((1 + rate), duration)) / (Math.Pow((1 + rate),duration) - 1);
Console.WriteLine(apr);
where the output is
10500
5378.0487804878
3672.08564631245
Only the first answer is the same as what you might expect from A=Pe^(rt) or similar calculations of the amount from the principal.
The actual calculation you need depends on both the legal jurisdiction and the type of credit/loan though.

How to write a method to get a value in seconds and print in Hours, Minutes and Seconds

Ok, so this was my first question on StackOverflow, I see the comments haven't been great (and the post keeps getting deleted before I have had a chance to fix it). Give me a chance! My understanding was the question should be as direct as possible and not create 'discussions'?
This is what I have tried already, but the output is not what I expect
int secondsToHours(seconds) {
int totalSec = seconds;
int hrs = totalSec % 3600;
int secs = totalSec % 60;
int mins = totalSec / 60;
string result = hrs + ":" + mins + ":" + secs;
Console.WriteLine(result);
Console.ReadLine();
}
You can use TimeSpan struct:
TimeSpan ts = TimeSpan.FromSeconds(seconds);
And then build string you want:
ts.ToString(#"hh\:mm\:ss")
Look at the TimeSpan class
TimeSpan span = TimeSpan.FromSeconds(total seconds here);
Then look at the Days, Hours, Minutes and Seconds properties, or the TotalDays, TotalHours etc
Well, you could use a TimeSpan object
int seconds = 104700;
TimeSpan ts = new TimeSpan(0, 0, seconds);
Console.WriteLine("Days:" + ts.Days +
", Hours:" + ts.Hours +
", Minutes:" + ts.Minutes +
", Seconds:" + ts.Seconds );
You need to subtract from totalSec. For 4700 as example;
int left;
int hrs = totalSec / 3600; // hrs will be 1
left = totalSec - hrs * 3600; //left will be 1100
int mins = left / 60; //mins will be 18
left = left - mins * 60; // left will be 20
int secs = left; // secs will be 20
As a solution, 4700 will be 1 hours, 18 minutes and 20 seconds.
But using TimeSpan properties would be better such a case. You can use TimeSpan(Int32, Int32, Int32) constructor like;
TimeSpan ts = new TimeSpan(0, 0, seconds);
int hrs = ts.Hours; // 1
int mins = ts.Minutes; // 18
int secs = ts.Seconds; // 20
Simplest way would be using TimeSpan as already suggested in previous answer but also you could try this if you want to do it using Math:
private static void secondsToHours(int seconds)
{
int hrs = seconds / 3600;
int remainder = seconds % 3600;
int mins = remainder / 60;
int secs = seconds % 60;
string result = hrs + ":" + mins + ":" + secs;
Console.WriteLine(result);
Console.ReadLine();
}

Categories