Adding Duration that contains frames - c#

I have a duration that contains frames:
e.g1: 00:00:00:00
hh:mm:ss:FR
FR - stands for frames which is 25 frames for the middleast/asia region.
But in C# it takes the last FR as seconds (which is 60seconds).
e.g2: 00:00:00:00
DD:hh:mm:ss
Now how do I add e.g1 in C#
Can I know with this format how do I add two duration.
TimeSpan t1 = TimeSpan.Parse(duration);
TimeSpan t2 = TimeSpan.Parse("00:00:30:18");
TimeSpan t3 = t1.Add(t2);

in this duration "00:00:30:18" 18 is considered as milliseconds and not frames, so Timespan.Duration won't work for you, and you need something custom (for displaying might work but not adding and subtracting):
public static class Extensions
{
public static TimeSpan AddWithFrames(this TimeSpan x, TimeSpan ts)
{
int fr = ts.Seconds + x.Seconds;
TimeSpan result = x.Add(ts).Add(new TimeSpan(0,0,fr/25,0));
return new TimeSpan(result.Days, result.Hours, result.Minutes, fr % 25);
}
}
And use it like:
TimeSpan t1 = TimeSpan.Parse(duration);
TimeSpan t2 = TimeSpan.Parse("00:00:30:18");
TimeSpan t3 = t1.AddWithFrames(t2);

you can use a custom class that handles operations with SMPTE timecodes.
you do not need to reinvent the wheel, as this project handles all different kinds of framerates and frame drops:
https://github.com/ailen0ada/Timecode4net
using Timecode4net;
var start = Timecode.FromString(input: "00:00:05:15", frameRate: FrameRate.fps25, isDropFrame: false);
var end = Timecode.FromString("00:00:10:22", FrameRate.fps25, false);
Console.WriteLine((end.TotalFrames - start.TotalFrames)/25.0);
gives you 5,28

Here is how I did it unless someone has a better way to simplify this, kindly please share
string timecode1 = "00:05:00:04";
string timecode2 = "00:06:00:24";
int hours1 = Int32.Parse(timecode1.Substring(0,2))*90000;
int minutes1 = Int32.Parse(timecode1.Substring(3, 2))*1500;
int seconds1 = Int32.Parse(timecode1.Substring(6, 2))*25;
int frames1 = Int32.Parse(timecode1.Substring(9, 2));
int hours2 = Int32.Parse(timecode2.Substring(0, 2)) * 90000;
int minutes2 = Int32.Parse(timecode2.Substring(3, 2)) * 1500;
int seconds2 = Int32.Parse(timecode2.Substring(6, 2)) * 25;
int frames2 = Int32.Parse(timecode2.Substring(9, 2));
int time1 = hours1 + minutes1 + seconds1 + frames1;
int time2 = hours2 + minutes2 + seconds2 + frames2;
int totaltime = time1 + time2;
int hours = totaltime / 90000;
int minutes = ((totaltime % 90000)) / 1500;
int seconds = ((totaltime % 90000) % 1500 )/ 25;
int frames = ((totaltime % 90000) % 1500) % 25;

Related

How do I add TimeSpan in C# inside Loop?

Can anyone please tell me I need to add time with interval with in the for loop. This is my C# code.
var t1 = selectedTime.TimeOfDay;
t1 = 8.00 //assum time is 8.00
for (int i = 0; i <=5; i++) {
var duration = TimeSpan.FromMinutes(15);
var t3 = duration;
}
My output should be:
8.00
8.15
8.30
8.45
9.00
The gotcha in your original code is increment and persist the new value; in this snippet I updated the t1 variable:
var selectedTime = DateTime.Today.AddHours(8);
var t1 = selectedTime.TimeOfDay; //assume time is 8.00
for (int i = 0; i <=5; i++)
{
Console.WriteLine(t1);
t1 += TimeSpan.FromMinutes(15);
}
Try like this:
var t1 = DateTime.Now.TimeOfDay;
//t1 = 8.00 //assum time is 8.00
var duration = TimeSpan.FromMinutes(15);
Console.WriteLine(t1); // print current time
for (int i = 0; i <=4; i++)
{
t1 += duration; // add timespan 4 times
Console.WriteLine(t1);
}
You can add TimeSpan to the DateTime easily. You just need to make sure you are remembering the previous value or by increasing the time span (eg. 15 min, 30 min etc) in each loop cycle.
Alternatively, you could use the DateTime.AddMinutes() method:
DateTime t1 = DateTime.Now.AddHours(8);
for(int i = 0; i < 5; i++) {
Console.WriteLine(t1.AddMinutes(15 * i).ToString("HH:mm"));
}
TimeSpan is added using the + operator with another TimeSpan, for example, I can implement this 15 seconds interval loop using Linq as the following:
TimeSpan initialTimeSpan = new TimeSpan(0, 4, 2);
IEnumerable<TimeSpan> spans = Enumerable.Range(0, 5)
.Select(x => x * 15)
.Select(x => initialTimeSpan + TimeSpan.FromSeconds(x));
foreach (TimeSpan span in spans)
{
Console.WriteLine(span);
}
To add it to a DateTime use the Add method:
DateTime date = DateTime.Now;
TimeSpan initialTimeSpan = new TimeSpan(0, 4, 2);
date = date.Add(initialTimeSpan);
Or you can just add the period you wish without using TimeSpan by using the AddSeconds/AddMinutes/AddHours/AddMilliseconds/AddTicks/AddYears/AddDays/AddMonths methods:
DateTime date = DateTime.Now;
TimeSpan initialTimeSpan = new TimeSpan(0, 4, 2);
date = date.AddSeconds(5);
You can use everything in a loop like that:
DateTime initialTime = DateTime.Now;
for (DateTime loopTime = initialTime; loopTime < initialTime.AddMinutes(2); loopTime = loopTime.AddSeconds(15))
{
Console.WriteLine(loopTime);
}
And you will get the following output:
26/09/2015 13:00:33
26/09/2015 13:00:48
26/09/2015 13:01:03
26/09/2015 13:01:18
26/09/2015 13:01:33
26/09/2015 13:01:48
26/09/2015 13:02:03
26/09/2015 13:02:18
To get the output in the format you wanted you can change the printing to the following:
Console.Write(loopTime.Minute + ".");
if (loopTime.Second < 10)
{
Console.Write(0);
}
Console.WriteLine(loopTime.Second);
And you will get this output for the same hours shown above:
0.33
0.48
1.03
1.18
1.33
1.48
2.03
2.18

How can i calculate the difference between a stored DateTime.Now and a current DateTime.Now?

I have a global var that i'm getting the DateTime.Now once i click a button:
dt = DateTime.Now;
Then inside a progresschanged event i'm doing:
var currentTime = DateTime.Now;
Now i need to calculate the difference between the currentTime and the stored time(dt) in seconds. Then i need to Divide BytesSent by the difference in seconds.
This is the progresschanged event i'm using:
double mbSent = 0;
int percentComplete = 0;
static string progress = "";
static string ttt = "";
private void videosInsertRequest_ProgressChanged(IUploadProgress obj)
{
stringProgressReport[1] = obj.Status.ToString();
backgroundWorker1.ReportProgress(0, 1);
mbSent = ((double)obj.BytesSent) / (1 << 20);
stringProgressReport[2] = mbSent.ToString();
backgroundWorker1.ReportProgress(0, 2);
percentComplete = (int)Math.Round(((double)obj.BytesSent) / totalBytes * 100);
stringProgressReport[3] = percentComplete.ToString();
backgroundWorker1.ReportProgress(0, 3);
var currentTime = DateTime.Now;
}
At the bottom of the event i need ot make the calculation and this way i can report the average speed. File upload speed.
EDIT
I'm getting exception when doing:
var currentTime = DateTime.Now;
TimeSpan diff = currentTime - dt;
int diffSeconds = (int)diff.TotalSeconds;
long averageSpeed = obj.BytesSent / diffSeconds;
both obj.BytesSent and diffSeconds are 0 so i get exception cant divide by zero on the averageSpeed.
Why diffSeconds is 0 ? Tried to calculate the time difference between dt and currentTime.
EDIT
This is what i did now:
if (obj.BytesSent != 0)
{
var currentTime = DateTime.Now;
TimeSpan diff = currentTime - dt;
var diffSeconds = (DateTime.Now - dt).TotalSeconds;
long averageSpeed = diffSeconds != 0 ? obj.BytesSent / diffSeconds : 0L;
double MBunits = ConvertBytesToMegabytes(averageSpeed);
stringProgressReport[4] = MBunits.ToString();
backgroundWorker1.ReportProgress(0, 4);
}
But getting error now on the long averageSpeed cant convert type double to long.
And this is the method that i use to convert to MegaBytes:
static double ConvertBytesToMegabytes(long bytes)
{
return (bytes / 1024f) / 1024f;
}
And in the backgroundworker progresschanged event:
label8.Text = stringProgressReport[4];
How can i show the user something nicer ? for example the speed something like:
The average speed is: 0.5 MB/s then 0.9 MB/s then 1.6 MB/s in this format or something else nicer.
You can simply substract two DateTime objects:
TimeSpan diff = currentTime - dt;
int diffSeconds = (int) diff.TotalSeconds;
var elapedSeconds = (DateTime.Now-dt).TotalSeconds;
You need a little bit of defensive programming to prevent the exception:
var diffSeconds = (DateTime.Now - dt).TotalSeconds;
long averageSpeed = diffSeconds !=0 ? obj.BytesSent / diffSeconds : 0L;

How to find End date from the given date and days excluding sundays

I have my start date as 05/03/2012 and duration is 200 days now I would like to get the end date excluding sundays. So that my end date should be 05/02/2013.. Can some one help me
Try this for me:
var startDate = new DateTime(2012, 5, 3);
var sundaysOverDuration = 200 / 7;
var actualDuration = 200 + sundaysOverDuration;
var newDate = startDate.AddDays(actualDuration);
I also honestly have to admit that this link is flat out elegant surrounding how it handles a lot of the exceptions that exist when doing these types of calculations. I'm not sure you need something that complex, but it's worth letting you know. I'm going to inline the code just to ensure it's preserved if the link is ever broken.
public static double GetBusinessDays(DateTime startD, DateTime endD)
{
double calcBusinessDays =
1 + ((endD-startD).TotalDays * 6 -
(startD.DayOfWeek-endD.DayOfWeek) * 2) / 7;
if ((int)startD.DayOfWeek == 0) calcBusinessDays --;
return calcBusinessDays;
}
public static DateTime AddWorkDaysToStartDate(DateTime startD, double businessDays)
{
int DoW = (int)startD.DayOfWeek;
double temp = businessDays + DoW + 1;
if (DoW != 0) temp --;
DateTime calcendD = startD.AddDays(
Math.Floor(temp / 6)*2-DoW + temp
- 2* Convert.ToInt32(temp % 6 == 0)) ;
}
Finally, based on your question it doesn't appear you need to handle holidays, but if you do the solution is much more complex and would need to be database driven, so just keep that in mind.
You can use the CalendarDateAdd class from the Time Period Library for .NET:
// ----------------------------------------------------------------------
public void AddDaysSample()
{
CalendarDateAdd calendarDateAdd = new CalendarDateAdd();
calendarDateAdd.AddWorkingWeekDays();
calendarDateAdd.WeekDays.Add( DayOfWeek.Saturday );
DateTime start = new DateTime( 2012, 5, 3 );
TimeSpan duration = new TimeSpan( 200, 0, 0, 0 );
DateTime? end = calendarDateAdd.Add( start, duration );
Console.WriteLine( "AddDaysSample : {0:d} + {1} days = {2:d}", start, duration.Days, end );
} // AddDaysSample

How to compare HH:MM in C#

Hi I have to compare HH:MM(hour and minutes). How can i do so?
var t1 = DateTime.Now.ToString("HH:mm");
var t2 = "20:03";
var res =result(t1, t2);
public int result(string t1, string t2)
{
int i = -1;
int hr1 = Convert.ToInt32(t1.Split(':')[0]);
int hr2 = Convert.ToInt32(t2.Split(':')[0]);
int min1 = Convert.ToInt32(t1.Split(':')[1]);
int min2 = Convert.ToInt32(t2.Split(':')[1]);
if (hr2 >= hr1)
{
if (min2 >= min1)
{
i = 1;
}
}
return i;
}
But it is not correct.. it is not taking care of all conditions.. how to make it perfect. Or is there any built in function that does this with thsi input only(I checked but no answer).
Thanks in advance
If you can assume the two strings are already in the right format, just use:
return t1.CompareTo(t2);
After all, they're lexicographically sorted due to the format used - no need to parse :)
With all the references to TimeSpan... Of course if you were using Noda Time you could use:
private static readonly LocalTimePattern TimePattern =
LocalTimePattern.CreateWithInvariantInfo("HH:mm");
...
public int CompareTimes(string t1, string t2)
{
// These will throw if the values are invalid. Use TryGetValue
// or the Success property to check first...
LocalTime time1 = TimePattern.Parse(t1).Value;
LocalTime time2 = TimePattern.Parse(t2).Value;
return time1.CompareTo(time2);
}
(You can use TimeSpan if you want, of course... but LocalTime represents the actual type of data you've got: a time of day, rather than an amount of time passing ;)
Use a TimeSpan:
TimeSpan s1 = TimeSpan.Parse(t1);
TimeSpan s2 = TimeSpan.Parse(t2);
return s1.CompareTo(s2);
If you're not sure the inputs are in the correct format, you can use TryParse instead.
If these represent clock times (i.e. hour is always less than 24), then DateTime.ParseExact is what you want.
Otherwise, TimeSpan.ParseExact
If you can guarantee that the provided time is always HH:mm you can use TimeSpan.ParseExact.
You can parse the time direct from the string. Beware the culture!
var time1 = DateTime.ParseExact("12:56", "hh:mm", CultureInfo.CurrentCulture);
var time2 = DateTime.ParseExact("11:21", "hh:mm", CultureInfo.CurrentCulture);
The other solutions are more elegant and simple and deal with culture issues and should be used in professional level code.
But to fix your code, you only need to compare the minute values if and only if the hour values are equal.
var t1 = DateTime.Now.ToString("HH:mm");
var t2 = "20:03";
var res =result(t1, t2);
public int result(string t1, string t2)
{
int i = -1;
int hr1 = Convert.ToInt32(t1.Split(':')[0]);
int hr2 = Convert.ToInt32(t2.Split(':')[0]);
int min1 = Convert.ToInt32(t1.Split(':')[1]);
int min2 = Convert.ToInt32(t2.Split(':')[1]);
if (hr2 > hr1)
i = 1;
else if (hr2 = hr1 && min2 >= min1)
i = 1;
return i;
}
This works
public int CompareTime(string t1, string t2)
{
int i = -1;
int hr1 = Convert.ToInt32(t1.Split(':')[0]);
int hr2 = Convert.ToInt32(t2.Split(':')[0]);
int min1 = Convert.ToInt32(t1.Split(':')[1]);
int min2 = Convert.ToInt32(t2.Split(':')[1]);
if (hr2 == hr1)
{
if (min2 >= min1)
{
i = 1;
}
}
if (hr2 > hr1)
{
i = 1;
}
return i;
}

Calculate the average TimeSpan between a collection of DateTimes

Let's say we're tracking the times when a user is performing a certain action, and we want to know the average time between said actions.
For example, if the user performed this action at these times:
today, 1 PM
today, 3 PM
today, 6 PM
The result would be 2.5 hours.
I actually have solved this already, but I felt my solution was more complicated than necessary. I'll post it as an answer.
It seems that you are basically looking for Max - Min divided by Count.
public TimeSpan? Average
{
get
{
var diff = _dateTimes.Max().Subtract(_dateTimes.Min());
var avgTs = TimeSpan.FromMilliseconds(diff.TotalMilliseconds / (_dateTimes.Count() - 1));
return avgTs;
}
}
Make sure you check that there is more than one DateTime.
Update: Even more accurate if you use Ticks.
TimeSpan.FromTicks(diff.Ticks / (_dateTimes.Count() - 1));
I recently had a similar task in where I had a long running operation iterating over thousands of rows with 20-30 iterations within each.
void LongRunningOperation()
{
int r = 5000;
int sR = 20;
List<TimeSpan> timeSpanList = new List<TimeSpan>();
for (int i = 0; i < r; i++)
{
DateTime n = DateTime.Now; // Gets start time of this iteration.
for (int x = 0; x < sR; x++)
{
// DOING WORK HERE
}
timeSpanList.Add(DateTime.Now - n); // Gets the length of time of iteration and adds it to list.
double avg = timeSpanList.Select(x => x.TotalSeconds).Average(); // Use LINQ to get an average of the TimeSpan durations.
TimeSpan timeRemaining = DateTime.Now.AddSeconds((r - i) * avg) - DateTime.Now;
// Calculate time remaining by taking the total number of rows minus the number of rows done multiplied by the average duration.
UpdateStatusLabel(timeRemaining);
}
}
This is how I solved it, but I don't like it much:
public class HistoryItem
{
private IEnumerable<DateTime> _dateTimes;
public TimeSpan? Average
{
get {
TimeSpan total = default(TimeSpan);
DateTime? previous = null;
int quotient = 0;
var sortedDates = _dateTimes.OrderBy(x => x);
foreach (var dateTime in sortedDates)
{
if (previous != null)
{
total += dateTime - previous.Value;
}
++quotient;
previous = dateTime;
}
return quotient > 0 ? (TimeSpan.FromMilliseconds(total.TotalMilliseconds/quotient)) as TimeSpan? : null;
}
}
}

Categories

Resources