My company has support staff that are available from 7am to 7pm CST, and we try to reflect that on our website by showing either a button to initiate a chat, or a message saying that they are not available. The support staff are located in Central time, but the servers that our site is hosted on could be in any time zone. (I work remotely and when I run the project locally on my machine, it's in Eastern time for example)
Right now there is a bug where this says you are outside of the time range at 6pm CST, which is an hour too early. This appears to be because my time range in CST actually spans 2 days in UTC time (1pm until 1am the next day), and i am basingmy times off of the UTC date. I know this is what's causing the problem, but I'm not sure of the best way to resolve this.
Here's the code, converted from a function that returns a boolean into a console app to log out eh values.
View the code below, or use it here: https://dotnetfiddle.net/Hzhv8n
//=================================================================================================
//Get hours & days of operation
//These normally come from a config file, but hardcoding them here for demo
int availableChatStartHour = 13; //7am CST in UTC time
int availableChatDuration = 12; //12 hours from 7am CST is 7pm CST
string[] availableDaysForChat = "monday,tuesday,wednesday,thursday,friday".ToUpper().Split(',');
//=================================================================================================
//The current timezone-agnostic time.
var now = DateTime.UtcNow;
//Convert times to a date object
//-------------------------------------------------
//I THINK THIS IS WHERE MY BUG IS
var startTime = new DateTime(now.Year, now.Month, now.Day, availableChatStartHour, 0, 0, DateTimeKind.Utc);
//-------------------------------------------------
var endTime = startTime.AddHours(availableChatDuration);
//Company HQ is located in the central time zone
//The central time zone can experience daylight saving time.
//We need to determine if DST is currently active or not in CST
var cstZone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var cstTime = TimeZoneInfo.ConvertTimeFromUtc(now, cstZone);
var isDstActive = cstZone.IsDaylightSavingTime(cstTime);
//If DST is active, then we need to subtract an hour from the start and end times.
if (isDstActive)
{
startTime = startTime.AddHours(-1);
endTime = endTime.AddHours(-1);
}
//Determine if the day of the week (in CST time) is available for chat
var isDayAvilable = availableDaysForChat.Contains(cstTime.DayOfWeek.ToString().ToUpper());
//Make sure the time of day is within the acceptable range
var isAfterStartTime = now > startTime;
var isBeforeEndTime = now < endTime;
//Now take everything into account and see if the chat is available
//return isDayAvilable && isAfterStartTime && isBeforeEndTime;
Console.WriteLine("NOW: "+ now);
Console.WriteLine("START: "+ startTime);
Console.WriteLine("END: "+ endTime);
Console.WriteLine("-------------------------------------");
Console.WriteLine("Day Available: "+isDayAvilable);
Console.WriteLine("Is After Start Time: "+ isAfterStartTime);
Console.WriteLine("Is Before End Time: "+ isBeforeEndTime);
Console.WriteLine("-------------------------------------");
Console.WriteLine("FINAL RESULT: "+ (isDayAvilable && isAfterStartTime && isBeforeEndTime));
Any ideas on how to make this work as it should?
You're doing far more than you need to. Personally I'd use my Noda Time project, but all of this can be done fairly easily with the BCL, using TimeZoneInfo.ConvertTime
:
var zone = TimeZoneInfo.FindSystemTimeZoneById("Central Standard Time");
var centralTime = TimeZoneInfo.ConvertTime(DateTime.UtcNow, zone);
if (centralTime.Hour >= 7 && centralTime.Hour < 21 &&
centralTime.DayOfWeek >= DayOfWeek.Monday &&
centralTime.DayOfWeek <= DayOfWeek.Friday)
{
// Yes, you have support staff
}
else
{
// Nope, let the answerphone handle it
}
See more on this question at Stackoverflow