Having an issue whereby the date I wish to save is changing from the onscreen selected date if the users selects a timezone that is ahead x number of hours.
E.g. they choose UTC+2 Athens and date of 25/02/2016
from the calendar pop-up, then date recorded will be 24/02/2016
.
I've narrowed the reasoning down to the fact that the selected datetime is recorded as for example 25/02/2016 00:00:00
and with the 2 hour offset, this takes it to 24/02/2016 22:00:00
Having never worked with timezones before, or UTC dates/times, this is highly confusing.
Here is the code -
oObject.RefDate = itTimeAndDate.ParseDateAndTimeNoUTCMap(Request, TextBox_RefDate.Text);
if (!string.IsNullOrEmpty(oObject.TimeZoneDetails))
{
TimeZoneInfo oTimeZone = TimeZoneInfo.FindSystemTimeZoneById(oObject.TimeZoneDetails);
oObject.RefDate = itTimeAndDate.GetUTCUsingTimeZone(oTimeZone, oObject.RefDate);
}
RefDate
would equate to something like 25/02/2016 00:00:00
once returned from ParseDateAndTimeNoUTCMap
* (code below)*
static public itDateTime ParseDateAndTimeNoUTCMap(HttpRequest oTheRequest, string sValue)
{
DateTime? oResult = ParseDateAndTimeNoUTCMapNull(oTheRequest, sValue);
if (oResult != null)
return new itDateTime(oResult.Value);
return null;
}
/// <summary>
/// Translate a string that has been entered by a user to a UTC date / time - mapping using the
/// current time zone
/// </summary>
/// <param name="oTheRequest">Request context</param>
/// <param name="sValue">Date / time string entered by a user</param>
/// <returns>UTC date / time object</returns>
static public DateTime? ParseDateAndTimeNoUTCMapNull(HttpRequest oTheRequest, string sValue)
{
try
{
if (string.IsNullOrEmpty(sValue))
return null;
sValue = sValue.Trim();
if (string.IsNullOrEmpty(sValue))
return null;
if (oTheRequest != null)
{
const DateTimeStyles iStyles = DateTimeStyles.AllowInnerWhite | DateTimeStyles.AllowLeadingWhite | DateTimeStyles.AllowTrailingWhite;
// Create array of CultureInfo objects
CultureInfo[] aCultures = new CultureInfo[oTheRequest.UserLanguages.Length + 1];
for (int iCount = oTheRequest.UserLanguages.GetLowerBound(0); iCount <= oTheRequest.UserLanguages.GetUpperBound(0);
iCount++)
{
string sLocale = oTheRequest.UserLanguages[iCount];
if (!string.IsNullOrEmpty(sLocale))
{
// Remove quality specifier, if present.
if (sLocale.Contains(";"))
sLocale = sLocale.Substring(0, sLocale.IndexOf(';'));
try
{
aCultures[iCount] = new CultureInfo(sLocale, false);
}
catch (Exception) { }
}
else
{
aCultures[iCount] = CultureInfo.CurrentCulture;
}
}
aCultures[oTheRequest.UserLanguages.Length] = CultureInfo.InvariantCulture;
// Parse input using each culture.
foreach (CultureInfo culture in aCultures)
{
DateTime oInputDate;
if (DateTime.TryParse(sValue, culture.DateTimeFormat, iStyles, out oInputDate))
return oInputDate;
}
}
return DateTime.Parse(sValue);
}
catch (Exception)
{
}
return null;
}
Once returned from the above, the following lines are executed -
TimeZoneInfo oTimeZone = TimeZoneInfo.FindSystemTimeZoneById(oObject.TimeZoneDetails);
oObject.RefDate = itTimeAndDate.GetUTCUsingTimeZone(oTimeZone, oObject.RefDate);
It is within GetUTCUsingTimeZone
that the problem seems to occur to me.
static public itDateTime GetUTCUsingTimeZone(TimeZoneInfo oTimeZone, itDateTime oDateTime)
{
if (oDateTime == null || oTimeZone == null)
return oDateTime;
DateTime oLocal = DateTime.SpecifyKind(oDateTime.Value, DateTimeKind.Unspecified);
DateTime oResult = TimeZoneInfo.ConvertTimeToUtc(oLocal, oTimeZone);
return new itDateTime(oResult);
}
I have checked TimezoneInfo
for the offset value, and oResult
always equates to the oLocal param
- the offset. So 25/02/2016 00:00:00
with a 3 hour offset would equate to 24/02/2016 21:00:00
When the offset is -hours, it goes in the other direct, so oResult = oLocal + the offset
, if that makes sense. So the main issue of the date changing is not occurring in those instances.
Obviously this is not what I want. I want the date to be what the user has selected, for their timezone. Has anyone seen something like this before? Any possible solution?
I'm not entirely sure what I've done wrong.
Therefore, you must convert a DateTime value to UTC by calling the DateTime. ToUniversalTime method before formatting it. In contrast, DateTimeOffset values perform this conversion automatically; there is no need to call the DateTimeOffset.
In performing the conversion to local time, the method first converts the current DateTimeOffset object's date and time to Coordinated Universal Time (UTC) by subtracting the offset from the time. It then converts the UTC date and time to local time by adding the local time zone offset.
DateTime currentTime = TimeZoneInfo. ConvertTime(DateTime. Now, TimeZoneInfo. FindSystemTimeZoneById("Central Standard Time"));
If you need to maintain the correct timezone, you should be using the DateTimeOffset
type instead of DateTime
type.
DateTimeOffset
maintains the offset from UTC so you never lose your timezone information and has a lot of useful methods like
UtcDateTime
From the horses mouth:
https://msdn.microsoft.com/en-us/library/system.datetimeoffset(v=vs.110).aspx
https://docs.microsoft.com/en-us/dotnet/standard/datetime/choosing-between-datetime
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With