Retrieve user's Outlook status - c#

I found VBScript code to retrieve a user's Outlook status and display in a list box. I need it to be C# and there are no conversion tools online:
Set objOutlook = CreateObject("Outlook.Application")
Set objNamespace = objOutlook.GetNamespace("MAPI")
Set objRecipient = objNameSpace.CreateRecipient("kenmyer")
strFreeBusyData = objRecipient.FreeBusy(#11/11/2014#, 60)
dtmStartDate = #11/11/2014#
For i = 1 to Len(strFreeBusyData) Step 24
Wscript.Echo dtmStartDate
strDay = Mid(strFreeBusyData, i, 24)
For x = 1 to 12
If x = 1 Then
strTime = "12 AM: "
Else
strTime = x - 1 & " AM: "
End If
intFreeBusy = Mid(strDay, x, 1)
If intFreeBusy = 1 Then
strFreeBusy = "Busy"
Else
strFreeBusy = "Free"
End If
Wscript.Echo strTime & strFreeBusy
Next
For x = 13 to 24
If x = 13 Then
strTime = "12 PM: "
Else
strTime = x - 13 & " PM: "
End If
intFreeBusy = Mid(strDay, x, 1)
If intFreeBusy = 1 Then
strFreeBusy = "Busy"
Else
strFreeBusy = "Free"
End If
Wscript.Echo strTime & strFreeBusy
Next
Wscript.Echo
dtmStartDate = dtmStartDate + 1
If dtmStartDate > #11/12/2014# Then
Exit For
End If
Next
The end result would look like this in my C# application under the appointments list box:
11/11/2014
8 AM: Free
9 AM: Free
10 AM: Free
11 AM: Free
12 PM: Free
1 PM: Free
2 PM: Free
3 PM: Free
4 PM: Free
5 PM: Busy
6 PM: Free
What I have so far:
private void userschedule()
{
Outlook.Application oApp = new Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace ns = oApp.Application.Session;
Outlook.Recipient recipient = ns.CreateRecipient(username.Text);
DateTime datetime = DateTime.Now;
string freeBusy = recipient.AddressEntry.GetFreeBusy(datetime, 60, true);
string status = freeBusy.Substring(0, 1);
textBox1.Text = status;
}
How can I convert this to C#? The other set of code is similar:
For i = 1 to Len(strFreeBusyData) Step 24
Wscript.Echo dtmStartDate
strDay = Mid(strFreeBusyData, i, 24)
For x = 1 to 12
If x = 1 Then
strTime = "12 AM: "
Else
strTime = x - 1 & " AM: "
End If
intFreeBusy = Mid(strDay, x, 1)
If intFreeBusy = 1 Then
strFreeBusy = "Busy"
Else
strFreeBusy = "Free"
End If
Wscript.Echo strTime & strFreeBusy
Next
Newly Edited Code ( Final Answer to my Question)
private void userstatus()
{
{
{
Outlook.Application oApp = new Outlook.Application();
Microsoft.Office.Interop.Outlook.NameSpace ns = oApp.Application.Session;
Outlook.Recipient recipient = ns.CreateRecipient(username.Text);
DateTime datetime = DateTime.Now; // gets current date and time
DateTime startDate = DateTime.Today; //gets todays date
startDate.AddHours(8); //Skip to 8 am
string freeBusy = recipient.AddressEntry.GetFreeBusy(startDate, 60, true);
textBox1.Text = freeBusy;
foreach (char c in freeBusy) //iteration process
{
if (startDate.Hour == 0) //start at 12 AM
Contacts.Items.Add(startDate.ToString("dd/MM/yyyy"));
if (8 <= startDate.Hour && startDate.Hour <= 18) // 8AM to 6PM inclusive
{
listBox1.Items.Add(
String.Format(
"{0}: {1}",
startDate.ToString("hh tt"),
c == '0' ? "Free" : "Busy"));
}
startDate = startDate.AddHours(1);
if (startDate.Date > DateTime.Today)
break; // stop once we get to tomorrow.
}
}
}
private void button5_Click(object sender, EventArgs e)
{
userstatus();
}
The freeBusy string looks like this for the user I am getting the free/busy status for.
I got the below by doing this:
string freeBusy = recipient.AddressEntry.GetFreeBusy(datetime, 60, true);
textBox1.Text = freeBusy;
000000002200000000000000000000002200000000000000333333333333333333333333000000000000000000000000000000000000000000000000000000002000001100000000000000002000001000000000000000002000000000000000000000002022200000000000000000002000001000000000000000000000000000000000000000000000000000000000333333333333333333333333000000002001101000000000000000002000000000000000000000002000000000000000000000002000000000000000000000000000000000000000000000000000000000000000000000002000001100000000000000002000000000000000000000002000000000000000000000002020000000000000000000002000001000000000000000000000000000000000000000000000000000000000000000002000001100000000000000002000000000000000000000002000000000000000000000002000000000000000

The following for loop and logic in VBScript
For i = 1 to Len(strFreeBusyData) Step 24
Wscript.Echo dtmStartDate
strDay = Mid(strFreeBusyData, i, 24)
...
Next
would be equivalent to the following in C#
for(int i = 0; i < strFreeBusyData.Length; i+= 24)
{
Console.WriteLine(dtmStartDate);
var strDay = strFreeBusyData.Substring(i, 24);
...
}
One big difference between VBScript and C# is that VBScript tends to be 1 - based when dealing with strings, whereas C# is 0 based. Specifically the Mid function's first parameter wants an index into the string that is 1-based (1 would mean start at the first character) whereas string.Substrings first parameter should be 0-based (0 would mean start at the first character).
EDIT
After sleeping on it a better way of dealing with this in C# would be the following.
DateTime startDate = DateTime.Today;
string freeBusy = recipient.AddressEntry.GetFreeBusy(datetime, 60, true);
foreach(char c in freeBusy)
{
if(startDate.Hour == 0)
Console.WriteLine(startDate.ToString("dd/MM/yyyy"));
Console.WriteLine(
"{0}: {1}",
startDate.ToString("hh tt"),
c == '1' ? "Busy" : "Free");
startDate = startDate.AddHours(1);
}
This will get a DateTime that has today's date, but a time of 12 am. Then as you iterate over each character in the freeBusy string you will output the startDate formatted as dd/MM/yyyy when the hour is 0 or 12 am. Then you write out the hour in 12 hour time (hh) and the AM/PM designator (tt) and the word Busy if the character is "1" or Free otherwise. Then increment the startDate by one hour. This avoids the unnecessary inner for loops that the VBScript code has.
EDIT
Based on your updated code you should change this
listBox1.Items.Add("{0}: {1}") ;
listBox1.Items.Add(startDate.ToString("hh tt") + " " + (c == '1' ? "Busy" : "Free"));
listBox1.Items.Add(c == '1' ? "Busy" : "Free");
startDate.AddHours(1);
to this
listBox1.Items.Add(
string.Format(
"{0}: {1}",
startDate.ToString("hh tt"),
c == '1' ? "Busy" : "Free");
startDate = startDate.AddHours(1);
The "{0}: {1}" is for formatting and Console.WriteLine has an overload that takes a format string. The date wasn't changing because DateTime is immuteable and you have to capture the return value of AddHours, that was my bad.
Edit
Here's code that will only show items for today and only between 8am and 6pm
foreach (char c in freeBusy) //iteration process
{
if (startDate.Hour == 0 ) //start at 12 AM
Contacts.Items.Add(startDate.ToString("dd/MM/yyyy"));
if(8 <= startDate.Hour && startDate.Hour <= 18) // 8AM to 6PM inclusive
{
listBox1.Items.Add(
String.Format(
"{0}: {1}",
startDate.ToString("hh tt"),
c == '1' ? "Busy" : "Free"));
}
startDate = startDate.AddHours(1);
if(startDate.Date > DateTime.Today)
break; // stop once we get to tomorrow.
}
You can optimize this to break after you hit 6PM if you want. It could also be shortened to the following
DateTime startDate = DateTime.Today; //gets todays date
string freeBusy = recipient.AddressEntry.GetFreeBusy(datetime, 60, true);
Contacts.Items.Add(startDate.ToString("dd/MM/yyyy"));
startDate = startDate.AddHours(8); //Skip to 8 am
foreach (char c in freeBusy.Skip(8).Take(11)) // skip to 8AM and only go to 6PM
{
listBox1.Items.Add(
String.Format(
"{0}: {1}",
startDate.ToString("hh tt"),
c == '0' ? "Free" : "Busy"));
startDate = startDate.AddHours(1);
}
EDIT
Changed
c == '1' ? "Busy" : "Free"
to
c == '0' ? "Free" : "Busy"

Related

Interpolate between DateTimes in a List in a linear fashion and reapply those values to the list

I have a class like this:
public class Datumsobjekt
{
public string dateiname { get; set; }
public DateTime zeit { get; set; }
}
When creating a List<Datumsobjekt> and filling it with values, I sometimes do not set zeit. zeit is always ascending, no sorting necessary.
Which leads to a(Example)
filename1.ext - 03.01.15
filename2.ext - 04.01.15
filename3.ext -
filename4.ext - 08.01.15
How do I interpolate between dates in a linear fashion, so every dateiname has a zeit and reapply it to the list?
The goal should be something along the lines of
filename1.ext - 03.01.15
filename2.ext - 04.01.15
filename3.ext - 06.01.15
filename4.ext - 08.01.15
for the first example.
PS: It could also be
filename1.ext - 03.01.15
filename2.ext - 04.01.15
filename3.ext -
filename4.ext -
filename5.ext - 08.01.15
and
filename1.ext - 03.01.15
filename2.ext - 04.01.15
filename3.ext -
filename4.ext -
filename5.ext - 08.01.15
filename6.ext -
filename7.ext -
...
filenamen.ext -
filenamen+1.ext - 09.01.15
ie arbitrary numbers of dateiname without a zeit and interrupted by given zeit.
DateTime has an operator Subtract which gives a TimeSpan object as a result.
This can be used to subtract 2 DateTime objects;
System.DateTime date1 = new System.DateTime(1996, 6, 3, 22, 15, 0);
System.DateTime date2 = new System.DateTime(1996, 12, 6, 13, 2, 0);
System.DateTime date3 = new System.DateTime(1996, 10, 12, 8, 42, 0);
// diff1 gets 185 days, 14 hours, and 47 minutes.
System.TimeSpan diff1 = date2.Subtract(date1);
// diff2 gets 55 days 4 hours and 20 minutes.
System.TimeSpan diff2 = date2 - date3;
TimeSpan has a useful operator Division which takes a double as a divisor and gives a TimeSpan result.
A TimeSpan can be added to a DateTime to get a DateTime result.
If You need n values in-between two selected DateTime's then the TimeSpan has to be divided by n+1.
Example 1:
dateTime1 = d1
datetime2 = ? > 1 empty value
datetime3 = d3
So the interval = (datetime1 - datetime3) / (1 + 1)
And datetime2 = datetime1 + interval.
Example 2:
dateTime1 = d1
datetime2 = ? \
datetime3 = ? |
datetime4 = ? |
datetime5 = ? | 8 empty values
datetime6 = ? |
datetime7 = ? |
datetime8 = ? |
datetime9 = ? /
datetime10 = d10
So the interval = (datetime1 - dateime10) / (8 + 1)
And datetime2 = datetime1 + interval.
And datetime3 = datetime2 + interval.
And datetime4 = datetime3 + interval.
...
The funny thing with indexes of an array is that if 2 indexes are subtracted from each other then they give the required value:
For example 1:
index's: 3 - 1 = 2
For example 2:
index's: 10 - 1 = 9
class Program
{
static void Main()
{
DateTime?[] dates = new DateTime?[]
{
new DateTime(2019,1,1),
null,
new DateTime(2019,1,3),
null,null,
new DateTime(2019,1,6),
null,null,null,
new DateTime(2019,1,10),
null,null,null, null,null,null, null,null,null,
new DateTime(2019,1,20),
};
Console.WriteLine("Before:");
foreach (var zeit in dates)
Console.WriteLine(zeit.HasValue ? zeit.ToString() : "<empty>");
Interpolate_dates(dates);
Console.WriteLine("\nAfter:");
foreach (var zeit in dates)
Console.WriteLine(zeit.HasValue ? zeit.ToString() : "!!ERROR!! - all dates should be interpolated.");
}
public static void Interpolate_dates(Span<DateTime?> dates)
{
if (dates.Length == 0)
return;
if (!dates[0].HasValue)
throw new ArgumentException("First date cannot be null.");
if (!dates[dates.Length - 1].HasValue)
throw new ArgumentException("Last date value cannot be null");
int last_filled_date_index = 0;
for (int checking_index = 1; checking_index < dates.Length; checking_index++)
{
if (dates[checking_index].HasValue)
{
if (checking_index != last_filled_date_index + 1)
{
Interpolate(dates, last_filled_date_index, checking_index);
}
last_filled_date_index = checking_index;
}
}
}
private static void Interpolate(Span<DateTime?> dates, int earlier_date_idx, int later_date_idx)
{
TimeSpan interval = (dates[later_date_idx].Value - dates[earlier_date_idx].Value) / (later_date_idx - earlier_date_idx);
for (int index = earlier_date_idx + 1; index < later_date_idx; index++)
{
dates[index] = dates[index - 1] + interval;
}
}
}

TimeSpan to string in format "hh.mm" [duplicate]

What is the recommended way of formatting TimeSpan objects into a string with a custom format?
Please note: this answer is for .Net 4.0 and above. If you want to format a TimeSpan in .Net 3.5 or below please see JohannesH's answer.
Custom TimeSpan format strings were introduced in .Net 4.0. You can find a full reference of available format specifiers at the MSDN Custom TimeSpan Format Strings page.
Here's an example timespan format string:
string.Format("{0:hh\\:mm\\:ss}", myTimeSpan); //example output 15:36:15
(UPDATE) and here is an example using C# 6 string interpolation:
$"{myTimeSpan:hh\\:mm\\:ss}"; //example output 15:36:15
You need to escape the ":" character with a "\" (which itself must be escaped unless you're using a verbatim string).
This excerpt from the MSDN Custom TimeSpan Format Strings page explains about escaping the ":" and "." characters in a format string:
The custom TimeSpan format specifiers do not include placeholder separator symbols, such as the symbols that separate days from hours, hours from minutes, or seconds from fractional seconds. Instead, these symbols must be included in the custom format string as string literals. For example, "dd.hh:mm" defines a period (.) as the separator between days and hours, and a colon (:) as the separator between hours and minutes.
For .NET 3.5 and lower you could use:
string.Format ("{0:00}:{1:00}:{2:00}",
(int)myTimeSpan.TotalHours,
myTimeSpan.Minutes,
myTimeSpan.Seconds);
Code taken from a Jon Skeet answer on bytes
For .NET 4.0 and above, see DoctaJonez answer.
One way is to create a DateTime object and use it for formatting:
new DateTime(myTimeSpan.Ticks).ToString(myCustomFormat)
// or using String.Format:
String.Format("{0:HHmmss}", new DateTime(myTimeSpan.Ticks))
This is the way I know. I hope someone can suggest a better way.
Simple. Use TimeSpan.ToString with c, g or G. More information at MSDN
I would go with
myTimeSpan.ToString("hh\\:mm\\:ss");
Personally, I like this approach:
TimeSpan ts = ...;
string.Format("{0:%d}d {0:%h}h {0:%m}m {0:%s}s", ts);
You can make this as custom as you like with no problems:
string.Format("{0:%d}days {0:%h}hours {0:%m}min {0:%s}sec", ts);
string.Format("{0:%d}d {0:%h}h {0:%m}' {0:%s}''", ts);
Dim duration As New TimeSpan(1, 12, 23, 62)
DEBUG.WriteLine("Time of Travel: " + duration.ToString("dd\.hh\:mm\:ss"))
It works for Framework 4
http://msdn.microsoft.com/en-us/library/ee372287.aspx
This is awesome one:
string.Format("{0:00}:{1:00}:{2:00}",
(int)myTimeSpan.TotalHours,
myTimeSpan.Minutes,
myTimeSpan.Seconds);
You can also go with:
Dim ts As New TimeSpan(35, 21, 59, 59) '(11, 22, 30, 30) '
Dim TimeStr1 As String = String.Format("{0:c}", ts)
Dim TimeStr2 As String = New Date(ts.Ticks).ToString("dd.HH:mm:ss")
EDIT:
You can also look at Strings.Format.
Dim ts As New TimeSpan(23, 30, 59)
Dim str As String = Strings.Format(New DateTime(ts.Ticks), "H:mm:ss")
if (timeSpan.TotalDays < 1)
return timeSpan.ToString(#"hh\:mm\:ss");
return timeSpan.TotalDays < 2
? timeSpan.ToString(#"d\ \d\a\y\ hh\:mm\:ss")
: timeSpan.ToString(#"d\ \d\a\y\s\ hh\:mm\:ss");
All literal characters must be escaped.
This is the approach I used my self with conditional formatting. and I post it here because I think this is clean way.
$"{time.Days:#0:;;\\}{time.Hours:#0:;;\\}{time.Minutes:00:}{time.Seconds:00}"
example of outputs:
00:00 (minimum)
1:43:04 (when we have hours)
15:03:01 (when hours are more than 1 digit)
2:4:22:04 (when we have days.)
The formatting is easy. time.Days:#0:;;\\ the format before ;; is for when value is positive. negative values are ignored. and for zero values we have;;\\ in order to hide it in formatted string. note that the escaped backslash is necessary otherwise it will not format correctly.
Here is my extension method:
public static string ToFormattedString(this TimeSpan ts)
{
const string separator = ", ";
if (ts.TotalMilliseconds < 1) { return "No time"; }
return string.Join(separator, new string[]
{
ts.Days > 0 ? ts.Days + (ts.Days > 1 ? " days" : " day") : null,
ts.Hours > 0 ? ts.Hours + (ts.Hours > 1 ? " hours" : " hour") : null,
ts.Minutes > 0 ? ts.Minutes + (ts.Minutes > 1 ? " minutes" : " minute") : null,
ts.Seconds > 0 ? ts.Seconds + (ts.Seconds > 1 ? " seconds" : " second") : null,
ts.Milliseconds > 0 ? ts.Milliseconds + (ts.Milliseconds > 1 ? " milliseconds" : " millisecond") : null,
}.Where(t => t != null));
}
Example call:
string time = new TimeSpan(3, 14, 15, 0, 65).ToFormattedString();
Output:
3 days, 14 hours, 15 minutes, 65 milliseconds
I used the code below. It is long, but still it is one expression, and produces very friendly output, as it does not outputs days, hours, minutes, or seconds if they have value of zero.
In the sample it produces output: "4 days 1 hour 3 seconds".
TimeSpan sp = new TimeSpan(4,1,0,3);
string.Format("{0}{1}{2}{3}",
sp.Days > 0 ? ( sp.Days > 1 ? sp.ToString(#"d\ \d\a\y\s\ "): sp.ToString(#"d\ \d\a\y\ ")):string.Empty,
sp.Hours > 0 ? (sp.Hours > 1 ? sp.ToString(#"h\ \h\o\u\r\s\ ") : sp.ToString(#"h\ \h\o\u\r\ ")):string.Empty,
sp.Minutes > 0 ? (sp.Minutes > 1 ? sp.ToString(#"m\ \m\i\n\u\t\e\s\ ") :sp.ToString(#"m\ \m\i\n\u\t\e\ ")):string.Empty,
sp.Seconds > 0 ? (sp.Seconds > 1 ? sp.ToString(#"s\ \s\e\c\o\n\d\s"): sp.ToString(#"s\ \s\e\c\o\n\d\s")):string.Empty);
I use this method. I'm Belgian and speak dutch so plural of hours and minutes is not just adding 's' to the end but almost a different word than singular.
It may seem long but it is very readable I think:
public static string SpanToReadableTime(TimeSpan span)
{
string[] values = new string[4]; //4 slots: days, hours, minutes, seconds
StringBuilder readableTime = new StringBuilder();
if (span.Days > 0)
{
if (span.Days == 1)
values[0] = span.Days.ToString() + " dag"; //day
else
values[0] = span.Days.ToString() + " dagen"; //days
readableTime.Append(values[0]);
readableTime.Append(", ");
}
else
values[0] = String.Empty;
if (span.Hours > 0)
{
if (span.Hours == 1)
values[1] = span.Hours.ToString() + " uur"; //hour
else
values[1] = span.Hours.ToString() + " uren"; //hours
readableTime.Append(values[1]);
readableTime.Append(", ");
}
else
values[1] = string.Empty;
if (span.Minutes > 0)
{
if (span.Minutes == 1)
values[2] = span.Minutes.ToString() + " minuut"; //minute
else
values[2] = span.Minutes.ToString() + " minuten"; //minutes
readableTime.Append(values[2]);
readableTime.Append(", ");
}
else
values[2] = string.Empty;
if (span.Seconds > 0)
{
if (span.Seconds == 1)
values[3] = span.Seconds.ToString() + " seconde"; //second
else
values[3] = span.Seconds.ToString() + " seconden"; //seconds
readableTime.Append(values[3]);
}
else
values[3] = string.Empty;
return readableTime.ToString();
}//end SpanToReadableTime
This is a pain in VS 2010, here's my workaround solution.
public string DurationString
{
get
{
if (this.Duration.TotalHours < 24)
return new DateTime(this.Duration.Ticks).ToString("HH:mm");
else //If duration is more than 24 hours
{
double totalminutes = this.Duration.TotalMinutes;
double hours = totalminutes / 60;
double minutes = this.Duration.TotalMinutes - (Math.Floor(hours) * 60);
string result = string.Format("{0}:{1}", Math.Floor(hours).ToString("00"), Math.Floor(minutes).ToString("00"));
return result;
}
}
}
The Substring method works perfectly when you only want the Hours:Minutes:Seconds. It's simple, clean code and easy to understand.
var yourTimeSpan = DateTime.Now - DateTime.Now.AddMinutes(-2);
var formatted = yourTimeSpan.ToString().Substring(0,8);// 00:00:00
Console.WriteLine(formatted);
No one has shown approach with decimal format specifier which is my favorite one, especially when used with string interpolation - https://learn.microsoft.com/en-us/dotnet/standard/base-types/standard-numeric-format-strings?redirectedfrom=MSDN#decimal-format-specifier-d
For example:
$"{time.Hours:D2}:{time.Minutes:D2}:{time.Seconds:D2}.{time.Milliseconds:D3}"
// Sample output: 00:00:09.200
You can of course wrap it up in some helper method.
Here is my version. It shows only as much as necessary, handles pluralization, negatives, and I tried to make it lightweight.
Output Examples
0 seconds
1.404 seconds
1 hour, 14.4 seconds
14 hours, 57 minutes, 22.473 seconds
1 day, 14 hours, 57 minutes, 22.475 seconds
Code
public static class TimeSpanExtensions
{
public static string ToReadableString(this TimeSpan timeSpan)
{
int days = (int)(timeSpan.Ticks / TimeSpan.TicksPerDay);
long subDayTicks = timeSpan.Ticks % TimeSpan.TicksPerDay;
bool isNegative = false;
if (timeSpan.Ticks < 0L)
{
isNegative = true;
days = -days;
subDayTicks = -subDayTicks;
}
int hours = (int)((subDayTicks / TimeSpan.TicksPerHour) % 24L);
int minutes = (int)((subDayTicks / TimeSpan.TicksPerMinute) % 60L);
int seconds = (int)((subDayTicks / TimeSpan.TicksPerSecond) % 60L);
int subSecondTicks = (int)(subDayTicks % TimeSpan.TicksPerSecond);
double fractionalSeconds = (double)subSecondTicks / TimeSpan.TicksPerSecond;
var parts = new List<string>(4);
if (days > 0)
parts.Add(string.Format("{0} day{1}", days, days == 1 ? null : "s"));
if (hours > 0)
parts.Add(string.Format("{0} hour{1}", hours, hours == 1 ? null : "s"));
if (minutes > 0)
parts.Add(string.Format("{0} minute{1}", minutes, minutes == 1 ? null : "s"));
if (fractionalSeconds.Equals(0D))
{
switch (seconds)
{
case 0:
// Only write "0 seconds" if we haven't written anything at all.
if (parts.Count == 0)
parts.Add("0 seconds");
break;
case 1:
parts.Add("1 second");
break;
default:
parts.Add(seconds + " seconds");
break;
}
}
else
{
parts.Add(string.Format("{0}{1:.###} seconds", seconds, fractionalSeconds));
}
string resultString = string.Join(", ", parts);
return isNegative ? "(negative) " + resultString : resultString;
}
}
If you want the duration format similar to youtube, given the number of seconds
int[] duration = { 0, 4, 40, 59, 60, 61, 400, 4000, 40000, 400000 };
foreach (int d in duration)
{
Console.WriteLine("{0, 6} -> {1, 10}", d, d > 59 ? TimeSpan.FromSeconds(d).ToString().TrimStart("00:".ToCharArray()) : string.Format("0:{0:00}", d));
}
Output:
0 -> 0:00
4 -> 0:04
40 -> 0:40
59 -> 0:59
60 -> 1:00
61 -> 1:01
400 -> 6:40
4000 -> 1:06:40
40000 -> 11:06:40
400000 -> 4.15:06:40
I wanted to return a string such as "1 day 2 hours 3 minutes" and also take into account if for example days or minuttes are 0 and then not showing them. thanks to John Rasch for his answer which mine is barely an extension of
TimeSpan timeLeft = New Timespan(0, 70, 0);
String.Format("{0}{1}{2}{3}{4}{5}",
Math.Floor(timeLeft.TotalDays) == 0 ? "" :
Math.Floor(timeLeft.TotalDays).ToString() + " ",
Math.Floor(timeLeft.TotalDays) == 0 ? "" : Math.Floor(timeLeft.TotalDays) == 1 ? "day " : "days ",
timeLeft.Hours == 0 ? "" : timeLeft.Hours.ToString() + " ",
timeLeft.Hours == 0 ? "" : timeLeft.Hours == 1 ? "hour " : "hours ",
timeLeft.Minutes == 0 ? "" : timeLeft.Minutes.ToString() + " ",
timeLeft.Minutes == 0 ? "" : timeLeft.Minutes == 1 ? "minute " : "minutes ");

How to convert the timestamp from 24 hr format to 12 hr format in C#?

I want to convert to timestamp in 24hrs fromat to 12 hrs format.Here is my code with output mentioned in braces.
date = Dyear + "" + Dmonth + "" + Dday + " " + strhour+""+strminute+""+"00"; (20130628 142900)
DateTime dt = new DateTime(Convert.ToInt32(Dyear), Convert.ToInt32(Dmonth), Convert.ToInt32(Dday), Convert.ToInt32(strhour), Convert.ToInt32(strminute), 00);(6/28/2013 2:29:00 PM)
TimeSpan ts = dt.Subtract(new DateTime(1970, 01, 01, 00, 00, 00));(15884.14:29:00)
String sTimeStamp = ts.TotalMilliseconds.ToString("0"); (1372429740000)
the above sTimeStamp will be in MM/DD/YYYY HH:MM:ttt format(06/28/2013 19:59:000) like "1372429740".
I want to display the time stamp in 12 hr format like MM/DD/YYYY hh:mm:ttt format(06/28/2013 07:59:000) like "1372386540"
Bear in mind that the format you refer is just for displaying purposes. If you want to account for this modification in your calculations (putting 2 instead of 14), a 12h lag would appear.
If you just want to display 6/28/2013 2:29:00, you can use the following string (the calculated miliseconds will not be affected):
string sTimeStamp = dt.ToString("MM/dd/yyyy hh:mm:ss tt");
If what you want is performing this change during the time calculations (not sure about the reason for doing that), you have to modify the way in which dt is generated (this time, the calculated milisenconds will be affected: 12h lag with respect to the option above):
DateTime dt = new DateTime(Convert.ToInt32(Dyear), Convert.ToInt32(Dmonth), Convert.ToInt32(Dday), Convert.ToInt32(new DateTime(2000, 1, 1, Convert.ToInt32(strhour), 0, 0).ToString("hh:mm tt").Split(':')[0]), Convert.ToInt32(strminute), 0);
In this second case, dt will always be formed on account of the "12h understanding" of the input value; for example: it will account for 2(am) if strhour is either 2 or 14.
internal static string ConvertTo_12_Format(string str)
{
//using system function
DateTime dt = DateTime.ParseExact(str, "HH:mm", System.Globalization.CultureInfo.InvariantCulture);
string s = dt.ToString("hh:mm");
//using logic
StringBuilder sb = new StringBuilder();
int h1 = (int)str[0] - '0';
int h2 = (int)str[1] - '0';
string Meridien;
int hh = h1 * 10 + h2;
if (hh < 12)
{
Meridien = "AM";
}
else
Meridien = "PM";
hh %= 12;
int c1 = (int)str[3] - '0';
int c2 = (int)str[4] - '0';
if (hh == 0)
{
sb.Append("12:");
//18:30
// Printing minutes and seconds
sb.Append(c1.ToString() + c2.ToString());
}
else
{
if(hh < 10)
{
sb.Append("0" + hh + ":");
sb.Append(c1.ToString() + c2.ToString());
}else
{
sb.Append(hh + ":");
sb.Append(c1.ToString() + c2.ToString());
}
}
sb.Append(" "+Meridien);
return sb.ToString();
}

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.

Refactor for Speed: Convert To a Date

I work for myself, I am a self-employed coder and as a result I don't have the luxury of code reviews or the ability to improve based upon peer programming. I am going to use this as an exercise to see if the StackOverflow community might help to review a simple method which i've written;
internal static DateTime CONVERT_To_DateTime(int binDate)
{
// 3/10/2008 = 1822556159
// 2/10/2008 = 1822523391
// 1/10/2008 = 1822490623
// 30/09/2008 = 1822392319
// 29/09/2008 = 1822359551
// September 30th 2008
// 1822392319 = 0x6c9f7fff
// 0x6c = 108 = 2008 (based on 1900 start date)
// 0x9 = 9 = September
// 0xf7fff - take top 5 bits = 0x1e = 30
// October 1st 2008
// 1822490623 = 0x6ca0ffff
// 0 x6c = 108 = 2008
// 0 xa = 10 = October
// 0x0ffff - take top 5 bits = 0x01 = 1
// OR using Binary (used by this function)
// a = 1822556159 (3/10/2008)
// 1101100 1010 00011 111111111111111
// b = 1822523391 (2/10/2008)
// 1101100 1010 00010 111111111111111
// c = 1822490623 (1/10/2008)
// 1101100 1010 00001 111111111111111
// D = 1822392319 (30/09/2008)
// 1101100 1001 11110 111111111111111
// Excess 111111 are probably used for time/seconds which
// we do not care for at the current time
var BaseYear = 1900;
// Dump the long date to binary
var strBinary = Convert.ToString(binDate);
// Calculate the year
var strBYear = strBinary.Substring(0, 7);
var iYear = Convert.ToInt32(strBYear, 2) + BaseYear;
// Calculate the month
var strBMonth = strBinary.Substring(7, 4);
var iMonth = Convert.ToInt32(strBMonth, 2);
// Calculate the day
var strBDay = strBinary.Substring(11, 5);
var iDay = Convert.ToInt32(strBDay, 2);
// ensure that month and day have two digits
var strDay = iDay < 10 ? "0" + iDay : iDay.ToString();
var strMonth = iMonth < 10 ? "0" + iMonth : iMonth.ToString();
// Build the final date
var convertedDate = iYear + strMonth + strDay;
return DateTime.ParseExact(convertedDate, "yyyyMMdd", null);
}
This is a method that takes a numeric representation of a date and converts it to a DateTime DataType. I would like the method to be reviewed to acheive the fastest possible execution time because it's being executed within a loop.
Any comments on the method is appreciated as this will be an exercise for me. i look forward to some responses.
Instead of converting to a string, then to integers, then to string, then to date, just get the integers by shifting and masking, and create the DateTime value directly from the integer values:
binDate >>= 15;
int day = binDate & 31;
binDate >>= 5;
int month = binDate & 15;
binDate >>= 8;
int year = binDate + 1900;
return new DateTime(year, month, day);
You're doing string manipulations. This is true performance killer when used in tight loops.
static DateTime ToDateTime(int value)
{
var year = (int)((value & 0xff000000) >> 24);
var month = (value & 0xf00000) >> 20;
var day = (value & (0xf8000)) >> 15;
return new DateTime(1900 + year, month, day);
}
Here's how you do that. First, take 1822490623 and convert it to binary:
0110 1100 1010 0000 1111 1111 1111 1111
This is a mask for year:
f f 0 0 0 0 0 0
This is for month:
0 0 f 0 0 0 0 0
And this is for day:
0 0 0 f 8 0 0 0
"Year" value has to be shifted right by 6 * 4 bits, "month" - by 5 * 4, and "day" - by 3 * 4 + 3 bits.
Welcome to the community, Phillis. :)
Anton is correct, your string manipulations are going to be slow. Because it looks like you're using the parameter as a bitfield, I'd suggest looking into the various (much faster) bit operators: <<, >>, &, |, and ~. It looks like you're trying to do binary manipulation, so use the operators built for it.
E.g. (untested, just off the cuff):
You start with a value of 0x6c9f7fff. The high order byte makes up the year. To mask out everything that isn't the year, do something like:
int year = ((binDate & 0xFF000000) >> 24) + BaseYear;
Likewise, the next 4 bits are the month, so:
int month = (binDate & 0x00F00000) >> 20;
int date = (binDate & 0x000F8000) >> 15;
return new DateTime(year, month, date);
I will suggest you to find the C/C++ code which does similar job; then port it into C#

Categories