From b2b7dc3ccf56779d0c623f2f375257048a8a6e81 Mon Sep 17 00:00:00 2001 From: Jachym Metlicka Date: Tue, 28 Mar 2023 14:52:21 +0200 Subject: [PATCH] Add filename-compatible date & time format (#25020) * enable the functionality to have filename-compatible date & time * fix PowerToys.sln * fix DateTime format * remove unrelated code * modify date time format * fix tests * fix hours to 24h format and modify tests to cover the case better. Simplify tests slightly --- .../ImageTests.cs | 2 + .../QueryTests.cs | 10 +-- .../TimeDateResultTests.cs | 85 +++++++++++-------- .../Components/AvailableResultsList.cs | 7 ++ .../Properties/Resources.Designer.cs | 9 ++ .../Properties/Resources.resx | 4 + 6 files changed, 76 insertions(+), 41 deletions(-) diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/ImageTests.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/ImageTests.cs index 9910e44388..a33b622d80 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/ImageTests.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/ImageTests.cs @@ -60,6 +60,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("iso zone", "ISO 8601 with time zone - ", "Images\\timeDate.dark.png")] [DataRow("iso utc zone", "ISO 8601 UTC with time zone - ", "Images\\timeDate.dark.png")] [DataRow("rfc", "RFC1123 -", "Images\\timeDate.dark.png")] + [DataRow("compatible", "Date and time in filename-compatible format", "Images\\timeDate.dark.png")] public void IconThemeDarkTest(string typedString, string subTitleMatch, string expectedResult) { // Setup @@ -105,6 +106,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("iso zone", "ISO 8601 with time zone - ", "Images\\timeDate.light.png")] [DataRow("iso utc zone", "ISO 8601 UTC with time zone - ", "Images\\timeDate.light.png")] [DataRow("rfc", "RFC1123 -", "Images\\timeDate.light.png")] + [DataRow("compatible", "Date and time in filename-compatible format", "Images\\timeDate.light.png")] public void IconThemeLightTest(string typedString, string subTitleMatch, string expectedResult) { // Setup diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/QueryTests.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/QueryTests.cs index 28aabc2aab..1ebb638df9 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/QueryTests.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/QueryTests.cs @@ -52,12 +52,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests } [DataTestMethod] - [DataRow("(time", 16)] - [DataRow("(date", 24)] + [DataRow("(time", 17)] + [DataRow("(date", 25)] [DataRow("(year", 7)] - [DataRow("(now", 30)] - [DataRow("(current", 30)] - [DataRow("(", 30)] + [DataRow("(now", 31)] + [DataRow("(current", 31)] + [DataRow("(", 31)] [DataRow("(now::10:10:10", 1)] // Windows file time [DataRow("(current::10:10:10", 0)] public void CountWithPluginKeyword(string typedString, int expectedResultCount) diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/TimeDateResultTests.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/TimeDateResultTests.cs index 741a14fe6c..08931e0d57 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/TimeDateResultTests.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests/TimeDateResultTests.cs @@ -26,11 +26,16 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests CultureInfo.CurrentUICulture = new CultureInfo("en-us"); } + private DateTime GetDateTimeForTest() + { + return new DateTime(2022, 03, 02, 22, 30, 45); + } + [DataTestMethod] - [DataRow("time", "10:30 AM")] + [DataRow("time", "10:30 PM")] [DataRow("date", "3/2/2022")] - [DataRow("date and time", "3/2/2022 10:30 AM")] - [DataRow("hour", "10")] + [DataRow("date and time", "3/2/2022 10:30 PM")] + [DataRow("hour", "22")] [DataRow("minute", "30")] [DataRow("second", "45")] [DataRow("millisecond", "0")] @@ -45,13 +50,14 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("month and day", "March 2")] [DataRow("year", "2022")] [DataRow("month and year", "March 2022")] - [DataRow("ISO 8601", "2022-03-02T10:30:45")] - [DataRow("ISO 8601 with time zone", "2022-03-02T10:30:45")] - [DataRow("RFC1123", "Wed, 02 Mar 2022 10:30:45 GMT")] + [DataRow("ISO 8601", "2022-03-02T22:30:45")] + [DataRow("ISO 8601 with time zone", "2022-03-02T22:30:45")] + [DataRow("RFC1123", "Wed, 02 Mar 2022 22:30:45 GMT")] + [DataRow("Date and time in filename-compatible format", "2022-03-02_22-30-45")] public void LocalFormatsWithShortTimeAndShortDate(string formatLabel, string expectedResult) { // Setup - var helperResults = AvailableResultsList.GetList(true, false, false, new DateTime(2022, 03, 02, 10, 30, 45)); + var helperResults = AvailableResultsList.GetList(true, false, false, GetDateTimeForTest()); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); @@ -61,10 +67,10 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests } [DataTestMethod] - [DataRow("time", "10:30 AM")] + [DataRow("time", "10:30 PM")] [DataRow("date", "Wednesday, March 2, 2022")] - [DataRow("date and time", "Wednesday, March 2, 2022 10:30 AM")] - [DataRow("hour", "10")] + [DataRow("date and time", "Wednesday, March 2, 2022 10:30 PM")] + [DataRow("hour", "22")] [DataRow("minute", "30")] [DataRow("second", "45")] [DataRow("millisecond", "0")] @@ -79,13 +85,14 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("month and day", "March 2")] [DataRow("year", "2022")] [DataRow("month and year", "March 2022")] - [DataRow("ISO 8601", "2022-03-02T10:30:45")] - [DataRow("ISO 8601 with time zone", "2022-03-02T10:30:45")] - [DataRow("RFC1123", "Wed, 02 Mar 2022 10:30:45 GMT")] + [DataRow("ISO 8601", "2022-03-02T22:30:45")] + [DataRow("ISO 8601 with time zone", "2022-03-02T22:30:45")] + [DataRow("RFC1123", "Wed, 02 Mar 2022 22:30:45 GMT")] + [DataRow("Date and time in filename-compatible format", "2022-03-02_22-30-45")] public void LocalFormatsWithShortTimeAndLongDate(string formatLabel, string expectedResult) { // Setup - var helperResults = AvailableResultsList.GetList(true, false, true, new DateTime(2022, 03, 02, 10, 30, 45)); + var helperResults = AvailableResultsList.GetList(true, false, true, GetDateTimeForTest()); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); @@ -95,10 +102,10 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests } [DataTestMethod] - [DataRow("time", "10:30:45 AM")] + [DataRow("time", "10:30:45 PM")] [DataRow("date", "3/2/2022")] - [DataRow("date and time", "3/2/2022 10:30:45 AM")] - [DataRow("hour", "10")] + [DataRow("date and time", "3/2/2022 10:30:45 PM")] + [DataRow("hour", "22")] [DataRow("minute", "30")] [DataRow("second", "45")] [DataRow("millisecond", "0")] @@ -113,13 +120,14 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("month and day", "March 2")] [DataRow("year", "2022")] [DataRow("month and year", "March 2022")] - [DataRow("ISO 8601", "2022-03-02T10:30:45")] - [DataRow("ISO 8601 with time zone", "2022-03-02T10:30:45")] - [DataRow("RFC1123", "Wed, 02 Mar 2022 10:30:45 GMT")] + [DataRow("ISO 8601", "2022-03-02T22:30:45")] + [DataRow("ISO 8601 with time zone", "2022-03-02T22:30:45")] + [DataRow("RFC1123", "Wed, 02 Mar 2022 22:30:45 GMT")] + [DataRow("Date and time in filename-compatible format", "2022-03-02_22-30-45")] public void LocalFormatsWithLongTimeAndShortDate(string formatLabel, string expectedResult) { // Setup - var helperResults = AvailableResultsList.GetList(true, true, false, new DateTime(2022, 03, 02, 10, 30, 45)); + var helperResults = AvailableResultsList.GetList(true, true, false, GetDateTimeForTest()); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); @@ -129,10 +137,10 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests } [DataTestMethod] - [DataRow("time", "10:30:45 AM")] + [DataRow("time", "10:30:45 PM")] [DataRow("date", "Wednesday, March 2, 2022")] - [DataRow("date and time", "Wednesday, March 2, 2022 10:30:45 AM")] - [DataRow("hour", "10")] + [DataRow("date and time", "Wednesday, March 2, 2022 10:30:45 PM")] + [DataRow("hour", "22")] [DataRow("minute", "30")] [DataRow("second", "45")] [DataRow("millisecond", "0")] @@ -147,13 +155,14 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("month and day", "March 2")] [DataRow("year", "2022")] [DataRow("month and year", "March 2022")] - [DataRow("ISO 8601", "2022-03-02T10:30:45")] - [DataRow("ISO 8601 with time zone", "2022-03-02T10:30:45")] - [DataRow("RFC1123", "Wed, 02 Mar 2022 10:30:45 GMT")] + [DataRow("ISO 8601", "2022-03-02T22:30:45")] + [DataRow("ISO 8601 with time zone", "2022-03-02T22:30:45")] + [DataRow("RFC1123", "Wed, 02 Mar 2022 22:30:45 GMT")] + [DataRow("Date and time in filename-compatible format", "2022-03-02_22-30-45")] public void LocalFormatsWithLongTimeAndLongDate(string formatLabel, string expectedResult) { // Setup - var helperResults = AvailableResultsList.GetList(true, true, true, new DateTime(2022, 03, 02, 10, 30, 45)); + var helperResults = AvailableResultsList.GetList(true, true, true, GetDateTimeForTest()); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); @@ -168,11 +177,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("ISO 8601 UTC", "yyyy-MM-ddTHH:mm:ss")] [DataRow("ISO 8601 UTC with time zone", "yyyy-MM-ddTHH:mm:ss'Z'")] [DataRow("Universal time format: YYYY-MM-DD hh:mm:ss", "u")] + [DataRow("Date and time in filename-compatible format", "yyyy-MM-dd_HH-mm-ss")] public void UtcFormatsWithShortTimeAndShortDate(string formatLabel, string expectedFormat) { // Setup - var helperResults = AvailableResultsList.GetList(true, false, false, new DateTime(2022, 03, 02, 10, 30, 45)); - var expectedResult = new DateTime(2022, 03, 02, 10, 30, 45).ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); + var helperResults = AvailableResultsList.GetList(true, false, false, GetDateTimeForTest()); + var expectedResult = GetDateTimeForTest().ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); @@ -187,11 +197,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("ISO 8601 UTC", "yyyy-MM-ddTHH:mm:ss")] [DataRow("ISO 8601 UTC with time zone", "yyyy-MM-ddTHH:mm:ss'Z'")] [DataRow("Universal time format: YYYY-MM-DD hh:mm:ss", "u")] + [DataRow("Date and time in filename-compatible format", "yyyy-MM-dd_HH-mm-ss")] public void UtcFormatsWithShortTimeAndLongDate(string formatLabel, string expectedFormat) { // Setup - var helperResults = AvailableResultsList.GetList(true, false, true, new DateTime(2022, 03, 02, 10, 30, 45)); - var expectedResult = new DateTime(2022, 03, 02, 10, 30, 45).ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); + var helperResults = AvailableResultsList.GetList(true, false, true, GetDateTimeForTest()); + var expectedResult = GetDateTimeForTest().ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); @@ -206,11 +217,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("ISO 8601 UTC", "yyyy-MM-ddTHH:mm:ss")] [DataRow("ISO 8601 UTC with time zone", "yyyy-MM-ddTHH:mm:ss'Z'")] [DataRow("Universal time format: YYYY-MM-DD hh:mm:ss", "u")] + [DataRow("Date and time in filename-compatible format", "yyyy-MM-dd_HH-mm-ss")] public void UtcFormatsWithLongTimeAndShortDate(string formatLabel, string expectedFormat) { // Setup - var helperResults = AvailableResultsList.GetList(true, true, false, new DateTime(2022, 03, 02, 10, 30, 45)); - var expectedResult = new DateTime(2022, 03, 02, 10, 30, 45).ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); + var helperResults = AvailableResultsList.GetList(true, true, false, GetDateTimeForTest()); + var expectedResult = GetDateTimeForTest().ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); @@ -225,11 +237,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests [DataRow("ISO 8601 UTC", "yyyy-MM-ddTHH:mm:ss")] [DataRow("ISO 8601 UTC with time zone", "yyyy-MM-ddTHH:mm:ss'Z'")] [DataRow("Universal time format: YYYY-MM-DD hh:mm:ss", "u")] + [DataRow("Date and time in filename-compatible format", "yyyy-MM-dd_HH-mm-ss")] public void UtcFormatsWithLongTimeAndLongDate(string formatLabel, string expectedFormat) { // Setup - var helperResults = AvailableResultsList.GetList(true, true, true, new DateTime(2022, 03, 02, 10, 30, 45)); - var expectedResult = new DateTime(2022, 03, 02, 10, 30, 45).ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); + var helperResults = AvailableResultsList.GetList(true, true, true, GetDateTimeForTest()); + var expectedResult = GetDateTimeForTest().ToUniversalTime().ToString(expectedFormat, CultureInfo.CurrentCulture); // Act var result = helperResults.FirstOrDefault(x => x.Label.Equals(formatLabel, StringComparison.OrdinalIgnoreCase)); diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Components/AvailableResultsList.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Components/AvailableResultsList.cs index 2dfc374485..e051d89568 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Components/AvailableResultsList.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Components/AvailableResultsList.cs @@ -256,6 +256,13 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), IconType = ResultIconType.DateTime, }, + new AvailableResult() + { + Value = dateTimeNow.ToString("yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture), + Label = Resources.Microsoft_plugin_timedate_filename_compatible, + AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), + IconType = ResultIconType.DateTime, + }, }); } diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.Designer.cs b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.Designer.cs index a7871ab040..41c0fc0398 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.Designer.cs +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.Designer.cs @@ -177,6 +177,15 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties { } } + /// + /// Looks up a localized string similar to Date and time in filename-compatible format. + /// + internal static string Microsoft_plugin_timedate_filename_compatible { + get { + return ResourceManager.GetString("Microsoft_plugin_timedate_filename_compatible", resourceCulture); + } + } + /// /// Looks up a localized string similar to Hour. /// diff --git a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.resx b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.resx index d9555e12c6..c5cd40c0a3 100644 --- a/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.resx +++ b/src/modules/launcher/Plugins/Microsoft.PowerToys.Run.Plugin.TimeDate/Properties/Resources.resx @@ -175,6 +175,10 @@ ISO 8601 UTC with time zone 'UTC' means here 'Universal Time Convention' + + Date and time in filename-compatible format + The format allows for embedding in filenames + Millisecond