How to get exact hours and minutes from DbFunctions.DiffMinutes() - c#

I am using this linq query,it works fine. only problem is it is returning hours in int i.e 10,9 etc but I want complete hours along with minutes i.e 10:28,9:45 etc
DayHours = (from ab in db.Attendances
where ab.Employee == 63
&& ab.InTime.Value.Year == 2015
&& ab.InTime.Value.Month == i
select new
{
Day = ab.InTime.Value.Day,
Hours = DbFunctions.DiffMinutes(ab.InTime, ab.OutTime) / 60
});

You can try this:
/*...*/
select new
{
Day = ab.InTime.Value.Day,
Hours = DbFunctions.DiffMinutes(ab.InTime, ab.OutTime) / 60
Minutes = DbFunctions.DiffMinutes(ab.InTime, ab.OutTime) % 60
});
If you don't want it on this format, please specify exactly how do you want to store it (a Timespan variable? something else?)

You Can get Exact Time from DB as
select round(
Cast(
DateDiff(
MINUTE,
convert(varchar(5), '09:40:00.0000000', 108),
convert(varchar(5), '18:12:00.0000000', 108)
) / 60 as float
)
+ Cast(
DateDiff(
MINUTE,
convert(varchar(5), '09:40:00.0000000', 108),
convert(varchar(5), '18:12:00.0000000', 108)
) % 60 as float
) / 60, 2
) as [Hour in office]

Related

Conversion of TimeSpan to a new variable on HHH: mm

I am downloading the list of times from the database
var listaNadgodzinZPoprzMies = _ecpContext.Karta.Where(x => x.Login == userName && x.Rok == numerRoku && x.Miesiac < numerMiesiaca)
.Select(b => string.IsNullOrEmpty(b.SaldoNadgodzin) ? TimeSpan.Zero : TimeSpan.Parse(b.SaldoNadgodzin))
.ToList();
Adds all times
var sumaListaNadgodzinZPoprzMies = listaNadgodzinZPoprzMies.Aggregate(TimeSpan.Zero, (t1, t2) => t1 + t2);
And, I need to convert the number of minutes/ from the variable shown in the image (TimeSpan)
to string to format HHH:mm to other new variable
I scraped out these two functions some time ago in javascript ( I don't know how to convert them to c # ) (I don't know if it will work and whether it will be useful)
function msToTime(duration) {
const minutes = Math.floor((duration / (1000 * 60)) % 60), // 3.4 - 3, 3.5 - 3, 3.8 - 3
hours = Math.floor(duration / (1000 * 60 * 60));
return twoOrMoreDigits(hours) + ":" + twoOrMoreDigits(minutes);
}
function twoOrMoreDigits(n) {
return n < 10 ? '0' + n : n; // if (n < 10) { return '0' + n;} else return n;
}
anyone have any idea?
Here is an example:
TimeSpan time = new TimeSpan(200,1,23);
string strTime = $"{((int)time.TotalHours).ToString("D3")}:{time.Minutes.ToString("D2")}";
Console.WriteLine(strTime);
Output:
200:01
You want to format a timespan, you can achieve it by using this code:
var timespan = TimeSpan.FromMinutes(3180);
var result = timespan.ToString("hh:mm");
Console.WriteLine(result);
hh - hour in 24h format with leading zero
mm - minutes with leading zero
You can read more about timespan formatting here:
https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-timespan-format-strings

Get sum of time column in sql server

What I tried is:
select cast(sum(datediff(second,0,totalhr))/3600 as varchar(12)) + ':' +
right('0' + cast(sum(datediff(second,0,totalhr))/60%60 as varchar(2)),2) +
':' + right('0' + cast(sum(datediff(second,0,totalhr))%60 as varchar(2)),2) as total
FROM checkinout where YEAR(date)=2019 and MONTH(date)=09 and userid=5
It giving wrong output 112:53:04 the right answer should be 116:30:04
If the totalhr column type is time and the format is hh:mm:ss,
For SQL Server: DATEADD (datepart , number , date )
SELECT DATEADD (ms, SUM (DATEDIFF (ms, '00:00:00.000', totalhr)), '00:00:00.000') AS total
FROM checkinout
WHERE
YEAR(date) = 2019 AND
MONTH(date) = 9 AND
userid = 5;
This function adds a specified number value (as a signed integer) to a specified datepart of an input date value, and then returns that modified value.
the above condition will return the calculated Date and Time but if you want just the hh:mm:ss in two digit format you can use:
SELECT FORMAT(hrs, '0#') + ':' + FORMAT(mins, '0#') + ':' + FORMAT(secs, '0#') as total FROM
(SELECT hrs + (((((mins * 60) + (secs - (secs % 60))) / 60) - ((((mins * 60) + (secs - (secs % 60))) / 60) % 60)) / 60) AS hrs,
(((mins * 60) + (secs - (secs % 60))) / 60) % 60 AS mins,
secs % 60 AS secs
FROM (
SELECT SUM(116) AS hrs, // you have to replace the number with your column
SUM(30) AS mins, // you have to replace the number with your column
SUM(04) AS secs // you have to replace the number with your column
) AS dateSplit) AS total
try running below query
SELECT cast(sum(DATEPART(HOUR,totalhr)) as varchar(max)) + ':' +
cast(sum(DATEPART(MINUTE,totalhr)) as varchar(max)) + ':' +
cast(sum(DATEPART(SECOND,totalhr)) as varchar(max)) FROM checkinout

convert string "172406" to integers 17, 24, 06 fast

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.

given a start date how to find the end date which have 365 or 366 days based on the leap year

public static DateTime GetBudgetYearEndDateConsideringLeapYear(DateTime budgetYearStartDate)
{
DateTime endDate = DateTime.MinValue;
if (budgetYearStartDate == null)
throw new ArgumentNullException("budgetYearStartDate must be provided before calling this method");
int startingDateMonth = budgetYearStartDate.Month;
if (startingDateMonth > 2) /// Leap year for the starting year is escaped because Month is NOT February
{
endDate = budgetYearStartDate.AddDays(365);
bool isEndYearLeapYear = DateTime.IsLeapYear(endDate.Year);
if (isEndYearLeapYear)
{
return endDate.AddDays(1);
}
return endDate;
}
else // started from JAN/ FEB
{
if (DateTime.IsLeapYear(budgetYearStartDate.Year))
{
return budgetYearStartDate.AddDays(366);
}
return budgetYearStartDate.AddDays(365);
}
}
What am I missing here
What's wrong with:
public static DateTime GetBudgetYearEndDateConsideringLeapYear
(DateTime budgetYearStartDate)
{
return budgetYearStartDate.AddYears(1);
}
? In other words, return the date a year from the start date, regardless of whether or not it's a leap year.
A couple of things to note:
You should consider what you want the result to be if the start date is February 29th
Your check for nullity is pointless, given that DateTime is a value type
AddYears takes leap years into account so...
budgetYearEndDateConsideringLeapYear = budgetYearStartDate.AddYears(1);
How about startDate.AddYears(1).AddDays(-1);?
This assumes that given a start date of July 1, you want an end date of June 30. The example you posted suggests that you want July 1 -> July 1, in which case, it would be startDate.AddYears(1);.
Try this:
DateTime dtStartOfThisYear = new DateTime( 2011, 11 , 1 ) ;
DateTime dtStartOfNextYear = dtStartOfThisyear.AddYears(1) ;
If you crack open the AddYears() method in Reflector, you'll see that it just invokes the AddMonths() method, passing it the value years * 12. Clever, huh?
And if you crack open AddMonths(), you'll see
public DateTime AddMonths(int months)
{
if ( ( months < -120000 ) || ( months > 0x1d4c0 ) )
{
throw new ArgumentOutOfRangeException("months", Environment.GetResourceString("ArgumentOutOfRange_DateTimeBadMonths"));
}
int datePart = this.GetDatePart( 0 ) ;
int month = this.GetDatePart( 2 ) ;
int day = this.GetDatePart( 3 ) ;
int num4 = ( month - 1 ) + months ;
if ( num4 >= 0 )
{
month = ( num4 % 12 ) + 1 ;
datePart += num4 / 12 ;
}
else
{
month = 12 + ( ( num4 + 1 ) % 12 ) ;
datePart += ( num4 - 11 ) / 12 ;
}
if ( ( datePart < 1 ) || ( datePart > 0x270f ) )
{
throw new ArgumentOutOfRangeException("months", Environment.GetResourceString("ArgumentOutOfRange_DateArithmetic"));
}
int num5 = DaysInMonth( datePart , month );
if ( day > num5 )
{
day = num5 ;
}
return new DateTime(((ulong) (DateToTicks(datePart, month, day) + (this.InternalTicks % 0xc92a69c000L))) | this.InternalKind);
}
I believe you'll find that this code does what you want: for instance, if you start on 29 February of a leap year and add 1 year, you'll wind up on 28 February of the next year.

Count days worked in a week without looping?

I need to count the total days worked given struct saying which days of the week are worked and a from and to date.
My current algorithm is this:
protected int TotalWorkDays(DateTime From, DateTime dtTo,WorkedDays days)
{
int Days = 0;
DayOfWeek DOW;
for (DateTime curDate = From; curDate.Date <= dtTo.Date; curDate = curDate.AddDays(1))
{
DOW = curDate.DayOfWeek;
if ((DOW == DayOfWeek.Sunday & days.Sunday) |
(DOW == DayOfWeek.Monday & days.Monday) |
(DOW == DayOfWeek.Tuesday & days.Tuesday) |
(DOW == DayOfWeek.Wednesday & days.Wednesday) |
(DOW == DayOfWeek.Thursday & days.Thursday) |
(DOW == DayOfWeek.Friday & days.Friday) |
(DOW == DayOfWeek.Saturday & days.Saturday)
)
{
Days += 1;
}
}
return Days;
}
I'm almost positive this can be done without a loop, but I can't seem to figure out. Can someone help me find a more efficient algorithm?
Find the number of weeks between the From and To dates (using subtraction and division). Then multiply that by the number of days worked per week. Do some subtraction for the end cases (From/To dates are in the middle of a week).
hmmmm....
Create a dictionary going from DayOfWeek (int if i remember correctly), to bool then....
var DaysWorked = (from dayoffset in Enumerable.Range(0, (To - From).TotalDays)
where WorkingDays[From.AddDays(dayoffset).DayOfWeek]
select dayoffset).Count();
Not exactly efficient though!
Have a look at this codeproject article which explains how to do it without looping ;)
EDIT: Here's the formula it uses:
Calculate the number of time span in terms of weeks. Call it, W.
Deduct the first week from the number of weeks. W= W-1
Multiply the number of weeks with the number of working days per week.
Call it, D.
Find out the holidays during the specified time span. Call it, H.
Calculate the days in the first week. Call it, SD.
Calculate the days in the last week. Call it, ED.
Sum up all the days. BD = D + SD + ED � H.
You can take advantage of the fact that days of the week repeat every seven days. Here is a basic outline of an algorithm:
Count the number of days worked in the first partial week.
Count the number of days worked in the last partial week.
Calculate the number of whole weeks in the middle and multiply by number of days worked in a week.
Sum the above three values.
var workDays = new DayOfWeek[]{ DayOfWeek.Monday, DayOfWeek.Tuesday};
var days = TotalWorkDays(new DateTime(2005,1,12), new DateTime(2005,3,15), workDays);
protected int TotalWorkDays(DateTime start, DateTime end, DayOfWeek[] workDays)
{
var weeks = (int)Math.Floor((end - start).TotalDays / 7);
var days = weeks * workDays.Length;
//Calc rest
var d = start.AddDays(weeks * 7);
while (d <= end)
{
if(workDays.Contains(d.DayOfWeek))
days++;
d = d.AddDays(1);
}
return days;
}
You can use the following algorithm:
count the working days of the starting week (max 7 iterations)
count the weeks between start/end and multiple the weeks with the working days
count the working days of the end week (max 7 iterations)
The sample uses the classes Week and DateDiff of the Time Period Library for .NET
// ----------------------------------------------------------------------
public int CountWorkingDays( DateTime start, DateTime end, IList<DayOfWeek> workingDays )
{
if ( workingDays.Count == 0 )
{
return 0;
}
Week startWeek = new Week( start );
Week endWeek = new Week( end );
int dayCount = 0;
// start week
DateTime currentDay = start.Date;
while ( currentDay < startWeek.End )
{
if ( workingDays.Contains( currentDay.DayOfWeek ) )
{
dayCount++;
}
currentDay = currentDay.AddDays( 1 );
}
// between weeks
DateDiff inBetweenWeekDiff = new DateDiff( startWeek.End, endWeek.Start );
dayCount += inBetweenWeekDiff.Weeks * workingDays.Count;
// end week
currentDay = endWeek.Start.Date;
while ( currentDay < end )
{
if ( workingDays.Contains( currentDay.DayOfWeek ) )
{
dayCount++;
}
currentDay = currentDay.AddDays( 1 );
}
return dayCount;
} // CountWorkingDays
Usage:
// ----------------------------------------------------------------------
public void CountWorkingDaysSample()
{
DayOfWeek[] workingDays = new [] { DayOfWeek.Monday, DayOfWeek.Tuesday };
DateTime start = new DateTime( 2011, 3, 1 );
DateTime end = new DateTime( 2011, 5, 1 );
Console.WriteLine( "working days: {0}", CountWorkingDays( start, end, workingDays ) );
// > working days: 19
} // CountWorkingDaysSample

Categories