DateTime.AddYear, AddMonth, AddDay, AddHour, AddMinute doesn't add? - c#

I have the following code:
DateTime endTime = new DateTime(01, 01, 01, 00, 00, 00);
endTime = endTime.AddYears(currentYear - 1);
endTime = endTime.AddMonths(currentMonth - 1);
endTime = endTime.AddDays(currentDay - 1);
hourToWaitTo = Convert.ToInt32(txtboxHourToWaitTo.Text);
minuteToWaitTo = Convert.ToInt32(txtboxMinuteToWaitTo.Text);
endTime = endTime.AddHours(hourToWaitTo);
endTime = endTime.AddMinutes(minuteToWaitTo);
But it doesn't add anything to endTime
EDIT1:
I set currentYear, currentMonth and currentDay like this:
int currentYear = Convert.ToInt32(DateTime.Now.ToString("yyyy"));
int currentMonth = Convert.ToInt32(DateTime.Now.ToString("MM"));
int currentDay = Convert.ToInt32(DateTime.Now.ToString("dd"));
hourToWaitTo and minuteToWaitTo is set by user in a textbox.
I want the user to set a time (e.g. 12:25) for the computer to shutdown at, and I also want a countdown to say how many hours:minutes:seconds left till shutdown. I have managed to do all of this, but i couldn't fix the above mentioned endTime problem.
SOLUTION:
The solution to this problem is very simple:
DateTime endTime = new DateTime(currentYear, currentMonth, currentDay, hourToWaitTo, minuteToWaitTo, 0);
I tried to do this earlier, but for some reason I was getting an error. To set those variables above I used:
int currentYear = Convert.ToInt32(DateTime.Now.ToString("yyyy"));
int currentMonth = Convert.ToInt32(DateTime.Now.ToString("MM"));
int currentDay = Convert.ToInt32(DateTime.Now.ToString("dd"));
and
int minuteToWaitTo = Convert.ToInt32(txtboxMinuteToWaitTo.Text);
int hourToWaitTo = Convert.ToInt32(txtboxHourToWaitTo.Text);
Thank you all for your help.

This is not a direct answer to your question - the code you've posted looks okay so there must be something else going on - but I'm wondering why you don't just do something like:
hourToWaitTo = Convert.ToInt32(txtboxHourToWaitTo.Text);
minuteToWaitTo = Convert.ToInt32(txtboxMinuteToWaitTo.Text);
DateTime endTime = new DateTime(currentYear, currentMonth, currentDay, hourToWaitTo, minuteToWaitTo, 0);

Code like this should be abolished:
int currentYear = Convert.ToInt32(DateTime.Now.ToString("yyyy"));
int currentMonth = Convert.ToInt32(DateTime.Now.ToString("MM"));
int currentDay = Convert.ToInt32(DateTime.Now.ToString("dd"));
You are checking the system clock three times, pulling out partial values, serializing to a string, parsing that string, and then using each part. Lots of work for nothing.
All you really need is:
DateTime endTime = DateTime.Today.AddHours(hourToWaitTo)
.AddMinutes(minuteToWaitTo);
You should consider the kind of the dates you are working with. When you construct a DateTime using the constructors, you are getting a .Kind of Unspecified unless you specifically tell it what kind of date you want. It's more appropriate in your scenario to be working with a local date, which you will get with DateTime.Today or DateTime.Now.
Also be aware that since you are asking the user for a local time, but allowing them to enter the time components, that time may be invalid or ambiguous. This happens during daylight savings time transitions. You can validate the user input with TimeZoneInfo.Local.IsInvalidTime() or TimeZoneInfo.Local.IsAmbiguousTime(). In the case of ambiguous time, you will need to ask your user "Before or after the daylight savings transition?" or something similar.
And finally, if there's any chance that the user is NOT in the same timezone as the computer in question, then you have a lot of more work to do. You should consider using DateTimeOffset instead, and you will need to capture the intended offset or timezone of the shutdown. Another approach would be to convert the time to the UTC time of the shutdown event. Review this article for more details and best practices.

new DateTime(year,month,day,hour,minute,0)
?

Related

Easily calculate the time before midnight in C#

I have a function which is already compact, i wanted to know if there was better (like a DateTime functionality already included).
Currently i use this:
DateTime today = DateTime.Now;
DateTime tomorrow = new DateTime(today.Year, today.Month, today.Day, 0, 0, 0).AddDays(1);
double remaining = (tomorrow - today).TotalMilliseconds;
Thank for reading.
You can simplify the tomorrow value by just doing this and taking the benefit of DateTime.Today:
DateTime tomorrow = DateTime.Today.AddDays(1);
So your code will be easy to read:
DateTime today = DateTime.Now;
DateTime tomorrow = DateTime.Today.AddDays(1);
double remaining = (tomorrow - today).TotalMilliseconds;
You can create extension for DateTime
public static class DateExtensions
{
public static double GetNextDayRemainingMs(this DateTime dateTime)
{
return (dateTime.AddDays(1).Date - dateTime).TotalMilliseconds;
}
}
Usage
DateTime.Now.GetNextDayRemainingMs();
You can try following code
(DateTime.Today.AddDays(1)-DateTime.Now).TotalMilliseconds
Instead of defining instance for tomorrow variable you can use .AddDate(1).Date property
.AddDate(1) will add one day to DateTime.Now and .Date property
will give you only date and sets time to 00.
DateTime today = DateTime.Now;
double remaining = (today.AddDate(1).Date - today).TotalMilliseconds;
Or (Elegant way)
You can use Today property of DateTime.
An object that is set to today's date, with the time component set to
00:00:00.
double remaining = (DateTime.Today.AddDays(1)-DateTime.Now).TotalMilliseconds

Timezone issue with UIDatePicker Date: 1 Hour Wrong

I'm having an issue with the Monotouch UIDatePicker being 1 hour behind. I think this is to do with Time Zones or something similar. I've tried explicitly setting the TimeZone and Locale of my UIDatePicker but this doesn't seem to be helping.
datePicker.Locale = NSLocale.CurrentLocale;
datePicker.TimeZone = NSTimeZone.LocalTimeZone;
In the ValueChanged handler the following line returns a value 1 hour earlier than the time selected in the user interface:
var date = DateTime.SpecifyKind((s as UIDatePicker).Date, DateTimeKind.Local).ToLocalTime();
In the ValueChanged Handler I've double checked that the Locale and TimeZone is the same as what was set. The TimeZone is Europe/Dublin and Locale en_US.
This information was retrieved by:
datePicker.Locale.LocaleIdentifier;
datePicker.DatePicker.TimeZone;
Is there another step I'm missing?
Thanks!
The date returned from DatePicker is in UTC format. There are several methods of converting UTC to local time. As this answer states ToLocalTime is the best one.
DateTime.SpecifyKind(datePicker.Date, DateTimeKind.Utc).ToLocalTime();
After var date = DateTime ..., add the following:
if (date.IsDaylightSavingTime ())
date = date.AddHours (1);
This magical code fixed all my problems with daylight savings and timezones. Write if you need help.
NSDate sourceDate = date;
NSTimeZone sourceTimeZone = new NSTimeZone ("UTC");
NSTimeZone destinationTimeZone = NSTimeZone.LocalTimeZone;
int sourceGMTOffset = sourceTimeZone.SecondsFromGMT (sourceDate);
int destinationGMTOffset = destinationTimeZone.SecondsFromGMT (sourceDate);
int interval = destinationGMTOffset - sourceGMTOffset;
var destinationDate = sourceDate.AddSeconds (interval);
var dateTime = new DateTime(2001, 1, 1, 0, 0,0).AddSeconds(destinationDate.SecondsSinceReferenceDate);
DescriptionLabel.Text = dateTime.ToString ("dd.MM.yyyy. HH:mm");
this.date = destinationDate;

Calculating start of day and start of month in UTC

I have users that can be in different timezones and I'm looking to determine the UTC value of the beginning of their days and their months. Inside an object, I have a method that attempts to do that; it looks like this:
private void SetUserStartTimesUTC()
{
DateTime TheNow = DateTime.UtcNow.ConvertUTCTimeToUserTime(this.UserTimezoneID);
DateTime TheUserStartDateUserTime = TheNow.Date;
DateTime TheUserStartMonthUserTime = new DateTime(TheNow.Year, TheNow.Month, 1);
DateTime TheUserEndMonthUserTime = TheUserStartMonthUserTime.AddMonths(1);
this.UserStartOfDayUTC = TheUserStartDateUserTime.ConvertUserTimeToUTCTime(this.UserTimezoneID);
this.UserStartOfMonthUTC = TheUserStartMonthUserTime.ConvertUserTimeToUTCTime(this.UserTimezoneID);
this.UserEndOfMonthUTC = TheUserEndMonthUserTime.ConvertUserTimeToUTCTime(this.UserTimezoneID);
}
And this method depends on two other extension methods that do the conversions between a user's time and UTC time
public static DateTime ConvertUserTimeToUTCTime(this DateTime TheUserTime, string TheTimezoneID)
{
TimeZoneInfo TheTZ = TimeZoneInfo.FindSystemTimeZoneById(TheTimezoneID);
DateTime TheUTCTime = new DateTime();
if (TheTZ != null)
{
DateTime UserTime = new DateTime(TheUserTime.Year, TheUserTime.Month, TheUserTime.Day, TheUserTime.Hour, TheUserTime.Minute, TheUserTime.Second);
TheUTCTime = TimeZoneInfo.ConvertTimeToUtc(UserTime, TheTZ);
}
return TheUTCTime;
}
public static DateTime ConvertUTCTimeToUserTime(this DateTime TheUTCTime, string TheTimezoneID)
{
TimeZoneInfo TheTZ = TimeZoneInfo.FindSystemTimeZoneById(TheTimezoneID);
DateTime TheUserTime = new DateTime();
if (TheTZ != null)
{
DateTime UTCTime = new DateTime(TheUTCTime.Year, TheUTCTime.Month, TheUTCTime.Day, TheUTCTime.Hour, TheUTCTime.Minute, 0, DateTimeKind.Utc);
TheUserTime = TimeZoneInfo.ConvertTime(UTCTime, TheTZ);
}
return TheUserTime;
}
Now I've been dealing with timezone issues for a while and I know that timezone issues can introduce off-by-one bugs that can be hard to detect.
Does my implementation of timezones seem to be correct or is there an edge case that will create some sort of off-by-one bug?
Thanks for your suggestions.
Your methods seem needlessly complicated, to be honest.
Why would you have a parameter called TheUTCTime and then create a UTC version of it? Shouldn't it already have a Kind of UTC? Even if it didn't, you would be better off using DateTime.SpecifyKind - currently when converting one way you wipe out the seconds, whereas converting the other way you don't... in both cases you wipe out any sub-second values.
Also:
TimeZoneInfo.FindSystemTimeZoneById never returns null
Returning new DateTime() (i.e. January 1st 0001 AD) if the time zone can't be found seems like a really poor way of indicating an error
There's no need to have a local variable in your conversion methods; just return the result of calling ConvertTime directly
Your "end of month" is really "start of the next month"; that may be what you want, but it's not clear.
Personally I would strongly advise you to avoid the BCL DateTime for all of this entirely. I'm entirely biased being the main author, but I'd at least hope that you'd find Noda Time more pleasant to work with... it separates out the idea of "date with no time component", "time with no date component", "local date and time with no specific time zone" and "date and time in a particular time zone"... so the type system helps you to only do sensible things.
EDIT: If you really have to do this within the BCL types, I'd write it like this:
private void SetUserStartTimesUTC()
{
DateTime nowUtc = DateTime.UtcNow;
TimeZoneInfo zone = TimeZoneInfo.FindSystemTimeZoneById(UserTimeZoneID);
// User-local values, all with a Kind of Unspecified.
DateTime now = TimeZoneInfo.ConvertTime(nowUtc, zone);
DateTime today = now.Date;
DateTime startOfThisMonth = todayUser.AddDays(1 - today.Day);
DateTime startOfNextMonth = startOfThisMonth.AddMonths(1);
// Now convert back to UTC... see note below
UserStartOfDayUTC = TimeZoneInfo.ConvertTimeToUtc(today, zone);
UserStartOfMonthUTC = TimeZoneInfo.ConvertTimeToUtc(startOfThisMonth, zone);
UserEndOfMonthUTC = TimeZoneInfo.ConvertTimeToUtc(startOfNextMonth, zone);
}
The extension methods you've added really don't provide much benefit, as you can see.
Now, the code mentions a "note" - you're currently always assuming that midnight always exists and is unambiguous. That's not true in all time zones. For example, in Brazil, on daylight saving changes forward, the time skips from midnight to 1am - so midnight itself is invalid, basically.
In Noda Time we fix this by having DateTimeZone.AtStartOfDay(LocalDate) but it's not as easy with the BCL.
For comparison, the equivalent Noda Time code would look like this:
private void SetUserStartTimesUTC()
{
// clock would be a dependency; you *could* use SystemClock.Instance.Now,
// but the code would be much more testable if you injected it.
Instant now = clock.Now;
// You can choose to use TZDB or the BCL time zones
DateTimeZone zone = zoneProvider.FindSystemTimeZoneById(UserTimeZoneID);
LocalDateTime userLocalNow = now.InZone(zone);
LocalDate today = userLocalNow.Date;
LocalDate startOfThisMonth = today.PlusDays(1 - today.Day);
LocalDate startOfNextMonth = startOfThisMonth.PlusMonths(1);
UserStartOfDayUTC = zone.AtStartOfDay(today);
UserStartOfMonthUTC = zone.AtStartOfDay(startOfThisMonth);
UserEndOfMonthUTC = zone.AtStartOfDay(startOfNextMonth);
}
... where the properties would be of type ZonedDateTime (which remembers the time zone). You could change them to be of type Instant (which is just a point in time) if you want, just chaining a ToInstant call for each property setter.

How to set current time to a value

I was just wondering if there is a way to get the current time and set it into a value.
If its 12:06 AM.. I want to get that time and set it into currentTime.
Example
float currentTime = 0;
currentTime = 12.06;
As others have mentioned, the DateTime class would be ideal for this, and to work out the difference between 2 date/times:
DateTime end = DateTime.Now;
DateTime start = new DateTime(2011, 12, 5, 12, 6,0);
double hours = (end - start).TotalHours;
The subtraction of DateTime objects results in a TimeSpan object that you can use to see the hours/minutes etc.
try DateTime class
DateTime dt = DateTime.Now;
Is this what you're looking for?
DateTime currentTime;
currentTime = DateTime.Now;
Don't use floats or strings. You can do all kinds of cool things using DateTime.
Here's how you'd get the hours that someone worked:
var clockIn = new DateTime(2011,12,4,9,0,0); // December 4th, 9 AM
var clockOut = new DateTime(2011,12,4,17,0,0); // December 4th, 5 PM
var duration = clockOut - clockIn; // TimeSpan
Console.Write(duration.TotalHours); // 8
A few people have mentioned how, but as a 'better' recommendation you should use
DateTime currentTime = DateTime.UtcNow
Otherwise you have issues when the clocks go back, if your timing code is run on those days. (plus it is far easier to alter the UTC time to local time than it is to convert a '1am' to UTC (as there will be two of them when the clocks go back)
Well if you really what it as a float then try:
var currentDate = DateTime.Now;
float currentTime = float.Parse((currentDate.Hour > 12 ? currentDate.Hour -12 :
currentDate.Hour) + "." + currentDate.Minute);
I wouldn't recommend comparing dates or time with floats. A better options would be to use timespans.
You should be using a Timespan instance for time related values, you can use the flexibility to get the required values like
TimeSpan ts = DateTime.Now.TimeOfDay;
ts.ToString("hh:mm") // this could be what you are looking for
You could then use ts.TotalHours which would give you fractional hours (as a double) else you could construct a string specifically using ts.Hours ..ts.Minutes play around and it could be prove useful.
Try the following:
DateTime StartTime=StartTime value;
DateTime CurrentTime=DateTime.Now;
TimeSpan dt = CurrentTime.Subtract(StartTime);
In dt you will get a working time period.
If you want to have the difference between two times, then do this:
DateTime dateOne = DateTime.Parse(enteredTime);
DateTime dateTwo = DateTime.Now;
TimeSpan difference = dateOne - dateTwo;

How to Handle Actual Time with Durations in C#?

What's the preferred approach to compare a complete DateTime instance with an hour, minute, and second which represents an actual time of day, with the ability to operate over those triplets (eg add hours, minutes seconds..)?
My current approach is something like
DateTime startHour = new DateTime(1900,1,1,12,25,43);
DateTime endHour = new DateTime(1900,1,1,13,45,32);
// I need to, say, know if a complete DateTime instance
// is later than startHour plus 15 minutes
DateTime now = DateTime.Now();
startHour = startHour.addMinutes(15);
if (now.CompareTo(new DateTime(now.Year, now.Month, now.Day, startHour.Hour,
startHour.Minute, startHour.Second)) > 0)
{
//I can do something now
}
This is very cumbersome and even failure prone. TimeSpans are not a solution as far as I can see, because they represent spans and aren't bound by the 24 hours limit (a TimeSpan of 56 hours 34 minutes is valid.)
What's the preferred approach for this type of calculations?
It's not at all clear what you mean by "is greater than startHour"... but taking
TimeSpan startHour = new TimeSpan(12, 25, 43);
if (endHour.TimeOfDay > startHour)
{
...
}
... works pretty simply.
By all means add argument checking to make sure that you don't specify a value for startHour which is < 0 or > 23 hours, but that's all pretty easy.
.NET's date and time API is quite primitive (even in 3.5) compared with, say, Joda Time - but in this particular case I think it's not too bad.
A little hint - .NET supports arithmetic operations on DateTime objects, and returns a TimeSpan object. Thus, you can do the following:
DateTime fromDate = ....
DateTime toDate = ....
TimeSpan diff = toDate - fromDate;
and you can expand this to:
DateTime fromDate = DateTime.Now;
DateTime toDate = DateTime.Now.addMinutes(x);
if ((toDate - fromDate).TotalMinutes > 15) {
...
}
You should use TimeSpan for startHour and endHour.
When comparing with now, you should "convert" them to a full DateTime or get the Time with DateTime.TimeOfDay as mentioned by Jon Skeet.
TimeSpan startHour = new TimeSpan(12, 25, 43);
DateTime now = DateTime.Now;
if (now.CompareTo(DateTime.Today.Add(startHour)) > 0) {
//...
}
or
TimeSpan startHour = new TimeSpan(12, 25, 43);
DateTime now = DateTime.Now;
if (now.TimeOfDay.CompareTo(startHour) > 0) {
//...
}
So you're only interested in the time component of the date.
if(DateTime.Now.TimeOfDay > startHour.TimeOfDay)
{
// do stuff
}
What's wrong with doing this?

Categories

Resources