How to pass variables as parameters with DateTime - c#

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));

Related

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);

I want to covert julian date(YYJJJ format) to any normal date format(MMDDYY) using c#. Is there any defined function for that?

Hi I have julian date string YYJJJ format. eg 05365(31st dec 2005). I want to covert to MMDDYY format(123105).
Is there any defined function for that in?
I faced same problem as I was try to convert dates from BACS 18 standard to a String. I couldn't find ready solution to this problem so I wrote this function:
private String bacsDateConvert(String bacsFormatDate)
{
int dateYear = Convert.ToInt16(bacsFormatDate.Substring(1, 2));
int dateDays = Convert.ToInt16(bacsFormatDate.Substring(3, 3));
DateTime outputDate = new DateTime();
outputDate = Convert.ToDateTime("31-12-1999");
outputDate = outputDate.AddYears(dateYear);
outputDate = outputDate.AddDays(dateDays);
String outputString = outputDate.ToString("yyyyMMdd");
return outputString;
}
//You may call it like this:
textBox4.Text = Convert.ToString(bacsDateConvert(bacsTxnValueDate));
You also may modify it slightly and easily make it return DateTime data type if you want to. I just needed to return a string in the above format.
First of all, there is no YY, JJJ and DD formats as a custom date and time format. One solution might be to split your string Year and DayOfYear part and create a DateTime with JulianCalendar class.
string s = "05365";
int year = Convert.ToInt32(s.Substring(0, 2));
// Get year part from your string
int dayofyear = Convert.ToInt32(s.Substring(2));
// Get day of years part from your string
DateTime dt = new DateTime(1999 + year, 12, 18, new JulianCalendar());
// Initialize a new DateTime one day before year value.
// Added 1999 to year part because it makes 5 AD as a year if we don't.
// In our case, it is 2004/12/31
dt = dt.AddDays(dayofyear);
// Since we have a last day of one year before, we can add dayofyear to get exact date
I initialized this new DateTime(.. part with 18th December because
From Julian Calendar
Consequently, the Julian calendar is currently 13 days behind the
Gregorian calendar; for instance, 1 January in the Julian calendar is
14 January in the Gregorian.
And you can format your dt like;
dt.ToString("MMddyy", CultureInfo.InvariantCulture) //123105
I honestly didn't like this way but this is the only one I can imagine as a solution.

Parsing times above 24 hours in C#

Suppose a time stamp (just time or date and time) where the time can roll over to the next day:
00:00:00 <- midnight
01:00:00 <- 1 AM
23:00:00 <- 11 PM
24:00:00 <- midnight, day + 1
25:00:00 <- 1 AM, day + 1
What would be a way to parse it easily into a C# DateTime that would perform the carry-over to the next day? In other words, "01:00:00" would become "0001-01-01 01:00:00" and "25:00:00" would become "0001-01-02 01:00:00".
EDIT:
I should mention that this fails miserably (i.e FormatException):
DateTime.ParseExact("0001-01-01 25:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture);
Since you're trying to represent a period of time from an arbitrary point, rather than as a specific date, perhaps you would be better off using the System.TimeSpan class? This allows you to set values of more than 24 hours in the constructor, and can be used with DateTime objects like this:
System.TimeSpan timestamp = new System.TimeSpan(25, 0, 0);
System.DateTime parsedDateTime = new DateTime(0, 0, 0);
parsedDateTime = parsedDateTime.Add(timestamp);
Console.WriteLine(parsedDateTime.ToString("yyyy-MM-dd HH:mm:ss")); //Output as "0001-01-02 01:00:00"
NOTE: Code is untested.
EDIT: In terms of parsing the strings, I can't think of any basic .NET objects that parse strings with values greater than 23 for the hour (since 25 is an invalid hour of the day), but assuming that the format is consistent, you could create a very simple string parsing routine (or even a regular expression) to read the values individually, and load the constructor manually.
If you have an existing DateTime value you can add to, you can always use a TimeSpan:
string dt = "25:00:00";
int hours = int.Parse(dt.Split(':')[0]);
TimeSpan ts = TimeSpan.FromHours(hours);
TimeSpan.Parse() doesn't work directly in this case because it complains (fair enough!) about the 25 in the hour notation.
If you want to code it out... this should be a starting point:
string dateString = "0001-01-01 25:00:00";
string[] parts = dateString.Split(' '); //now have '0001-01-01' and '25:00:00'
string datePart = parts[0]; // '0001-01-01'
string[] timeParts = parts[1].Split(':'); //now have '25', '00', and '00
DateTime initialDate = DateTime.ParseExact(datePart, "yyyy-MM-dd", CultureInfo.InvariantCulture);//use the date as a starting point
//use the add methods to get your desired datetime
int hours = int.Parse(timeParts[0]);
int minutes = int.Parse(timeParts[1]);
int seconds = int.Parse(timeParts[2]);
DateTime resultDate = initialDate.AddHours(hours)
.AddMinutes(minutes)
.AddSeconds(seconds);
Of course, it makes assumptions that the input is formatted properly and is parsable, etc..
In addition, you could definitely use timespan instead of the individual add methods for hour, minute, second as some other answers are..
In case nobody points out an out-of-the-box answer, here is a neat ActionScript class I wrote to parse time inputs (human input)...
https://github.com/appcove/AppStruct/blob/master/Flex/AppStruct/src/AppStruct/TimeInput.as
It would be very simple to port this to C#, and you could tweak the 24 hour logic to result in #days, #hours, #minutes.
Good luck!
You are specifying an invalid date. So not only can you not parse it, you cannot store it!
How about a nice TimeSpan object instead? (It also has a Parse() method.)
Alternatively, use a sscanf()-type function like the one at http://www.blackbeltcoder.com/Articles/strings/a-sscanf-replacement-for-net to extract each number separate. (Best if you have no control over the string format being read.)

Negative values in C# DateTime

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.

Categories