1
0
mirror of https://github.com/ppy/osu.git synced 2025-03-11 15:27:20 +08:00

Merge pull request #14079 from peppy/fix-timestamp-formatting

Fix beatmap durations over one hour displaying incorrectly
This commit is contained in:
Dean Herbert 2021-07-31 20:02:54 +09:00 committed by GitHub
commit 858d1f8dd0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 99 additions and 31 deletions

View File

@ -0,0 +1,41 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using NUnit.Framework;
using osu.Game.Extensions;
namespace osu.Game.Tests.NonVisual
{
[TestFixture]
public class TimeDisplayExtensionTest
{
private static readonly object[][] editor_formatted_duration_tests =
{
new object[] { new TimeSpan(0, 0, 0, 0, 50), "00:00:050" },
new object[] { new TimeSpan(0, 0, 0, 10, 50), "00:10:050" },
new object[] { new TimeSpan(0, 0, 5, 10), "05:10:000" },
new object[] { new TimeSpan(0, 1, 5, 10), "65:10:000" },
};
[TestCaseSource(nameof(editor_formatted_duration_tests))]
public void TestEditorFormat(TimeSpan input, string expectedOutput)
{
Assert.AreEqual(expectedOutput, input.ToEditorFormattedString());
}
private static readonly object[][] formatted_duration_tests =
{
new object[] { new TimeSpan(0, 0, 10), "00:10" },
new object[] { new TimeSpan(0, 5, 10), "05:10" },
new object[] { new TimeSpan(1, 5, 10), "01:05:10" },
new object[] { new TimeSpan(1, 1, 5, 10), "01:01:05:10" },
};
[TestCaseSource(nameof(formatted_duration_tests))]
public void TestFormattedDuration(TimeSpan input, string expectedOutput)
{
Assert.AreEqual(expectedOutput, input.ToFormattedDuration().ToString());
}
}
}

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. // Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text. // See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Allocation; using osu.Framework.Allocation;
using osu.Framework.Bindables; using osu.Framework.Bindables;
using osu.Framework.Graphics; using osu.Framework.Graphics;
@ -11,6 +10,7 @@ using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Beatmaps.Legacy; using osu.Game.Beatmaps.Legacy;
using osu.Game.Extensions;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Screens.Menu; using osu.Game.Screens.Menu;
@ -198,8 +198,8 @@ namespace osu.Game.Tournament.Components
Direction = FillDirection.Vertical, Direction = FillDirection.Vertical,
Children = new Drawable[] Children = new Drawable[]
{ {
new DiffPiece(("Length", TimeSpan.FromMilliseconds(length).ToString(@"mm\:ss"))), new DiffPiece(("Length", length.ToFormattedDuration().ToString())),
new DiffPiece(("BPM", $"{bpm:0.#}")) new DiffPiece(("BPM", $"{bpm:0.#}")),
} }
}, },
new Container new Container

View File

@ -1,26 +0,0 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
namespace osu.Game.Extensions
{
public static class EditorDisplayExtensions
{
/// <summary>
/// Get an editor formatted string (mm:ss:mss)
/// </summary>
/// <param name="milliseconds">A time value in milliseconds.</param>
/// <returns>An editor formatted display string.</returns>
public static string ToEditorFormattedString(this double milliseconds) =>
ToEditorFormattedString(TimeSpan.FromMilliseconds(milliseconds));
/// <summary>
/// Get an editor formatted string (mm:ss:mss)
/// </summary>
/// <param name="timeSpan">A time value.</param>
/// <returns>An editor formatted display string.</returns>
public static string ToEditorFormattedString(this TimeSpan timeSpan) =>
$"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{timeSpan:mm\\:ss\\:fff}";
}
}

View File

@ -0,0 +1,51 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Localisation;
namespace osu.Game.Extensions
{
public static class TimeDisplayExtensions
{
/// <summary>
/// Get an editor formatted string (mm:ss:mss)
/// </summary>
/// <param name="milliseconds">A time value in milliseconds.</param>
/// <returns>An editor formatted display string.</returns>
public static string ToEditorFormattedString(this double milliseconds) =>
ToEditorFormattedString(TimeSpan.FromMilliseconds(milliseconds));
/// <summary>
/// Get an editor formatted string (mm:ss:mss)
/// </summary>
/// <param name="timeSpan">A time value.</param>
/// <returns>An editor formatted display string.</returns>
public static string ToEditorFormattedString(this TimeSpan timeSpan) =>
$"{(timeSpan < TimeSpan.Zero ? "-" : string.Empty)}{(int)timeSpan.TotalMinutes:00}:{timeSpan:ss\\:fff}";
/// <summary>
/// Get a formatted duration (dd:hh:mm:ss with days/hours omitted if zero).
/// </summary>
/// <param name="milliseconds">A duration in milliseconds.</param>
/// <returns>A formatted duration string.</returns>
public static LocalisableString ToFormattedDuration(this double milliseconds) =>
ToFormattedDuration(TimeSpan.FromMilliseconds(milliseconds));
/// <summary>
/// Get a formatted duration (dd:hh:mm:ss with days/hours omitted if zero).
/// </summary>
/// <param name="timeSpan">A duration value.</param>
/// <returns>A formatted duration string.</returns>
public static LocalisableString ToFormattedDuration(this TimeSpan timeSpan)
{
if (timeSpan.TotalDays >= 1)
return new LocalisableFormattableString(timeSpan, @"dd\:hh\:mm\:ss");
if (timeSpan.TotalHours >= 1)
return new LocalisableFormattableString(timeSpan, @"hh\:mm\:ss");
return new LocalisableFormattableString(timeSpan, @"mm\:ss");
}
}
}

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Game.Beatmaps; using osu.Game.Beatmaps;
using osu.Game.Extensions;
using osu.Game.Graphics; using osu.Game.Graphics;
using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Sprites;
using osuTK; using osuTK;
@ -62,7 +63,7 @@ namespace osu.Game.Overlays.BeatmapSet
} }
else else
{ {
length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToString(@"m\:ss"); length.Value = TimeSpan.FromMilliseconds(beatmap.Length).ToFormattedDuration();
circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString(); circleCount.Value = beatmap.OnlineInfo.CircleCount.ToString();
sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString(); sliderCount.Value = beatmap.OnlineInfo.SliderCount.ToString();
} }

View File

@ -24,6 +24,7 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Localisation; using osu.Framework.Localisation;
using osu.Framework.Logging; using osu.Framework.Logging;
using osu.Game.Configuration; using osu.Game.Configuration;
using osu.Game.Extensions;
using osu.Game.Rulesets; using osu.Game.Rulesets;
using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Mods;
using osu.Game.Rulesets.UI; using osu.Game.Rulesets.UI;
@ -333,7 +334,7 @@ namespace osu.Game.Screens.Select
{ {
Name = "Length", Name = "Length",
CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Length), CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Length),
Content = TimeSpan.FromMilliseconds(beatmap.BeatmapInfo.Length).ToString(@"m\:ss"), Content = beatmap.BeatmapInfo.Length.ToFormattedDuration().ToString(),
}), }),
bpmLabelContainer = new Container bpmLabelContainer = new Container
{ {