C# 如何使用 ToString() 格式化可为空的 DateTime?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1833054/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 21:14:29  来源:igfitidea点击:

How can I format a nullable DateTime with ToString()?

c#datetimeformattingnullable

提问by Edward Tanguay

How can I convert the nullable DateTime dt2to a formatted string?

如何将可为空的 DateTime dt2转换为格式化字符串?

DateTime dt = DateTime.Now;
Console.WriteLine(dt.ToString("yyyy-MM-dd hh:mm:ss")); //works

DateTime? dt2 = DateTime.Now;
Console.WriteLine(dt2.ToString("yyyy-MM-dd hh:mm:ss")); //gives following error:

no overload to method ToString takes one argument

方法 ToString 没有重载需要一个参数

采纳答案by Blake Pettersson

Console.WriteLine(dt2 != null ? dt2.Value.ToString("yyyy-MM-dd hh:mm:ss") : "n/a"); 

EDIT: As stated in other comments, check that there is a non-null value.

编辑:如其他评论中所述,检查是否存在非空值。

Update: as recommended in the comments, extension method:

更新:如评论中所推荐,扩展方法:

public static string ToString(this DateTime? dt, string format)
    => dt == null ? "n/a" : ((DateTime)dt).ToString(format);

And starting in C# 6, you can use the null-conditional operatorto simplify the code even more. The expression below will return null if the DateTime?is null.

从 C# 6 开始,您可以使用空条件运算符进一步简化代码。如果DateTime?为 null ,则下面的表达式将返回null。

dt2?.ToString("yyyy-MM-dd hh:mm:ss")

回答by Henk Holterman

You can use dt2.Value.ToString("format"), but of course that requires that dt2 != null, and that negates th use of a nullable type in the first place.

您可以使用dt2.Value.ToString("format"),但当然这需要 dt2 != null,并且首先否定可空类型的使用。

There are several solutions here, but the big question is: How do you want to format a nulldate?

这里有几种解决方案,但最大的问题是:您想如何格式化null日期?

回答by Russ

Try this on for size:

试试这个尺寸:

The actual dateTime object your looking to format is in the dt.Value property, and not on the dt2 object itself.

您要格式化的实际 dateTime 对象在 dt.Value 属性中,而不是在 dt2 对象本身上。

DateTime? dt2 = DateTime.Now;
 Console.WriteLine(dt2.HasValue ? dt2.Value.ToString("yyyy-MM-dd hh:mm:ss") : "[N/A]");

回答by Matt Howells

The problem with formulating an answer to this question is that you do not specify the desired output when the nullable datetime has no value. The following code will output DateTime.MinValuein such a case, and unlike the currently accepted answer, will not throw an exception.

制定此问题的答案的问题在于,当可为空的日期时间没有值时,您没有指定所需的输出。以下代码将DateTime.MinValue在这种情况下输出,并且与当前接受的答案不同,不会抛出异常。

dt2.GetValueOrDefault().ToString(format);

回答by martin

I think you have to use the GetValueOrDefault-Methode. The behaviour with ToString("yy...") is not defined if the instance is null.

我认为您必须使用 GetValueOrDefault-Methode。如果实例为空,则不会定义 ToString("yy...") 的行为。

dt2.GetValueOrDefault().ToString("yyy...");

回答by David Glenn

As others have stated you need to check for null before invoking ToString but to avoid repeating yourself you could create an extension method that does that, something like:

正如其他人所说,您需要在调用 ToString 之前检查 null 但为了避免重复自己,您可以创建一个扩展方法来执行此操作,例如:

public static class DateTimeExtensions {

  public static string ToStringOrDefault(this DateTime? source, string format, string defaultValue) {
    if (source != null) {
      return source.Value.ToString(format);
    }
    else {
      return String.IsNullOrEmpty(defaultValue) ?  String.Empty : defaultValue;
    }
  }

  public static string ToStringOrDefault(this DateTime? source, string format) {
       return ToStringOrDefault(source, format, null);
  }

}

Which can be invoked like:

可以像这样调用:

DateTime? dt = DateTime.Now;
dt.ToStringOrDefault("yyyy-MM-dd hh:mm:ss");  
dt.ToStringOrDefault("yyyy-MM-dd hh:mm:ss", "n/a");
dt = null;
dt.ToStringOrDefault("yyyy-MM-dd hh:mm:ss", "n/a")  //outputs 'n/a'

回答by Schmalls

Here is a more generic approach. This will allow you to string format any nullable value type. I have included the second method to allow overriding the default string value instead of using the default value for the value type.

这是一个更通用的方法。这将允许您对任何可为空的值类型进行字符串格式化。我已经包含了第二种方法来允许覆盖默认字符串值,而不是使用值类型的默认值。

public static class ExtensionMethods
{
    public static string ToString<T>(this Nullable<T> nullable, string format) where T : struct
    {
        return String.Format("{0:" + format + "}", nullable.GetValueOrDefault());
    }

    public static string ToString<T>(this Nullable<T> nullable, string format, string defaultValue) where T : struct
    {
        if (nullable.HasValue) {
            return String.Format("{0:" + format + "}", nullable.Value);
        }

        return defaultValue;
    }
}

回答by ElmarG

Seeing that you actually want to provide the format I'd suggest to add the IFormattable interface to Smalls extension method like so, that way you don't have the nasty string format concatenation.

看到您实际上想要提供我建议将 IFormattable 接口添加到 Smalls 扩展方法的格式,这样您就没有讨厌的字符串格式连接。

public static string ToString<T>(this T? variable, string format, string nullValue = null)
where T: struct, IFormattable
{
  return (variable.HasValue) 
         ? variable.Value.ToString(format, null) 
         : nullValue;          //variable was null so return this value instead   
}

回答by JeroenH

IFormattable also includes a format provider that can be used, it allows both format of IFormatProvider to be null in dotnet 4.0 this would be

IFormattable 还包括一个可以使用的格式提供程序,它允许 IFormatProvider 的两种格式在 dotnet 4.0 中都为空,这将是

/// <summary>
/// Extentionclass for a nullable structs
/// </summary>
public static class NullableStructExtensions {

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="provider">The format provider 
    /// If <c>null</c> the default provider is used</param>
    /// <param name="defaultValue">The string to show when the source is <c>null</c>. 
    /// If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format = null, 
                                     IFormatProvider provider = null, 
                                     string defaultValue = null) 
                                     where T : struct, IFormattable {
        return source.HasValue
                   ? source.Value.ToString(format, provider)
                   : (String.IsNullOrEmpty(defaultValue) ? String.Empty : defaultValue);
    }
}

using together with named parameters you can do:

与命名参数一起使用,您可以执行以下操作:

dt2.ToString(defaultValue: "n/a");

dt2.ToString(defaultValue: "n/a");

In older versions of dotnet you get a lot of overloads

在旧版本的 dotnet 中,您会遇到很多重载

/// <summary>
/// Extentionclass for a nullable structs
/// </summary>
public static class NullableStructExtensions {

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="provider">The format provider 
    /// If <c>null</c> the default provider is used</param>
    /// <param name="defaultValue">The string to show when the source is <c>null</c>. 
    /// If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format, 
                                     IFormatProvider provider, string defaultValue) 
                                     where T : struct, IFormattable {
        return source.HasValue
                   ? source.Value.ToString(format, provider)
                   : (String.IsNullOrEmpty(defaultValue) ? String.Empty : defaultValue);
    }

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="defaultValue">The string to show when the source is null. If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format, string defaultValue) 
                                     where T : struct, IFormattable {
        return ToString(source, format, null, defaultValue);
    }

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <param name="provider">The format provider (if <c>null</c> the default provider is used)</param>
    /// <returns>The formatted string or an empty string if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, string format, IFormatProvider provider)
                                     where T : struct, IFormattable {
        return ToString(source, format, provider, null);
    }

    /// <summary>
    /// Formats a nullable struct or returns an empty string
    /// </summary>
    /// <param name="source"></param>
    /// <param name="format">The format string 
    /// If <c>null</c> use the default format defined for the type of the IFormattable implementation.</param>
    /// <returns>The formatted string or an empty string if the source is null</returns>
    public static string ToString<T>(this T? source, string format)
                                     where T : struct, IFormattable {
        return ToString(source, format, null, null);
    }

    /// <summary>
    /// Formats a nullable struct
    /// </summary>
    /// <param name="source"></param>
    /// <param name="provider">The format provider (if <c>null</c> the default provider is used)</param>
    /// <param name="defaultValue">The string to show when the source is <c>null</c>. If <c>null</c> an empty string is returned</param>
    /// <returns>The formatted string or the default value if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, IFormatProvider provider, string defaultValue)
                                     where T : struct, IFormattable {
        return ToString(source, null, provider, defaultValue);
    }

    /// <summary>
    /// Formats a nullable struct or returns an empty string
    /// </summary>
    /// <param name="source"></param>
    /// <param name="provider">The format provider (if <c>null</c> the default provider is used)</param>
    /// <returns>The formatted string or an empty string if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source, IFormatProvider provider)
                                     where T : struct, IFormattable {
        return ToString(source, null, provider, null);
    }

    /// <summary>
    /// Formats a nullable struct or returns an empty string
    /// </summary>
    /// <param name="source"></param>
    /// <returns>The formatted string or an empty string if the source is <c>null</c></returns>
    public static string ToString<T>(this T? source) 
                                     where T : struct, IFormattable {
        return ToString(source, null, null, null);
    }
}

回答by John C

You guys are over engineering this all and making it way more complicated than it really is. Important thing, stop using ToString and start using string formatting like string.Format or methods that support string formatting like Console.WriteLine. Here is the preferred solution to this question. This is also the safest.

你们都过度设计了这一切,使它比实际情况更复杂。重要的是,停止使用 ToString 并开始使用像 string.Format 这样的字符串格式或像 Console.WriteLine 这样支持字符串格式的方法。这是此问题的首选解决方案。这也是最安全的。

Update:

更新:

I update the examples with up to date methods of today's C# compiler. conditional operators& string interpolation

我使用当今 C# 编译器的最新方法更新示例。条件运算符字符串插值

DateTime? dt1 = DateTime.Now;
DateTime? dt2 = null;

Console.WriteLine("'{0:yyyy-MM-dd hh:mm:ss}'", dt1);
Console.WriteLine("'{0:yyyy-MM-dd hh:mm:ss}'", dt2);
// New C# 6 conditional operators (makes using .ToString safer if you must use it)
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/operators/null-conditional-operators
Console.WriteLine(dt1?.ToString("yyyy-MM-dd hh:mm:ss"));
Console.WriteLine(dt2?.ToString("yyyy-MM-dd hh:mm:ss"));
// New C# 6 string interpolation
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/tokens/interpolated
Console.WriteLine($"'{dt1:yyyy-MM-dd hh:mm:ss}'");
Console.WriteLine($"'{dt2:yyyy-MM-dd hh:mm:ss}'");

Output: (I put single quotes in it so you can see that it comes back as a empty string when null)

输出:(我在其中加了单引号,这样您就可以看到它在为空时作为空字符串返回)

'2019-04-09 08:01:39'
''
2019-04-09 08:01:39

'2019-04-09 08:01:39'
''