mirror of
https://github.com/microsoft/PowerToys.git
synced 2025-12-15 11:17:53 +01:00
[PTRun][TimeDate]Unix Time in milliseconds, fix negative unix time input, error message improvement (#29149)
* add unix time in ms * update dev docs * unit tests * fix spell check * tool tip * fix negative unix time input, improve regex, update unit tests, improve error message * Update error handling and tests * add tests and fix spelling * small fixes
This commit is contained in:
1
.github/actions/spell-check/expect.txt
vendored
1
.github/actions/spell-check/expect.txt
vendored
@@ -1983,6 +1983,7 @@ uipi
|
||||
UIs
|
||||
ULARGE
|
||||
ULONGLONG
|
||||
ums
|
||||
unapply
|
||||
unassign
|
||||
uncompilable
|
||||
|
||||
@@ -18,6 +18,7 @@ The 'Time and Date' plugin shows the date and time in different formats. For the
|
||||
**Remarks**
|
||||
- The following formats requires a prefix in the query:
|
||||
- Unix Timestamp: `u`
|
||||
- Unix Timestamp in milliseconds: `ums`
|
||||
- Windows file time: `ft`
|
||||
- On invalid number inputs we show a warning that tells the user which prefixes are allowed/required.
|
||||
|
||||
@@ -33,6 +34,7 @@ The following formats are currently available:
|
||||
| Time UTC | 4:10 PM | x | x |
|
||||
| Now UTC | 3/5/2022 4:10 PM | x | x |
|
||||
| Unix Timestamp | 1646496622 | x | x |
|
||||
| Unix Timestamp in milliseconds | 1646496622500 | x | x |
|
||||
| Hour | 10 | x | |
|
||||
| Minute | 30 | x | |
|
||||
| Second | 45 | x | |
|
||||
|
||||
@@ -36,6 +36,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
[DataRow("now", "Now -", "Images\\timeDate.dark.png")]
|
||||
[DataRow("now u", "Now UTC -", "Images\\timeDate.dark.png")]
|
||||
[DataRow("unix", "Unix epoch time -", "Images\\timeDate.dark.png")]
|
||||
[DataRow("unix epoch time in", "Unix epoch time in milliseconds -", "Images\\timeDate.dark.png")]
|
||||
[DataRow("hour", "Hour -", "Images\\time.dark.png")]
|
||||
[DataRow("minute", "Minute -", "Images\\time.dark.png")]
|
||||
[DataRow("second", "Second -", "Images\\time.dark.png")]
|
||||
@@ -82,6 +83,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
[DataRow("now", "Now -", "Images\\timeDate.light.png")]
|
||||
[DataRow("now u", "Now UTC -", "Images\\timeDate.light.png")]
|
||||
[DataRow("unix", "Unix epoch time -", "Images\\timeDate.light.png")]
|
||||
[DataRow("unix epoch time in", "Unix epoch time in milliseconds -", "Images\\timeDate.light.png")]
|
||||
[DataRow("hour", "Hour -", "Images\\time.light.png")]
|
||||
[DataRow("minute", "Minute -", "Images\\time.light.png")]
|
||||
[DataRow("second", "Second -", "Images\\time.light.png")]
|
||||
|
||||
@@ -31,13 +31,13 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("time", 2)]
|
||||
[DataRow("date", 2)]
|
||||
[DataRow("now", 3)]
|
||||
[DataRow("current", 3)]
|
||||
[DataRow("year", 0)]
|
||||
[DataRow("time::10:10:10", 0)]
|
||||
[DataRow("date::10/10/10", 0)]
|
||||
[DataRow("time", 2)] // Setting 'Only Date, Time, Now on global results' is default on
|
||||
[DataRow("date", 2)] // Setting 'Only Date, Time, Now on global results' is default on
|
||||
[DataRow("now", 3)] // Setting 'Only Date, Time, Now on global results' is default on
|
||||
[DataRow("current", 3)] // Setting 'Only Date, Time, Now on global results' is default on
|
||||
[DataRow("year", 0)] // Setting 'Only Date, Time, Now on global results' is default on
|
||||
[DataRow("time::10:10:10", 0)] // Setting 'Only Date, Time, Now on global results' is default on
|
||||
[DataRow("date::10/10/10", 0)] // Setting 'Only Date, Time, Now on global results' is default on
|
||||
public void CountWithoutPluginKeyword(string typedString, int expectedResultCount)
|
||||
{
|
||||
// Setup
|
||||
@@ -52,12 +52,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("(time", 17)]
|
||||
[DataRow("(date", 25)]
|
||||
[DataRow("(time", 18)]
|
||||
[DataRow("(date", 26)]
|
||||
[DataRow("(year", 7)]
|
||||
[DataRow("(now", 31)]
|
||||
[DataRow("(current", 31)]
|
||||
[DataRow("(", 31)]
|
||||
[DataRow("(now", 32)]
|
||||
[DataRow("(current", 32)]
|
||||
[DataRow("(", 32)]
|
||||
[DataRow("(now::10:10:10", 1)] // Windows file time
|
||||
[DataRow("(current::10:10:10", 0)]
|
||||
public void CountWithPluginKeyword(string typedString, int expectedResultCount)
|
||||
@@ -104,6 +104,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
[DataRow("(now", "Now -")]
|
||||
[DataRow("(now u", "Now UTC -")]
|
||||
[DataRow("(unix", "Unix epoch time -")]
|
||||
[DataRow("(unix epoch time in milli", "Unix epoch time in milliseconds -")]
|
||||
[DataRow("(file", "Windows file time (Int64 number) ")]
|
||||
[DataRow("(hour", "Hour -")]
|
||||
[DataRow("(minute", "Minute -")]
|
||||
@@ -156,6 +157,11 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
[DataRow("(12:30", "Time -")]
|
||||
[DataRow("(10.10.2022", "Date -")]
|
||||
[DataRow("(u1646408119", "Date and time -")]
|
||||
[DataRow("(u+1646408119", "Date and time -")]
|
||||
[DataRow("(u-1646408119", "Date and time -")]
|
||||
[DataRow("(ums1646408119", "Date and time -")]
|
||||
[DataRow("(ums+1646408119", "Date and time -")]
|
||||
[DataRow("(ums-1646408119", "Date and time -")]
|
||||
[DataRow("(ft637820085517321977", "Date and time -")]
|
||||
public void DateTimeNumberOnlyInput(string typedString, string expectedResult)
|
||||
{
|
||||
@@ -176,15 +182,10 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
[DataTestMethod]
|
||||
[DataRow("(abcdefg")]
|
||||
[DataRow("(timmmmeeee")]
|
||||
[DataRow("(10.10.20.aa.22")]
|
||||
[DataRow("(12::55")]
|
||||
[DataRow("(12:aa:55")]
|
||||
[DataRow("(timtaaaetetaae::u1646408119")]
|
||||
[DataRow("(time:eeee")]
|
||||
[DataRow("(time::eeee")]
|
||||
[DataRow("(time//eeee")]
|
||||
[DataRow("(date::12::55")]
|
||||
[DataRow("(date::12:aa:55")]
|
||||
public void InvalidInputNotShowsResults(string typedString)
|
||||
{
|
||||
// Setup
|
||||
@@ -201,8 +202,23 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
[DataTestMethod]
|
||||
[DataRow("(ug1646408119")] // Invalid prefix
|
||||
[DataRow("(u9999999999999")] // Unix number + prefix is longer than 12 characters
|
||||
[DataRow("(ums999999999999999")] // Unix number in milliseconds + prefix is longer than 17 characters
|
||||
[DataRow("(-u99999999999")] // Unix number with wrong placement of - sign
|
||||
[DataRow("(+ums9999999999")] // Unix number in milliseconds with wrong placement of + sign
|
||||
[DataRow("(0123456")] // Missing prefix
|
||||
[DataRow("(ft63782008ab55173dasdas21977")] // Number contains letters
|
||||
[DataRow("(ft63782008ab55173dasdas")] // Number contains letters at the end
|
||||
[DataRow("(ft12..548")] // Number contains wrong punctuation
|
||||
[DataRow("(ft12..54//8")] // Number contains wrong punctuation and other characters
|
||||
[DataRow("(time::ft12..54//8")] // Number contains wrong punctuation and other characters
|
||||
[DataRow("(ut2ed.5555")] // Number contains letters
|
||||
[DataRow("(12..54//8")] // Number contains punctuation and other characters, but no special prefix
|
||||
[DataRow("(ft::1288gg8888")] // Number contains delimiter and letters, but no special prefix
|
||||
[DataRow("(date::12::55")]
|
||||
[DataRow("(date::12:aa:55")]
|
||||
[DataRow("(10.aa.22")]
|
||||
[DataRow("(12::55")]
|
||||
[DataRow("(12:aa:55")]
|
||||
public void InvalidNumberInputShowsErrorMessage(string typedString)
|
||||
{
|
||||
// Setup
|
||||
@@ -217,10 +233,12 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
}
|
||||
|
||||
[DataTestMethod]
|
||||
[DataRow("(ft12..548")] // Number contains punctuation
|
||||
[DataRow("(ft12..54//8")] // Number contains punctuation and other characters
|
||||
[DataRow("(12..54//8")] // Number contains punctuation and other characters
|
||||
[DataRow("(ft::1288gg8888")] // Number contains delimiter and other characters
|
||||
[DataRow("(ft1 2..548")] // Input contains space
|
||||
[DataRow("(ft12..54 //8")] // Input contains space
|
||||
[DataRow("(time::ft12..54 //8")] // Input contains space
|
||||
[DataRow("(10.10aa")] // Input contains <Number>.<Number> (Can be part of a date.)
|
||||
[DataRow("(10:10aa")] // Input contains <Number>:<Number> (Can be part of a time.)
|
||||
[DataRow("(10/10aa")] // Input contains <Number>/<Number> (Can be part of a date.)
|
||||
public void InvalidInputNotShowsErrorMessage(string typedString)
|
||||
{
|
||||
// Setup
|
||||
|
||||
@@ -34,6 +34,11 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.UnitTests
|
||||
[DataRow("5:05:10 PM", true, "T", "5:05:10 PM")]
|
||||
[DataRow("10456", false, "", "")]
|
||||
[DataRow("u10456", true, "", "")] // Value is UTC and can be different based on system
|
||||
[DataRow("u-10456", true, "", "")] // Value is UTC and can be different based on system
|
||||
[DataRow("u+10456", true, "", "")] // Value is UTC and can be different based on system
|
||||
[DataRow("ums10456", true, "", "")] // Value is UTC and can be different based on system
|
||||
[DataRow("ums-10456", true, "", "")] // Value is UTC and can be different based on system
|
||||
[DataRow("ums+10456", true, "", "")] // Value is UTC and can be different based on system
|
||||
[DataRow("ft10456", true, "", "")] // Value is UTC and can be different based on system
|
||||
public void ConvertStringToDateTime(string typedString, bool expectedBool, string stringType, string expectedString)
|
||||
{
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
|
||||
{
|
||||
// We use long instead of int for unix time stamp because int is too small after 03:14:07 UTC 2038-01-19
|
||||
long unixTimestamp = (long)dateTimeNowUtc.Subtract(new DateTime(1970, 1, 1)).TotalSeconds;
|
||||
long unixTimestampMilliseconds = (long)dateTimeNowUtc.Subtract(new DateTime(1970, 1, 1)).TotalMilliseconds;
|
||||
int weekOfYear = calendar.GetWeekOfYear(dateTimeNow, DateTimeFormatInfo.CurrentInfo.CalendarWeekRule, DateTimeFormatInfo.CurrentInfo.FirstDayOfWeek);
|
||||
string era = DateTimeFormatInfo.CurrentInfo.GetEraName(calendar.GetEra(dateTimeNow));
|
||||
string eraShort = DateTimeFormatInfo.CurrentInfo.GetAbbreviatedEraName(calendar.GetEra(dateTimeNow));
|
||||
@@ -89,6 +90,13 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
|
||||
IconType = ResultIconType.DateTime,
|
||||
},
|
||||
new AvailableResult()
|
||||
{
|
||||
Value = unixTimestampMilliseconds.ToString(CultureInfo.CurrentCulture),
|
||||
Label = Resources.Microsoft_plugin_timedate_Unix_Milliseconds,
|
||||
AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"),
|
||||
IconType = ResultIconType.DateTime,
|
||||
},
|
||||
new AvailableResult()
|
||||
{
|
||||
Value = dateTimeNow.Hour.ToString(CultureInfo.CurrentCulture),
|
||||
Label = Resources.Microsoft_plugin_timedate_Hour,
|
||||
|
||||
@@ -86,6 +86,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
|
||||
{
|
||||
Title = Resources.Microsoft_plugin_timedate_ErrorResultTitle,
|
||||
SubTitle = Resources.Microsoft_plugin_timedate_ErrorResultSubTitle,
|
||||
ToolTipData = new ToolTipData(Resources.Microsoft_plugin_timedate_ErrorResultTitle, Resources.Microsoft_plugin_timedate_ErrorResultSubTitle),
|
||||
IcoPath = $"Images\\Warning.{theme}.png",
|
||||
};
|
||||
}
|
||||
|
||||
@@ -121,8 +121,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
|
||||
}
|
||||
|
||||
// If search term is only a number that can't be parsed return an error message
|
||||
if (!isEmptySearchInput && results.Count == 0 && searchTerm.Any(char.IsNumber) && Regex.IsMatch(searchTerm, @"\w+\d+$") &&
|
||||
!searchTerm.Contains(InputDelimiter) && !searchTerm.Any(char.IsWhiteSpace) && !searchTerm.Any(char.IsPunctuation))
|
||||
if (!isEmptySearchInput && results.Count == 0 && Regex.IsMatch(searchTerm, @"\w+\d+.*$") && !searchTerm.Any(char.IsWhiteSpace) && (TimeAndDateHelper.IsSpecialInputParsing(searchTerm) || !Regex.IsMatch(searchTerm, @"\d+[\.:/]\d+")))
|
||||
{
|
||||
// Without plugin key word show only if message is not hidden by setting
|
||||
if (isKeywordSearch || !TimeDateSettings.Instance.HideNumberMessageOnGlobalQuery)
|
||||
|
||||
@@ -96,17 +96,24 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
|
||||
// Known date/time format
|
||||
return true;
|
||||
}
|
||||
else if (Regex.IsMatch(input, @"^u\d+") && input.Length <= 12 && long.TryParse(input.TrimStart('u'), out long secondsInt))
|
||||
else if (Regex.IsMatch(input, @"^u[\+-]?\d{1,10}$") && long.TryParse(input.TrimStart('u'), out long secondsU))
|
||||
{
|
||||
// unix time stamp
|
||||
// we use long instead of int because int is too small after 03:14:07 UTC 2038-01-19
|
||||
timestamp = new DateTime(1970, 1, 1).AddSeconds(secondsInt).ToLocalTime();
|
||||
timestamp = new DateTime(1970, 1, 1).AddSeconds(secondsU).ToLocalTime();
|
||||
return true;
|
||||
}
|
||||
else if (Regex.IsMatch(input, @"^ft\d+") && long.TryParse(input.TrimStart("ft".ToCharArray()), out long secondsLong))
|
||||
else if (Regex.IsMatch(input, @"^ums[\+-]?\d{1,13}$") && long.TryParse(input.TrimStart("ums".ToCharArray()), out long millisecondsUms))
|
||||
{
|
||||
// unix time stamp in milliseconds
|
||||
// we use long instead of int because int is too small after 03:14:07 UTC 2038-01-19
|
||||
timestamp = new DateTime(1970, 1, 1).AddMilliseconds(millisecondsUms).ToLocalTime();
|
||||
return true;
|
||||
}
|
||||
else if (Regex.IsMatch(input, @"^ft\d+$") && long.TryParse(input.TrimStart("ft".ToCharArray()), out long secondsFt))
|
||||
{
|
||||
// windows file time
|
||||
timestamp = new DateTime(secondsLong);
|
||||
timestamp = new DateTime(secondsFt);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
@@ -115,6 +122,16 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Components
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test if input is special parsing for Unix time, Unix time in milliseconds or File time.
|
||||
/// </summary>
|
||||
/// <param name="input">String with date/time</param>
|
||||
/// <returns>True if yes, otherwise false</returns>
|
||||
internal static bool IsSpecialInputParsing(string input)
|
||||
{
|
||||
return Regex.IsMatch(input, @"^.*(u|ums|ft)\d");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -160,7 +160,7 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Valid prefixes: 'u' for Unix Timestamp, 'ft' for Windows file time.
|
||||
/// Looks up a localized string similar to Valid prefixes: 'u' for Unix Timestamp, 'ums' for Unix Timestamp in milliseconds, 'ft' for Windows file time.
|
||||
/// </summary>
|
||||
internal static string Microsoft_plugin_timedate_ErrorResultSubTitle {
|
||||
get {
|
||||
@@ -555,6 +555,15 @@ namespace Microsoft.PowerToys.Run.Plugin.TimeDate.Properties {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Unix epoch time in milliseconds.
|
||||
/// </summary>
|
||||
internal static string Microsoft_plugin_timedate_Unix_Milliseconds {
|
||||
get {
|
||||
return ResourceManager.GetString("Microsoft_plugin_timedate_Unix_Milliseconds", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Week of the month.
|
||||
/// </summary>
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
<value>Era abbreviation</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_ErrorResultSubTitle" xml:space="preserve">
|
||||
<value>Valid prefixes: 'u' for Unix Timestamp, 'ft' for Windows file time</value>
|
||||
<value>Valid prefixes: 'u' for Unix Timestamp, 'ums' for Unix Timestamp in milliseconds, 'ft' for Windows file time</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_ErrorResultTitle" xml:space="preserve">
|
||||
<value>Error: Invalid number input</value>
|
||||
@@ -312,4 +312,7 @@
|
||||
<data name="Microsoft_plugin_timedate_Year" xml:space="preserve">
|
||||
<value>Year</value>
|
||||
</data>
|
||||
<data name="Microsoft_plugin_timedate_Unix_Milliseconds" xml:space="preserve">
|
||||
<value>Unix epoch time in milliseconds</value>
|
||||
</data>
|
||||
</root>
|
||||
Reference in New Issue
Block a user