围绕utc日期的问题 - TimeZoneInfo.ConvertTimeToUtc导致日期更改

时间:2016-02-24 14:11:48

标签: c# datetime timezone utc

如果用户选择提前x个小时的时区,那么我希望保存的日期会从屏幕上选择的日期发生变化。 例如。他们从日历弹出窗口中选择 UTC + 2 Athens 25/02/2016的日期,然后记录的日期将为24/02/2016。 我已将原因缩小到选定的日期时间记录为例如25/02/2016 00:00:00并且偏差为2小时这一事实,这将它带到24/02/2016 22:00:00 从未使用过时区或UTC日期/时间,这非常令人困惑。

以下是代码

     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 *(以下代码)*

返回后,

25/02/2016 00:00:00等同于ParseDateAndTimeNoUTCMap之类的内容

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

从上面返回后,执行以下行 -

TimeZoneInfo oTimeZone = TimeZoneInfo.FindSystemTimeZoneById(oObject.TimeZoneDetails);
        oObject.RefDate = itTimeAndDate.GetUTCUsingTimeZone(oTimeZone, oObject.RefDate);  

GetUTCUsingTimeZone范围内,问题似乎发生在我身上。

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

我已检查TimezoneInfo的偏移值,oResult始终等于oLocal param - 偏移量。因此25/02/2016 00:00:00偏移3小时将等同于24/02/2016 21:00:00 当偏移是-hours时,它会直接进入另一个,所以o Result = oLocal + the offset,如果这是有道理的。因此,在这些情况下不会发生日期变更的主要问题。

显然这不是我想要的。我希望日期是用户为他们的时区选择的。 以前有人见过这样的东西吗?任何可能的解决方案?

我不完全确定我做错了什么。

2 个答案:

答案 0 :(得分:0)

修复是在从数据库中获取值并重新显示之前运行以下命令 -

static public itDateTime FixUTCUsingTimeZone(TimeZoneInfo oTimeZone, itDateTime oDateTime)
{
    if (oDateTime == null || oTimeZone == null)
        return oDateTime;

    DateTime oTime = DateTime.SpecifyKind(oDateTime.Value, DateTimeKind.Unspecified);
    DateTime oResult = TimeZoneInfo.ConvertTimeFromUtc(oTime, oTimeZone);

    return new itDateTime(oResult);

}

所以基本上只是执行前面执行的ConvertTimeToUtc的反向操作。不知道为什么最初没有这样做,但是你去了。

答案 1 :(得分:0)

如果您需要维护正确的时区,则应使用DateTimeOffset类型而不是DateTime类型。

DateTimeOffset维持与UTC的偏移,因此您永远不会丢失您的时区信息,并且有许多有用的方法,例如 UtcDateTime

从马口:

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