2009-05-08 3 views
83

У меня есть два DateTime vars, beginTime и endTime. Я получил разницу их, выполнив следующие действия:Как преобразовать TimeSpan в форматированную строку?

TimeSpan dateDifference = endTime.Subtract(beginTime); 

Как я теперь возвращать строку этого в чч часов, мм мин, сс сек формата с использованием C#.

Если разница была 00: 06: 32,4458750

Он должен вернуться, 00 часов, 06 минут, 32 СЕК

+0

Для более современного ответа идти на этот вопрос: http://stackoverflow.com/questions/574881/how-can-i-string-format-a-timespan-object-with-a-custom- format-in-net – User

ответ

34

Would TimeSpan.ToString() сделать трюк для вас? Если нет, похоже, что пример кода на этой странице описывает, как выполнить произвольное форматирование объекта TimeSpan.

+1

Я получил то же самое, искал и обновил ссылку. Это работает для вас? – Andy

+57

Эта страница делает ** не ** описывают, как программист может форматировать строку TimeSpan по желанию. Он описывает только формат, в котором возвращается TimeSpan при преобразовании с помощью ToString(). Это ToString() не принимает никаких настраиваемых аргументов, таких как «mm: ss». Образцы кода показывают только то, как автоматически сгенерированная строка будет выглядеть с учетом разных значений TimeSpan, ** не ** как отформатировать ее по желанию. Сначала вам нужно преобразовать в DateTime (TimeSpan.Ticks) .ToString («mm: ss»). – MrSparkly

+0

Я преобразовал его таким образом => timespan.tostring ("% d") + "" + timespan.tostring (@ "hh \: mm: \ ss"); , Идея состоит в том, чтобы получить нужные строки отдельно и присоединиться к ним. – prabhakaran

9

Самый простой способ форматирования TimeSpan является добавление его в DateTime и форматам:

string formatted = (DateTime.Today + dateDifference).ToString("HH 'hrs' mm 'mins' ss 'secs'"); 

Это работает до тех пор, как разница во времени не более 24 часов.

Свойство Today возвращает значение DateTime, где компонент времени равен нулю, поэтому компонент времени результата равен TimeSpan.

+0

Я думаю, что это самый простой подход. Вы можете удалить нулевые часы и минуты, например: .ToString ("HH 'hrs' mm 'mins' ss 'secs'"). Замените («00 hrs», «»). Замените («00 mins», "") .Trim() –

28

Используйте String.Format() с несколькими параметрами.

using System; 

namespace TimeSpanFormat 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      TimeSpan dateDifference = new TimeSpan(0, 0, 6, 32, 445); 
      string formattedTimeSpan = string.Format("{0:D2} hrs, {1:D2} mins, {2:D2} secs", dateDifference.Hours, dateDifference.Minutes, dateDifference.Seconds); 
      Console.WriteLine(formattedTimeSpan); 
     } 
    } 
} 
5

Согласно the Microsoft documentation, структура TimeSpan выставляет часы, минуты, секунды и миллисекунды в качестве членов целого числа. Может быть, вы хотите что-то вроде:

dateDifference.Hours.ToString() + " hrs, " + dateDifference.Minutes.ToString() + " mins, " + dateDifference.Seconds.ToString() + " secs" 
106

Путем преобразования его в DateTime, вы можете получить локализованные форматы:

new DateTime(timeSpan.Ticks).ToString("HH:mm"); 
+4

Обязательно используйте «HH», а не «hh», в качестве спецификатора формата, иначе значение часов 0 может быть распечатано как «12». Я предполагаю, что интерпретация Спецификаторы формата зависят от настроек локали. – weiji

+2

Кроме того, это имеет ту же проблему, что и у Гуффа - если прошедшее время, например, 26 часов, распечатывается как «02:00» часов. Но я предпочитаю этот способ печати форматированных строк. – weiji

+0

Мне понадобился один лайнер для использования в выражении VB. Это было прекрасно. –

154

Я только что построил несколько методов TimeSpan Extension. Думал я мог бы поделиться:

public static string ToReadableAgeString(this TimeSpan span) 
{ 
    return string.Format("{0:0}", span.Days/365.25); 
} 

public static string ToReadableString(this TimeSpan span) 
{ 
    string formatted = string.Format("{0}{1}{2}{3}", 
     span.Duration().Days > 0 ? string.Format("{0:0} day{1}, ", span.Days, span.Days == 1 ? String.Empty : "s") : string.Empty, 
     span.Duration().Hours > 0 ? string.Format("{0:0} hour{1}, ", span.Hours, span.Hours == 1 ? String.Empty : "s") : string.Empty, 
     span.Duration().Minutes > 0 ? string.Format("{0:0} minute{1}, ", span.Minutes, span.Minutes == 1 ? String.Empty : "s") : string.Empty, 
     span.Duration().Seconds > 0 ? string.Format("{0:0} second{1}", span.Seconds, span.Seconds == 1 ? String.Empty : "s") : string.Empty); 

    if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2); 

    if (string.IsNullOrEmpty(formatted)) formatted = "0 seconds"; 

    return formatted; 
} 
+1

Что делать, если я не хочу показывать секунды или дни. Не очень 'extensible' :(но это, безусловно, правильное направление, вы должны принять строку типа« hh: mm »здесь и построить время, основанное на этом. Точно так же, как' ToString() 'Я думаю, что ответ by @rubenroid лучший ответ. – ppumkin

+1

@ppumkin Его ответ отображает результат в полностью фиксированном формате. Этот ответ будет обрабатывать разумное отображение в течение 1 секунды, вплоть до сотен дней. Его ответ не отвечает. – NickG

8
public static class TimeSpanFormattingExtensions 
    { 
     public static string ToReadableString(this TimeSpan span) 
     { 
     return string.Join(", ", span.GetReadableStringElements() 
      .Where(str => !string.IsNullOrWhiteSpace(str))); 
     } 

     private static IEnumerable<string> GetReadableStringElements(this TimeSpan span) 
     { 
     yield return GetDaysString((int)Math.Floor(span.TotalDays)); 
     yield return GetHoursString(span.Hours); 
     yield return GetMinutesString(span.Minutes); 
     yield return GetSecondsString(span.Seconds); 
     } 

     private static string GetDaysString(int days) 
     { 
     if (days == 0) 
      return string.Empty; 

     if (days == 1) 
      return "1 day"; 

     return string.Format("{0:0} days", days); 
     } 

     private static string GetHoursString(int hours) 
     { 
     if (hours == 0) 
      return string.Empty; 

     if (hours == 1) 
      return "1 hour"; 

     return string.Format("{0:0} hours", hours); 
     } 

     private static string GetMinutesString(int minutes) 
     { 
     if (minutes == 0) 
      return string.Empty; 

     if (minutes == 1) 
      return "1 minute"; 

     return string.Format("{0:0} minutes", minutes); 
     } 

     private static string GetSecondsString(int seconds) 
     { 
     if (seconds == 0) 
      return string.Empty; 

     if (seconds == 1) 
      return "1 second"; 

     return string.Format("{0:0} seconds", seconds); 
     } 
    } 
0

Я знаю, что это поздний ответ, но это работает для меня:

TimeSpan dateDifference = new TimeSpan(0,0,0, (int)endTime.Subtract(beginTime).TotalSeconds); 

dateDifference теперь должны исключить части меньше, чем на секунду. Работает также в .net 2.0.

-8
''' <summary> 
''' Return specified Double # (NumDbl) as String using specified Number Format String (FormatStr, 
''' Default = "N0") and Format Provider (FmtProvider, Default = Nothing) followed by space and, 
''' if NumDbl = 1, the specified Singular Unit Name (SglUnitStr), else the Plural Unit Name 
''' (PluralUnitStr). 
''' </summary> 
''' <param name="NumDbl"></param> 
''' <param name="SglUnitStr"></param> 
''' <param name="PluralUnitStr"></param> 
''' <param name="FormatStr"></param> 
''' <param name="FmtProvider"></param> 
''' <returns></returns> 
''' <remarks></remarks> 
Public Function PluralizeUnitsStr(_ 
    ByVal NumDbl As Double, _ 
    ByVal SglUnitStr As String, _ 
    ByVal PluralUnitStr As String, _ 
    Optional ByVal FormatStr As String = "N0", _ 
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _ 
    ) As String 

    PluralizeUnitsStr = NumDbl.ToString(FormatStr, FmtProvider) & " " 

    Dim RsltUnitStr As String 

    If NumDbl = 1 Then 
     RsltUnitStr = SglUnitStr 
    Else 
     RsltUnitStr = PluralUnitStr 
    End If 

    PluralizeUnitsStr &= RsltUnitStr 

End Function 

''' <summary> 
''' Info about a # Unit. 
''' </summary> 
''' <remarks></remarks> 
Public Class clsNumUnitInfoItem 
    ''' <summary> 
    ''' Name of a Singular Unit (i.e. "day", "trillion", "foot") 
    ''' </summary> 
    ''' <remarks></remarks> 
    Public UnitSglStr As String 

    ''' <summary> 
    ''' Name of a Plural Unit (i.e. "days", "trillion", "feet") 
    ''' </summary> 
    ''' <remarks></remarks> 
    Public UnitPluralStr As String 

    ''' <summary> 
    ''' # of Units to = 1 of Next Higher (aka Parent) Unit (i.e. 24 "hours", 1000 "million", 
    ''' 5280 "feet") 
    ''' </summary> 
    ''' <remarks></remarks> 
    Public UnitsInParentInt As Integer 
End Class ' -- clsNumUnitInfoItem 

Dim TimeLongEnUnitInfoItms As clsNumUnitInfoItem() = { _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "day", .UnitPluralStr = "days", .UnitsInParentInt = 1}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "hour", .UnitPluralStr = "hours", .UnitsInParentInt = 24}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "minute", .UnitPluralStr = "minutes", .UnitsInParentInt = 60}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "second", .UnitPluralStr = "seconds", .UnitsInParentInt = 60}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "millisecond", .UnitPluralStr = "milliseconds", .UnitsInParentInt = 1000} _ 
    } ' -- Dim TimeLongEnUnitInfoItms 

Dim TimeShortEnUnitInfoItms As clsNumUnitInfoItem() = { _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "day", .UnitPluralStr = "days", .UnitsInParentInt = 1}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "hr", .UnitPluralStr = "hrs", .UnitsInParentInt = 24}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "min", .UnitPluralStr = "mins", .UnitsInParentInt = 60}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "sec", .UnitPluralStr = "secs", .UnitsInParentInt = 60}, _ 
    New clsNumUnitInfoItem With {.UnitSglStr = "msec", .UnitPluralStr = "msecs", .UnitsInParentInt = 1000} _ 
    } ' -- Dim TimeShortEnUnitInfoItms 

''' <summary> 
''' Convert a specified Double Number (NumDbl) to a long (aka verbose) format (i.e. "1 day, 
''' 2 hours, 3 minutes, 4 seconds and 567 milliseconds") with a specified Array of Time Unit 
''' Info Items (TimeUnitInfoItms), Conjunction (ConjStr, Default = "and"), Minimum Unit Level 
''' Shown (MinUnitLevInt) (0 to TimeUnitInfoItms.Length - 1, -1=All), Maximum Unit Level Shown 
''' (MaxUnitLevInt) (-1=All), Maximum # of Unit Levels Shown (MaxNumUnitLevsInt) (1 to 0 to 
''' TimeUnitInfoItms.Length - 1, 0=All) and Round Last Shown Units Up Flag (RoundUpBool). 
''' Suppress leading 0 Unit Levels. 
''' </summary> 
''' <param name="NumDbl"></param> 
''' <param name="NumUnitInfoItms"></param> 
''' <param name="ConjStr"></param> 
''' <param name="MinUnitLevInt"></param> 
''' <param name="MaxUnitLevInt"></param> 
''' <param name="MaxNumUnitLevsInt"></param> 
''' <param name="RoundUpBool"></param> 
''' <param name="FormatStr"></param> 
''' <param name="FmtProvider"></param> 
''' <returns></returns> 
''' <remarks></remarks> 
Public Function NumToLongStr(_ 
    ByVal NumDbl As Double, _ 
    ByVal NumUnitInfoItms As clsNumUnitInfoItem(), _ 
    Optional ByVal ConjStr As String = "and", _ 
    Optional ByVal MinUnitLevInt As Integer = -1, _ 
    Optional ByVal MaxUnitLevInt As Integer = -1, _ 
    Optional ByVal MaxNumUnitLevsInt As Integer = 0, _ 
    Optional ByVal RoundUpBool As Boolean = False, _ 
    Optional ByVal FormatStr As String = "N0", _ 
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _ 
    ) As String 
    NumToLongStr = "" 

    Const TUnitDelimStr As String = ", " 

    If (MinUnitLevInt < -1) OrElse (MinUnitLevInt >= NumUnitInfoItms.Length) Then 
     Throw New Exception("Invalid MinUnitLevInt: " & MaxUnitLevInt) 
    End If 

    If (MaxUnitLevInt < -1) OrElse (MaxUnitLevInt >= NumUnitInfoItms.Length) Then 
     Throw New Exception("Invalid MaxDetailLevelInt: " & MaxUnitLevInt) 
    End If 

    If (MaxNumUnitLevsInt < 0) OrElse (MaxNumUnitLevsInt > NumUnitInfoItms.Length) Then 
     Throw New Exception("Invalid MaxNumUnitLevsInt: " & MaxNumUnitLevsInt) 
    End If 

    Dim PrevNumUnitsDbl As Double = NumDbl 
    Dim CurrUnitLevInt As Integer = -1 
    Dim NumUnitLevsShownInt As Integer = 0 

    For Each UnitInfoItem In NumUnitInfoItms 
     CurrUnitLevInt += 1 

     With UnitInfoItem 

      Dim CurrNumUnitsDbl As Double = PrevNumUnitsDbl * .UnitsInParentInt 
      Dim CurrTruncNumUnitsInt As Integer = Math.Truncate(CurrNumUnitsDbl) 
      PrevNumUnitsDbl = CurrNumUnitsDbl 
      If CurrUnitLevInt < MinUnitLevInt Then Continue For 
      PrevNumUnitsDbl -= CurrTruncNumUnitsInt 

      'If (CurrUnitLevInt > TimeUnitInfoItms.Length) _ 
      ' OrElse _ 
      ' (_ 
      ' (CurrUnitLevInt > MaxUnitLevInt) AndAlso _ 
      ' (MaxUnitLevInt <> -1) _ 
      ' ) _ 
      ' OrElse _ 
      ' (_ 
      ' (NumUnitLevsShownInt + 1 > MaxNumUnitLevsInt) AndAlso _ 
      ' (MaxNumUnitLevsInt <> 0) _ 
      ' ) Then Exit For 

      If (CurrUnitLevInt = (NumUnitInfoItms.Length - 1)) OrElse _ 
       (CurrUnitLevInt = MaxUnitLevInt) OrElse _ 
       ((NumUnitLevsShownInt + 1) = MaxNumUnitLevsInt) Then 

       If NumUnitLevsShownInt > 0 Then 
        Dim TUnitDelimStrLenInt As Integer = TUnitDelimStr.Length 
        NumToLongStr = NumToLongStr.Remove(_ 
         NumToLongStr.Length - TUnitDelimStrLenInt, _ 
         TUnitDelimStrLenInt) 
        NumToLongStr &= " " & ConjStr & " " 
       End If 

       Dim CurrNunUnitsRoundedInt As Integer 
       If RoundUpBool Then 
        If CurrNumUnitsDbl <> CurrTruncNumUnitsInt Then 
         CurrNunUnitsRoundedInt = CurrTruncNumUnitsInt + 1 
        Else 
         CurrNunUnitsRoundedInt = CurrTruncNumUnitsInt 
        End If 
       Else 
        CurrNunUnitsRoundedInt = Math.Round(_ 
         value:=CurrNumUnitsDbl, mode:=MidpointRounding.AwayFromZero) 
       End If 

       NumToLongStr &= _ 
        PluralizeUnitsStr(CurrNunUnitsRoundedInt, _ 
         .UnitSglStr, .UnitPluralStr, FormatStr, FmtProvider) 
       Exit For 

      Else ' -- Not (MaxUnitLevInt or MaxNumUnitLevsInt) 

       If NumUnitLevsShownInt > 0 OrElse CurrTruncNumUnitsInt <> 0 Then 
        NumToLongStr &= _ 
         PluralizeUnitsStr(CurrTruncNumUnitsInt, _ 
          .UnitSglStr, .UnitPluralStr, FormatStr, FmtProvider) & _ 
         TUnitDelimStr 
        NumUnitLevsShownInt += 1 
       End If 

      End If ' -- Else Not (MaxUnitLevInt or MaxNumUnitLevsInt) 

     End With ' -- UnitInfoItem 

    Next UnitInfoItem 

End Function 

''' <summary> 
''' Call NumToLongStr with a specified TimeSpan's (TS) TotalDays. 
''' </summary> 
''' <param name="TS"></param> 
''' <param name="TimeUnitInfoItms"></param> 
''' <param name="ConjStr"></param> 
''' <param name="MinUnitLevInt"></param> 
''' <param name="MaxUnitLevInt"></param> 
''' <param name="MaxNumUnitLevsInt"></param> 
''' <param name="RoundUpBool"></param> 
''' <param name="FormatStr"></param> 
''' <param name="FmtProvider"></param> 
''' <returns></returns> 
''' <remarks></remarks> 
Public Function TimeSpanToStr(_ 
    ByVal TS As TimeSpan, _ 
    ByVal TimeUnitInfoItms As clsNumUnitInfoItem(), _ 
    Optional ByVal ConjStr As String = "and", _ 
    Optional ByVal MinUnitLevInt As Integer = -1, _ 
    Optional ByVal MaxUnitLevInt As Integer = -1, _ 
    Optional ByVal MaxNumUnitLevsInt As Integer = 0, _ 
    Optional ByVal RoundUpBool As Boolean = False, _ 
    Optional ByVal FormatStr As String = "N0", _ 
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _ 
    ) As String 

    Return NumToLongStr(_ 
     NumDbl:=TS.TotalDays, _ 
     NumUnitInfoItms:=TimeUnitInfoItms, _ 
     ConjStr:=ConjStr, _ 
     MinUnitLevInt:=MinUnitLevInt, _ 
     MaxUnitLevInt:=MaxUnitLevInt, _ 
     MaxNumUnitLevsInt:=MaxNumUnitLevsInt, _ 
     RoundUpBool:=RoundUpBool, _ 
     FormatStr:=FormatStr, _ 
     FmtProvider:=FmtProvider _ 
     ) 

End Function 

''' <summary> 
''' Call TimeSpanToStr with TimeLongEnUnitInfoItms. 
''' </summary> 
''' <param name="TS"></param> 
''' <param name="MinUnitLevInt"></param> 
''' <param name="MaxUnitLevInt"></param> 
''' <param name="MaxNumUnitLevsInt"></param> 
''' <param name="RoundUpBool"></param> 
''' <param name="FormatStr"></param> 
''' <param name="FmtProvider"></param> 
''' <returns></returns> 
''' <remarks></remarks> 
Public Function TimeSpanToLongEnStr(_ 
    ByVal TS As TimeSpan, _ 
    Optional ByVal MinUnitLevInt As Integer = -1, _ 
    Optional ByVal MaxUnitLevInt As Integer = -1, _ 
    Optional ByVal MaxNumUnitLevsInt As Integer = 0, _ 
    Optional ByVal RoundUpBool As Boolean = False, _ 
    Optional ByVal FormatStr As String = "N0", _ 
    Optional ByVal FmtProvider As System.IFormatProvider = Nothing _ 
    ) As String 

    Return TimeSpanToStr(_ 
     TS:=TS, _ 
     TimeUnitInfoItms:=TimeLongEnUnitInfoItms, _ 
     MinUnitLevInt:=MinUnitLevInt, _ 
     MaxUnitLevInt:=MaxUnitLevInt, _ 
     MaxNumUnitLevsInt:=MaxNumUnitLevsInt, _ 
     RoundUpBool:=RoundUpBool, _ 
     FormatStr:=FormatStr, _ 
     FmtProvider:=FmtProvider _ 
     ) 
End Function 
+1

Это VB. для C#. –

+0

@ Стефен Кеннеди: Действительно [ссылка] (http://www.developerfusion.com/tools/convert/vb-to-csharp/) – Tom

+5

@ user401246 вам нужно запустить его через этот конвертер, протестировал его и поставил вместо этого код C#, так как это ваш ответ не очень полезен. – Peter

4

Благодаря Петру для метода расширения. Я изменил его на работу с более длительное время охватывает лучше:

namespace ExtensionMethods 
{ 
    public static class TimeSpanExtensionMethods 
    { 
     public static string ToReadableString(this TimeSpan span) 
     { 
      string formatted = string.Format("{0}{1}{2}", 
       (span.Days/7) > 0 ? string.Format("{0:0} weeks, ", span.Days/7) : string.Empty, 
       span.Days % 7 > 0 ? string.Format("{0:0} days, ", span.Days % 7) : string.Empty, 
       span.Hours > 0 ? string.Format("{0:0} hours, ", span.Hours) : string.Empty); 

      if (formatted.EndsWith(", ")) formatted = formatted.Substring(0, formatted.Length - 2); 

      return formatted; 
     } 
    } 
} 
+0

Можно также добавить годы? Но я думаю, что будет неточно добавлять годы – Thunder

1

Я также имел подобную проблему и пришли с моим собственным расширением, но это, кажется, немного отличается от всего остального.

public static string TimeSpanToString(this TimeSpan timeSpan) 
    { 
     //if it's negative 
     if (timeSpan.Ticks < 0) 
     { 
      timeSpan = timeSpan - timeSpan - timeSpan; 
      if (timeSpan.Days != 0) 
       return string.Format("-{0}:{1}", timeSpan.Days.ToString("d"), new DateTime(timeSpan.Ticks).ToString("HH:mm:ss")); 
      else 
       return new DateTime(timeSpan.Ticks).ToString("-HH:mm:ss"); 
     } 

     //if it has days 
     else if (timeSpan.Days != 0) 
      return string.Format("{0}:{1}", timeSpan.Days.ToString("d"), new DateTime(timeSpan.Ticks).ToString("HH:mm:ss")); 

     //otherwise return the time 
     else 
      return new DateTime(timeSpan.Ticks).ToString("HH:mm:ss"); 
    } 
+0

, называя это 'timeSpan = timeSpan - timeSpan - timeSpan;', поскольку разные - это оскорбление для разных :-), но мне это нравится, в извращенном виде of –

3

Я знаю, что этот вопрос старше, но .Net 4 теперь поддерживает Custom TimeSpan formats.

Также я знаю, что это было упомянуто, но это меня поймало, преобразование Ticks в DateTime работает, но не обрабатывает должным образом более 24-часовой промежуток.

new DateTime((DateTime.Now - DateTime.Now.AddHours(-25)).Ticks).ToString("HH:mm") 

Это будет вам 01:00, а не 25:00, как вы и ожидали.

2

Вы можете использовать следующий код.

public static class TimeSpanExtensions 
{ 
    public static String Verbose(this TimeSpan timeSpan) 
    { 
    var hours = timeSpan.Hours; 
    var minutes = timeSpan.Minutes; 

    if (hours > 0) return String.Format("{0} hours {1} minutes", hours, minutes); 
    return String.Format("{0} minutes", minutes); 
    } 
} 
74

Это кратчайшее решение.

timeSpan.ToString(@"hh\:mm"); 
+4

У этого есть ошибка. timespan - 1 день, 0 часов и 33 минуты, он вернется в 00:33, хотя технически это 24:33. –

+8

@RickRatayczak Imo Я бы не назвал это ошибкой, учитывая, что в большинстве случаев это будет использоваться для отображения прошедшего времени между двумя временными интервалами. Который редко превышает целый день. Несмотря на это, я вижу вашу точку зрения, и если это так, это решение просто не для вас. Я думаю, что это блестяще. – Falgantil

+4

Это связано с тем, что в строке формата ответа не указывается значение компонента days для отображаемого периода времени; 24 часа перекатываются на 1 день. Не ошибка, ее просто не видно. – AnotherUser

Смежные вопросы