Как я могу отформатировать обнуляемый DateTime с ToString ()?

226

Как я могу преобразовать обнуляемый 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:

нет перегрузки для метода ToString принимает один аргумент

Эдвард Тангей
источник
3
Здравствуйте, не могли бы вы проверить принятые и текущие ответы? Более актуальный сегодняшний ответ может быть более правильным.
iuliu.net

Ответы:

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

РЕДАКТИРОВАТЬ: Как указано в других комментариях, проверьте, что есть ненулевое значение.

Обновление: как рекомендуется в комментариях, метод расширения:

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

И начиная с C # 6, вы можете использовать нулевой условный оператор, чтобы еще больше упростить код. Выражение ниже вернет ноль, если DateTime?ноль.

dt2?.ToString("yyyy-MM-dd hh:mm:ss")
Блейк Петтерссон
источник
26
Похоже, это требует от меня расширения.
Дэвид Гленн
42
. Значение является ключевым
stuartdotnet
@ Не забывай, что задача не тривиальна ... stackoverflow.com/a/44683673/5043056
Синджай,
3
Вы готовы к этому ... dt? .ToString ("дд / ммм / гггг") ?? «Большие преимущества C # 6
Том Макдоно
Ошибка CS0029: невозможно неявно преобразовать тип 'string' в 'System.DateTime?' (CS0029). .Net Core 2.0
Оракулярный человек
80

Попробуйте это для размера:

Фактический объект dateTime, который вы хотите отформатировать, находится в свойстве dt.Value, а не в самом объекте dt2.

DateTime? dt2 = DateTime.Now;
 Console.WriteLine(dt2.HasValue ? dt2.Value.ToString("yyyy-MM-dd hh:mm:ss") : "[N/A]");
Russ
источник
36

Вы, ребята, уже спроектировали все это и сделали его намного сложнее, чем на самом деле. Важная вещь, прекратите использовать ToString и начните использовать форматирование строк, например string.Format или методы, которые поддерживают форматирование строк, например Console.WriteLine. Вот предпочтительное решение этого вопроса. Это также самый безопасный.

Обновить:

Я обновляю примеры современными методами сегодняшнего компилятора 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}'");

Вывод: (я поместил в него одинарные кавычки, чтобы вы могли видеть, что он возвращается как пустая строка, когда ноль)

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

'2019-04-09 08:01:39'
''
Джон С
источник
30

Как уже говорили другие, перед вызовом ToString необходимо проверить наличие нуля, но чтобы избежать повторения, вы можете создать метод расширения, который делает это, что-то вроде:

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

}

Который может быть вызван как:

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'
Дэвид Гленн
источник
28

C # 6.0 детка:

dt2?.ToString("dd/MM/yyyy");

iuliu.net
источник
2
Я бы предложил следующую версию, чтобы этот ответ был эквивалентен существующему принятому ответу для C # 6.0. Console.WriteLine(dt2?.ToString("yyyy-MM-dd hh:mm:ss" ?? "n/a");
Can Bud
15

Проблема с формулировкой ответа на этот вопрос заключается в том, что вы не указываете желаемый результат, если значение даты и времени, обнуляемое значением, не имеет значения. Следующий код выведет DateTime.MinValueв таком случае и, в отличие от принятого в настоящее время ответа, не сгенерирует исключение.

dt2.GetValueOrDefault().ToString(format);
Мэтт Хауэллс
источник
7

Видя, что вы на самом деле хотите предоставить формат, я бы предложил добавить интерфейс 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   
}
Эль-Марг
источник
6

Как насчет чего-то такого простого:

String.Format("{0:dd/MM/yyyy}", d2)
Макс Браун
источник
5

Вы можете использовать dt2.Value.ToString("format"), но, конечно, для этого требуется, чтобы dt2! = Null, и это в первую очередь сводит на нет использование nullable типа.

Здесь есть несколько решений, но главный вопрос: как вы хотите отформатировать nullдату?

Хенк Холтерман
источник
5

Вот более общий подход. Это позволит вам отформатировать любой тип значения, допускающий значение NULL. Я включил второй метод, позволяющий переопределить строковое значение по умолчанию вместо использования значения по умолчанию для типа значения.

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;
    }
}
Schmalls
источник
4

Кратчайший ответ

$"{dt:yyyy-MM-dd hh:mm:ss}"

тесты

DateTime dt1 = DateTime.Now;
Console.Write("Test 1: ");
Console.WriteLine($"{dt1:yyyy-MM-dd hh:mm:ss}"); //works

DateTime? dt2 = DateTime.Now;
Console.Write("Test 2: ");
Console.WriteLine($"{dt2:yyyy-MM-dd hh:mm:ss}"); //Works

DateTime? dt3 = null;
Console.Write("Test 3: ");
Console.WriteLine($"{dt3:yyyy-MM-dd hh:mm:ss}"); //Works - Returns empty string

Output
Test 1: 2017-08-03 12:38:57
Test 2: 2017-08-03 12:38:57
Test 3: 
drobertson
источник
4

Еще лучшее решение в C # 6.0:

DateTime? birthdate;

birthdate?.ToString("dd/MM/yyyy");
Мухаммед Нурельдин
источник
4

Синтаксис бритвы:

@(myNullableDateTime?.ToString("yyyy-MM-dd") ?? String.Empty)
ВТ
источник
2

Я думаю, что вы должны использовать GetValueOrDefault-Methode. Поведение с ToString ("yy ...") не определено, если экземпляр является нулевым.

dt2.GetValueOrDefault().ToString("yyy...");
Мартин
источник
1
Поведение с ToString ( «уу ...») будет определена , если экземпляр является недействительным, так как GetValueOrDefault () вернет DateTime.MinValue
Lucas
2

Вот отличный ответ Блейка как метод расширения. Добавьте это в свой проект, и звонки в вопросе будут работать как положено.
Это означает, что он используется как MyNullableDateTime.ToString("dd/MM/yyyy")с тем же выводом MyDateTime.ToString("dd/MM/yyyy"), что и за исключением того, что значение будет, "N/A"если DateTime равно нулю

public static string ToString(this DateTime? date, string format)
{
    return date != null ? date.Value.ToString(format) : "N/A";
}
Sinjai
источник
1

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

используя вместе с именованными параметрами вы можете сделать:

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

В старых версиях 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);
    }
}
JeroenH
источник
1

Мне нравится этот вариант:

Console.WriteLine(dt2?.ToString("yyyy-MM-dd hh:mm:ss") ?? "n/a");
Мартин
источник
0

Простые общие расширения

public static class Extensions
{

    /// <summary>
    /// Generic method for format nullable values
    /// </summary>
    /// <returns>Formated value or defaultValue</returns>
    public static string ToString<T>(this Nullable<T> nullable, string format, string defaultValue = null) where T : struct
    {
        if (nullable.HasValue)
        {
            return String.Format("{0:" + format + "}", nullable.Value);
        }

        return defaultValue;
    }
}
Анджей Мациусович
источник
-2

Может быть, это поздний ответ, но может помочь кому-то еще.

Простое это:

nullabledatevariable.Value.Date.ToString("d")

или просто используйте любой формат, а не "d".

Лучший

Валид
источник
1
Это будет ошибка, когда nullabledatevariable.Value равно нулю.
Джон C
-2

Вы можете использовать простую строку:

dt2.ToString("d MMM yyyy") ?? ""
Даниэль Хео
источник