Negative values in C# DateTime - c#

Is there a way to set negative values when calling the DateTime constructor.
like this:
DateTime date = new DateTime(2011, 2, -1);
would be the same as:
DateTime date = new DateTime(2011, 1, 31);
I know this works in other languages, but the problem is that C# .net throws an exception when i'm doing this. Any ideas on how to do this in C# .net?

Use
DateTime date = new DateTime(2011, 2,1).AddDays(-1);

You can't. If you want to get the last day of the month, you should either start off with the start of the next month and then take off one day, or use DateTime.DaysInMonth(year, month).
Personally I'd use the second approach, as otherwise you have to make sure you handle finding the last day in December correctly by starting off with January 1st of the next year, for example. Here's the code I'd use:
DateTime date = new DateTime(year, month, DateTime.DaysInMonth(year, month));

A DateTime is always an absolute position in time. I think what you're searching for is a TimeSpan, which can also be negative.

Related

How to pass variables as parameters with DateTime

Currently writing some code and I want to use DateTime.Parse, passing a string specifying the format, but with some variables as well.
Examples:
DateTime first_day = DateTime.Parse("{0}/01/{1}", Today.Month - 1, Today.Year - 1);
DateTime first_day = DateTime.Parse("12/01/{0}", Today.Year - 1);
Is there a way to do this?
Do not use either string interpolation or manipulate variables passed to the constructor. Either will have the consequence of trying to created dates that do not exist.
For example, when today is July 31st, trying to create a date of June 31st will throw an FormatException when using DateTime.Parse, or an ArgumentOutOfRangeException when using the DateTime constructor.
Likewise, trying to create a date of February 29th will only work when the associated year is a leap year. 2020-02-29 is valid, but 2019-02-29 is not.
Also, passing a date in January such as 2020-01-01 would try to create a date in month 0 (2019-00-01), which is also invalid.
Instead, use the AddYears and/or AddMonths methods:
DateTime first_day = DateTime.Today.AddYears(-1).AddMonths(-1);
DateTime second_day = DateTime.Today.AddYears(-1);
These will correctly move back to a valid date. July 31st - 1 month becomes June 30th. Feb 29th 2020 - 1 year becomes Feb 28th 2019, etc.
If you need to snap to the first of the month, then you could do something like this:
DateTime dt = DateTime.Today.AddYears(-1).AddMonths(-1);
DateTime first_day = new DateTime(dt.Year, dt.Month, 1);
(All months have a day 1.)
You can use string interpolation (came with C# 6.0 version) like;
DateTime first_day = DateTime.Parse($"{Today.Month - 1}/01/{Today.Year - 1}");
and
DateTime first_day = DateTime.Parse($"12/01/{Today.Year - 1}");
without any parameter needs in your DateTime.Parse methods. This method does not support composite formatting, so what you do is not possible.
You can use new DateTime(Int32, Int32, Int32) constructor also as Ed commented which takes year, month and day as a parameter.
By the way, as Matt mentioned, these Month-1 calculations is an anti pattern they can lead you to some dates that doesn't exists. See his answer for more details.
You could use string.Format like that:
var first_day = DateTime.Parse(string.Format("{0}/01/{1}", DateTime.Today.Month - 1, DateTime.Today.Year - 1));

Insert time without the date into my database

I tried to insert into my MS Access database a specific format to see how just the "time" in my database behaves, but when I tried to show what I got the date also, but I want to insert just the time.
I tried to convert the datetime variable to specific format and insert that
DateTime starttime = Convert.ToDateTime(DateTime.Now.ToShortTimeString());
DateTime nstarttime = Convert.ToDateTime(starttime.ToString("HH:mm"));
06/04/2019 22:55:00 that what I got and I want just the time
without the date
Your main issue is, that in .Net the time part of a DateTime is not a DateTime but a TimeSpan:
DateTime dateTime = new DateTime(2019, 6, 4, 22, 55, 0);
TimeSpan timePart = dateTime.TimeOfDay;
In Access (VBA) however, a "time only" value is the time of the date of the VBA Date epoch which is 1899-12-30. Depending on how you insert the time in an Access table, you may have to apply the time part to the epoch to obtain a value like that Access would use:
DateTime dateTime = new DateTime(2019, 6, 4, 22, 55, 0);
TimeSpan timePart = dateTime.TimeOfDay;
DateTime vbaEpoch = new DateTime(1899, 12, 30);
DateTime vbaTime = vbaEpoch.AddTicks(timePart.Ticks);
Of course, when reading back the values, ignore the date part:
TimeSpan timeOfDay = vbaTime.TimeOfDay;
This has been answered so many times, but nevertheless here is the link to one of the discussions Link 1:
Please check also this Link 2 with may useful patterns
This detail is one of the actual examples provided on Link 1:
DateTime dt = DateTime.Parse("6/22/2009 07:00:00 AM");
dt.ToString("HH:mm"); // 07:00 // 24 hour clock // hour is always 2 digits
dt.ToString("hh:mm tt"); // 07:00 AM // 12 hour clock // hour is always 2 digits
dt.ToString("H:mm"); // 7:00 // 24 hour clock
dt.ToString("h:mm tt"); // 7:00 AM // 12 hour clock
Hope this helps!
Cheers and happy coding!

Turn wrong date string to nearest valid one

For example I have 31.09.2017 (which is NON existent date) and that string's DateTime.ParseExact("31.09.2017", "dd.MM.yyyy", null); returns System.FormatException exception. Is there a way to turn 31.09.2017 into 30.09.2017 and do the same for all such wrong dates? For example like "round" works: to move to previous month's last day or next month's first day.
You can use the following technique :
DateTime temp;
if (!DateTime.TryParse("31.09.2017", out temp))
temp = GetValidDate("31.09.2017");
DateTime GetValidDate(string _date)
{
int day, year, month;
day = int.Parse(_date.Substring(0, 2));
month = int.Parse(_date.Substring(3, 2));
year = int.Parse(_date.Substring(6, 4));
return new DateTime(year, month, Math.Min(day, DateTime.DaysInMonth(year, month)));
}
The result may be unpredictable but your could split parts, convert to an int, then ensure that each part is within the correct range, then create a new string to parse. I suspect you only need to do this for the first 2 parts (dd and MM) and if outside of the range just set to the closest bounding value.
You can write a custom format provider and use it with DateTime.ParseExact however it may not work across cultures and may still throw exceptions like The DateTime represented by the string is not supported in calendar System.Globalization.GregorianCalendar. depending on how you implement.
DateTime.ParseExact Method (String, String, IFormatProvider)
An example.

Generate Date Time offset

I have DateTimeOffset input param. Need to create other DateTimeOffset param which Month is 2 month less than from input:
//DateTimeOffset input;
DateTimeOffset modified = new DateTimeOffset(input.Year,
input.Month - 2, input.Day,
input.Hour, input.Minute,
input.Second, input.Millisecond,
input.Offset);
I get an exception
Year, Month, and Day parameters describe an un-representable DateTime.
What is wrong? - the month is 4. S0 4-2 = 2 is valid
Thanks
I think the month is a red herring, it's probably more likely your day is above 28 which means you are trying to create a date like 30th Feb (which doesn't exist!).
Use the AddMonths method instead
DateTimeOffset modified = input.AddMonths(-2);

TimeSpan to DateTime conversion

I want to convert a Timespan to Datetime. How can I do this?
I found one method on Google:
DateTime dt;
TimeSpan ts="XXX";
//We can covnert 'ts' to 'dt' like this:
dt= Convert.ToDateTime(ts.ToString());
Is there any other way to do this?
It is not very logical to convert TimeSpan to DateTime. Try to understand what leppie said above. TimeSpan is a duration say 6 Days 5 Hours 40 minutes. It is not a Date. If I say 6 Days; Can you deduce a Date from it? The answer is NO unless you have a REFERENCE Date.
So if you want to convert TimeSpan to DateTime you need a reference date. 6 Days & 5 Hours from when? So you can write something like this:
DateTime dt = new DateTime(2012, 01, 01);
TimeSpan ts = new TimeSpan(1, 0, 0, 0, 0);
dt = dt + ts;
While the selected answer is strictly correct, I believe I understand what the OP is trying to get at here as I had a similar issue.
I had a TimeSpan which I wished to display in a grid control (as just hh:mm) but the grid didn't appear to understand TimeSpan, only DateTime . The OP has a similar scenario where only the TimeSpan is the relevant part but didn't consider the necessity of adding the DateTime reference point.
So, as indicated above, I simply added DateTime.MinValue (though any date will do) which is subsequently ignored by the grid when it renders the timespan as a time portion of the resulting date.
TimeSpan can be added to a fresh DateTime to achieve this.
TimeSpan ts="XXX";
DateTime dt = new DateTime() + ts;
But as mentioned before, it is not strictly logical without a valid start date. I have encountered
a use-case where i required only the time aspect. will work fine as long as the logic is correct.
You need a reference date for this to be useful.
An example from
http://msdn.microsoft.com/en-us/library/system.datetime.add.aspx
// Calculate what day of the week is 36 days from this instant.
System.DateTime today = System.DateTime.Now;
System.TimeSpan duration = new System.TimeSpan(36, 0, 0, 0);
System.DateTime answer = today.Add(duration);
System.Console.WriteLine("{0:dddd}", answer);
Worked for me.
var StartTime = new DateTime(item.StartTime.Ticks);
If you only need to show time value in a datagrid or label similar, best way is convert directly time in datetime datatype.
SELECT CONVERT(datetime,myTimeField) as myTimeField FROM Table1
You could also use DateTime.FromFileTime(finishTime) where finishTme is a long containing the ticks of a time. Or FromFileTimeUtc.
An easy method, use ticks:
new DateTime((DateTime.Now - DateTime.Now.AddHours(-1.55)).Ticks).ToString("HH:mm:ss:fff")
This function will give you a date (Without Day / Month / Year)
A problem with all of the above is that the conversion returns the incorrect number of days as specified in the TimeSpan.
Using the above, the below returns 3 and not 2.
Ideas on how to preserve the 2 days in the TimeSpan arguments and return them as the DateTime day?
public void should_return_totaldays()
{
_ts = new TimeSpan(2, 1, 30, 10);
var format = "dd";
var returnedVal = _ts.ToString(format);
Assert.That(returnedVal, Is.EqualTo("2")); //returns 3 not 2
}
First, convert the timespan to a string, then to DateTime, then back to a string:
Convert.ToDateTime(timespan.SelectedTime.ToString()).ToShortTimeString();

Categories