AddDays() not working within a while loop - c#

Is there anything that stops the DateTime AddDays() method that doesn't run within a while loop. I have this simple bit of code;
DateTime last_day = monthCalendar2.SelectionRange.End;
DateTime first_day = new DateTime(year, month, day);
//Insert dates into vector
while (first_day != last_day)
{
dates.Add(first_day);
first_day.AddDays(1);
}
I step through the program and first_day never changes, anyone know why?!

The reason being is that DateTime is Immutable, this means that you can't directly modify it and instead need to create a new instance of it. Strings are another type that behave in this way which you may be more used to.
first_day = first_day.AddDays(1);

DateTime is immutable. You should do
first_day = first_day.AddDays(1);
UPDATE:
If you check DateTime.AddDays method description: Returns a new System.DateTime that adds the specified number of days to the value of this instance. That relates to all operations (such as Add, Substract, AddHours etc) on DateTime structure - any calculation does not modify the value of the structure. Instead, the calculation returns a new DateTime structure whose value is the result of the calculation. That's because DateTime is immutable struct. I.e. instance value cannot be changed after it was created.

DateTime can't be changed, so instead do.
first_day = first_day.AddDays(1);

Related

DateTime change timezone without converting

I am passed a DateTime object and a string timezone variable separately. Is there a way to cast this DateTime as the timezone in the string without "converting"(changing the actual time)?
If your time zone string is very specifically one of the system-defined strings, you can definitely do this. The easiest way is to make the assumption that the DateTime passed in is already in UTC, and that the string passed in is one of the Id values listed in TimeZoneInfo.GetSystemTimeZones(). Your function would look something like this:
public DateTime ConvertUtcDateTime(DateTime utcDateTime, string timeZoneId)
{
var tz = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId);
var convertedDateTime = TimeZoneInfo.ConvertTimeFromUtc(utcDateTime, tz);
return convertedDateTime;
}
This would create a "new" DateTime value, and your original utcDateTime value would be unchanged. If you can't assume that the DateTime value is UTC, you'll have to require both the source and destination time zones and your function would change slightly:
public DateTime ConvertDateTime(DateTime currentDateTime, string sourceTimeZoneId, string destinationTimeZoneId)
{
var tzSource = TimeZoneInfo.FindSystemTimeZoneById(sourceTimeZoneId);
var tzDestination = TimeZoneInfo.FindSystemTimeZoneById(destinationTimeZoneId);
var convertedDateTime = TimeZoneInfo.ConvertTime(currentDateTime, tzSource, tzDestination);
return convertedDateTime;
}
Keep in mind that in both of these functions, you need to test if the time zone returned by TimeZoneInfo.FindSystemTimeZoneById is not null. If it is, your input string was bad and you will need to handle that. An exception would likely work well there, but I don't know your needs.
Edit:
As an afterthought, if your strings aren't exactly the same as the Id values from TimeZoneInfo.GetSystemTimeZones(), but they do kind of match up one-to-one, you could make some kind of Dictionary<string, string> to map your time zone strings to the system's Id values and run from that. That's a good bit of hard-coding, though, but sometimes you need something like this if your inputs can't be changed.
DateTime itself is immutable in C# so you can't really change it like you are wanting to.
Your best bet would be to store the object as a UTC DateTime and then based on the timezone string you are passed, add or subtract time from that to "correct" the UTC time stamp.
Use UTC Time.
https://time.is/UTC
To implelent it, follow this code.
var currentDate = DateTime.SpecifyKind(DateTime.UtcNow, DateTimeKind.Utc);

why datetime change to 1st Jan in 16 year ago does not show year part properly?

i want to set the date to 1st of Jan 16 years ago from today's date. I used the code
DateTime dtm = new DateTime(DateTime.Today.Year, 1, 1);
dtm.AddYears(-16);
dtpDOB.Value = dtm;// assign value to date time picker
but it shows the date value as 1/1/2014, why this does not set the year part back in 16 years?
thanks
dtm = dtm.AddYears(-16);
Just assign the value
According to the MSDN documentation, .AddYears will return a new DateTime object rather than modifying the existing instance. So change your line to
dtm = dtm.AddYears(-16);
The DateTime type is a struct. Because of that, its properties are immutable (they can't be changed post-constructor). structs are passed by value in C#.
Because of that, as a few other people have said, you need to reassign the value.
dtm = dtm.AddYears(-16);
It's just like a typical string operation in C#. When you call string.Replace(string, string), you need to capture the return value of the operation. The same is true for LINQ-y IEnumerable<T> operations.
Although that said, it seems like you'd be better off to just call the constructor appropriately.
dtpDOB.Value = new DateTime(DateTime.Today.Year - 16, 1, 1);

How to differentiate between DateTime, Date and Time

There are three styles of Date and Time that can go into a DateTime variable; DateTime, Date or Time. I would like to differentiate between them. How can I do so?
I am creating column filtering on a DataGrid. Depending if it is one of the three the filter will display a DateTime picker or a DatePicker or a Time picker.
This classification is not part of the struct. IOW there's no built-in way to do this, so it's up to you to pick the implementation you'd like.
It has been suggested to check if the TotalSeconds == 0, which may satisfy you, imo it's a wonderful solution, but I think it should be used with caution because it is limited. Because what if you want to have a time+date that points to the date when TotalSeconds that really is == 0. This approach will turn this into just a date automatically.
I suggest that if you do not associate this time with a date, choose TimeSpan and make your life so much easier. However I assume this is not the case.
So, if the time really is associated with a date, I suggest you simply make your own type that wraps a DateTime, plus a boolean flag that will answer your question: is it just a date or date+time?.
This is obvious but I simply must say this anyways: if you do take this approach - encapsulate & hide!
If you expose DateTime as a field, an end-user might change the time of a date, expecting it to become date+time, yet the flag will not follow along. So don't just make a wrapper, make your own type that just uses DateTime internally.
There is no absolute way to differentiate. A DateTime always has a date portion and a time portion. If you create a DateTime from just a date then the time portion will be zeroed to midnight, but there is no difference between that and a value that actually represents the stroke of midnight on that date. If you create a DateTime from just a time then the date portion will be equal to #1/01/0001#, but there's no difference between that and a value that actually represents a time on the first day of the new era.
One option is to assume that a DateTime with a non-zero time and a date of #1/01/0001# represents just a time and a value with a zeroed time portion represents just a date. With that in mind, you could add this extension:
public enum DateTimeType
{
Date,
Time,
DateAndTime
}
public static class DateTimeExtensions
{
private static readonly DateTime ZeroDate = new DateTime(1, 1, 1);
public static DateTimeType GetDateTimeType(this DateTime value)
{
if (value.TimeOfDay == TimeSpan.Zero)
{
return DateTimeType.Date;
}
if (value.Date == ZeroDate)
{
return DateTimeType.Time;
}
return DateTimeType.DateAndTime;
}
}
The only way to check if DateTime has a date value is to make it a nullable type.
So something like this:
DateTime? dt;
if(dt.HasValue) {
//has date
if(dt.Value.TimeOfDay.TotalSeconds == 0) {
// display datepicker
} else {
// display timepicker
}
} else {
// show date time picker
}
Other than that, a regular DateTime will always have a date value (if not time value, or both). That is because it's a struct, hence it is not nullable unless you "make" it so (by wrapping in Nullable, which is done either manually (Nullable<DateTime>) or much simpler - by appending ? to the type (DateTime?) as demonstrated above).
If you have an option to go with different datatype (other than DateTime), then I suggest looking at NodaTime (Microsoft should simply build this into CLR and drop their lame DateTime struct).
You can then have 3 nullable properties
LocalDate? Date;
LocalDateTime? DateTime;
LocalTime? Time;
So based on which prop has value, you show the appropriate control. Of course, you also need to set the appropriate property which I'm not sure if you have any control on.

Taking a DateTime value and only accepting time and vice versa

I'm currently developing an application to function as a todo - list and i was wondering how do i accept a Value from a date time box, but only use the value of the date, or the value of the time. I'm currently doing it like this.
DateTime ted = appointmentDateTimeDate.Value; //The date
DateTime at = appointmentDateTimeTime.Value; //The time
should i be doing this another way?
Use DateTime.Date property for date, and DateTime.TimeOfDay for time:
DateTime ted = appointmentDateTimeDate.Date; //The date
TimeSpan at = appointmentDateTimeTime.TimeOfDay; //The time
The BCL doesn't really separate dates and times nicely.
If you're happy to take a new external dependency, I'd like to plug my Noda Time library, which will let you separate things out clearly into LocalDate and LocalTime. To perform the conversion from a date/time picker you'd probably use:
var dateAndTime = LocalDateTime.FromDateTime(appointmentDateTimeDate.Value);
LocalDate date = dateAndTime.LocalDate;
LocalTime time = dateAndTime.LocalTime;
Like others pointed out a DateTime always has both a date and a time component. So although it's possible to save both independently using two DateTime, in most cases it's recommendable to save both together in a single DateTime instance.
You should see if you really need both values separated or if your application could combine both in one property, which will make things easier.
A DateTime value ALWAYS contains both the date and the time, whether you use both or not.
You can use the .Date property of a DateTime to get "just the date". it will still have a time value, but the time value will be midnight. You can also use the .TimeOfDay property to get the time portion, which will be a TimeSpan indicating the number of ticks since midnight.
I'm taking a leap here and assuming you're trying to set the date with one control an d the time with another in the UI. Here's a sample of some code we use to do this using an Ajax CalendarExtender attached to a textbox and a custom TimePicker control.
DateTime dt;
try
{
dt = Convert.ToDateTime(txtViewDate.Text).AddHours(txtViewTime.Hour).AddMinutes(txtViewTime.Minute);
if (txtViewTime.AmPm == MKB.TimePicker.TimeSelector.AmPmSpec.PM)
{
dt = dt.AddHours(12);
}
System.Diagnostics.Debug.WriteLine(dt.ToString());
}
catch (Exception)
{
// abort processing
return;
}

DateTime comparison, minus certain timeframe? c#

Say I have these two DateTime objects:
var dt1 = new DateTime(1900,12,1,1,1,1);
var dt2 = new DateTime(1900, 12, 1, 1, 59, 1);
Obviously if I do DateTime.Compare(dt1,dt2) the method will return a value indicating they do not equal the same (because of the 59/minute component).
If I only want comparison with precision restricted to a certain value (i.e. same day - dont care about hours/minutes etc) is the best way to do this just to rebuild each datetime object?
I.e.
DateTime.Compare(new DateTime(dt1.Year,dt1.Month,dt1.Day,1,1,1),new DateTime(dt2.Year,dt2.Month,dt2.Day,1,1,1))
or is there a smarter way to do this?
There is already a built in function to get the Date from a DateTime, namely the Date property:
DateTime.Compare(dt1.Date,dt2.Date)
In theory you could compare year, month and day in that order instead of building a new DateTime, but since DateTime is a small struct building it is rather cheap, causes no heap allocations etc. And the code is much more readable.
If you just want the same date, just compare the Date properties:
dt1.Date == dt2.Date
If you need down to the same hour, or up to the same month, you need to use the constructors as you've shown.
The same day is easy - just use the Date property:
dt1.Date.CompareTo(dt2.Date)
For other granularities you would probably need to manually build different values though.

Categories

Resources