DateTime.TryParse - > " Ghost ticks"

时间:2015-07-20 06:27:13

标签: c# .net datetime

我进行了下面的单元测试,它在我们的一个开发人员的机器上失败了(他在结果变量中得到一些滴答,而datetime变量是零滴答),但在其他所有机器上运行良好

    [TestMethod]
    public void DateTimeStringDateTimeMinCurrentCultureToNullableDateTimeSuccessTest()
    {
        var dateTime = new DateTime(1, 1, 1);
        string value = dateTime.ToString();
        var result = value.ToNullableDateTime();
        Assert.AreEqual(dateTime, result);
    }

以下是使用的扩展方法:

    /// <summary>
    /// Converts a string to a nullable DateTime. If the string is a invalid dateTime returns null.
    /// Uses the current culture.
    /// </summary>
    public static DateTime? ToNullableDateTime(this string s)
    {
        //Don't use CultureInfo.CurrentCulture to override user changes of the cultureinfo.
        return s.ToNullableDateTime(CultureInfo.GetCultureInfo(CultureInfo.CurrentCulture.Name));
    }

    /// <summary>
    /// Converts a string to a nullable DateTime. If the string is a invalid dateTime returns null.
    /// </summary>
    public static DateTime? ToNullableDateTime(this string s, CultureInfo cultureInfo)
    {
        if (String.IsNullOrEmpty(s)) return null;
        DateTime i;
        if (DateTime.TryParse(s, cultureInfo, DateTimeStyles.None, out i)) return i;
        return null;
    }

我认为这可能与他使用的某些Windows日期时间设置有关。从理论上讲,ToNullableDateTime(string)应该创建一个新的文化信息,这是用户机器中立的。 GetCultureInfo应致电new CultureInfo(name, false)。我唯一能想到的是,有一个缓存的文化信息,其中包含s_NameCachedCultures中与GetCultureInfoHelper中检查的某种与用户机器相关的修改日期时间CreateSpecificCulture({{ 3}})。

我知道,GetDateTime方法可以返回用户修改的日期时间,如果您使用与Windows机器相同的文化来调用它。但我一直认为,CultureInfo在任何情况下都会返回未修改的日期时间。

所以有两个问题:

  • 是否可以将修改后的CultureInfo存储在内部缓存中?
  • 如果是,通过手动调用new CultrueInfo("xy", false)来获取未修改var list = [{ a: '1'}, {b: '2'}]; var lastObject = list.pop(); if(lastObject) { //use object.. } 的唯一方法是什么?

3 个答案:

答案 0 :(得分:3)

当你这样做时

  

string value = dateTime.ToString();

这将使用CultureInfo.CurrentCulture。然后,您尝试使用...

解析此字符串
  

CultureInfo.GetCultureInfo(CultureInfo.CurrentCulture.Name);

因此,您专门使用文化来解析与您创建字符串的字符串不同的字符串。当然会出现这种情况并未通过的情况。

我建议这个问题出现在大多数人的机器上

Assert.AreEqual(CultureInfo.CurrentCulture, CultureInfo.GetCultureInfo(CultureInfo.CurrentCulture.Name));

会通过但是在有问题的机器上它没有,你的字符串也没有。

我建议您可能要使用CultureInfo.InvariantCulture。所以......

    [TestMethod]
    public void DateTimeStringDateTimeMinCurrentCultureToNullableDateTimeSuccessTest()
    {
        DateTime dateTime = new DateTime(1, 1, 1);
        string value = dateTime.ToStringInvariant();
        var result = value.ToNullableDateTime();
        Assert.AreEqual(dateTime, result);
    }


    public static string ToStringInvariant(this DateTime? date)
    {
        if (date.HasValue)
            return date.Value.ToStringInvariant();

        return null;
    }

    public static string ToStringInvariant(this DateTime date)
    {
        return date.ToString(CultureInfo.InvariantCulture);

    }
    /// <summary>
    /// Converts a string to a nullable DateTime. If the string is a invalid dateTime returns null.
    /// Uses the current culture.
    /// </summary>
    public static DateTime? ToNullableDateTime(this string s)
    {
        //Don't use CultureInfo.CurrentCulture to override user changes of the cultureinfo.
        return s.ToNullableDateTime(CultureInfo.InvariantCulture);
    }

    /// <summary>
    /// Converts a string to a nullable DateTime. If the string is a invalid dateTime returns null.
    /// </summary>
    public static DateTime? ToNullableDateTime(this string s, CultureInfo cultureInfo)
    {
        if (String.IsNullOrEmpty(s)) return null;
        DateTime i;
        if (DateTime.TryParse(s, cultureInfo, DateTimeStyles.None, out i)) return i;
        return null;
    }

答案 1 :(得分:1)

我已经监督了一些细节。该问题与GetCultureInfo返回修改后的日期时间无关,问题已经开始于使用dateTime.ToString();的{​​{1}}(等于可以修改的Windows文化)。开发者机器将Thread.CurrentThread.CultureInfo转换为DateTime(1, 1, 1)。在任何其他计算机上,输出为01.01.01 00:00:00。因此,使用了年份的缩写版本,这似乎被解释为本世纪的第1年&#34;在01.01.0001 00:00:00方法中(快速侧节点:因此,对于年龄超过100岁的用户来说,使用缩写的年份版本告诉他们的出生日期是不可能的)。 这实际上是一种有趣的行为......

TryParse

导致:

        for (int i = 0; i < 100; i++)
        {
            var year = 1900 + i;
            DateTime date = new DateTime(year, 1, 1);
            var parsedDate = DateTime.ParseExact(date.ToString("yy"), "yy", CultureInfo.InvariantCulture);
            Console.WriteLine("{0}: {1}", year, parsedDate.ToString("yyyy"));
        }

因此,任何年龄较大的86岁的缩写出生日期都会导致该功能中的日期..但这会偏离问题背景。

我认为实际问题没有真正的解决方案(除了告诉开发人员不要在UI字符串之外使用本地CultureInfos并且从不使用缩写日期作为输入)。

我们的代码本身没有这样的问题,因为我们对所有内部内容使用[...] 1928: 2028 1929: 2029 1930: 1930 1931: 1931 [...] 。我只考虑单元测试..我认为测试本身是正确的。它表明,该函数实际上没有使用缩写日期正确工作。如果识别出具有缩写年份的日期时间字符串,我将更改CultureInfo.InvariantCulture的行为以抛出异常。

答案 2 :(得分:0)

我猜,很可能argv位于缓存中。这可以很容易地检查单元测试(CultureInfo)。

而不是AreSame使用DateTime(1, 1, 1)并检查幽灵蜱。它们是在字符串中找到的吗?您是否在两台具有不同结果的机器上尝试相同的文化(硬编码文化名称)?

同时检查差异是否是您文化中UTC的偏移量。

您可能可以使用DateTime(1, 2, 3)