mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-03 17:56:44 +02:00
* [PowerRename][Feature] Add new date/time formatting patterns to GetDatedFileName * [PowerRename][UI] Add date/time shortcut patterns to cheat sheet * [PowerRename][Tests] Add tests for new date/time formatting patterns * [PowerRename] [Refactor] Simplify AM/PM string handling in time patterns
This commit is contained in:
@@ -195,8 +195,15 @@ namespace winrt::PowerRenameUI::implementation
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$DDD", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_DayNameAbbr").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$DD", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_DayDigitLZero").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$D", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_DayDigit").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$hh", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_HoursLZero").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$h", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_Hours").ValueAsString()));
|
||||
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$HH", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_Hours12LZero").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$H", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_Hours12").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$TT", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_AMPMUpperCase").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$tt", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_AMPMLowerCase").ValueAsString()));
|
||||
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$hh", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_Hours24LZero").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$h", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_Hours24").ValueAsString()));
|
||||
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$mm", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_MinutesLZero").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$m", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_Minutes").ValueAsString()));
|
||||
m_dateTimeShortcuts.Append(winrt::make<PatternSnippet>(L"$ss", manager.MainResourceMap().GetValue(L"Resources/DateTimeCheatSheet_SecondsLZero").ValueAsString()));
|
||||
|
||||
@@ -219,11 +219,23 @@
|
||||
<data name="DateTimeCheatSheet_DayDigit" xml:space="preserve">
|
||||
<value>Day of the month as digits without leading zeros for single-digit days.</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_HoursLZero" xml:space="preserve">
|
||||
<value>Hours with leading zeros for single-digit hours.</value>
|
||||
<data name="DateTimeCheatSheet_Hours12LZero" xml:space="preserve">
|
||||
<value>Hours in 12-hour format (01-12) with leading zero.</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_Hours" xml:space="preserve">
|
||||
<value>Hours without leading zeros for single-digit hours.</value>
|
||||
<data name="DateTimeCheatSheet_Hours12" xml:space="preserve">
|
||||
<value>Hours in 12-hour format (1-12) without leading zero.</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_AMPMUpperCase" xml:space="preserve">
|
||||
<value>AM/PM indicator in uppercase (AM or PM).</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_AMPMLowerCase" xml:space="preserve">
|
||||
<value>AM/PM indicator in lowercase (am or pm).</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_Hours24LZero" xml:space="preserve">
|
||||
<value>Hours in 24-hour format (00-23) with leading zero.</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_Hours24" xml:space="preserve">
|
||||
<value>Hours in 24-hour format (0-23) without leading zero.</value>
|
||||
</data>
|
||||
<data name="DateTimeCheatSheet_MinutesLZero" xml:space="preserve">
|
||||
<value>Minutes with leading zeros for single-digit minutes.</value>
|
||||
|
||||
@@ -248,7 +248,19 @@ HRESULT GetTransformedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR sour
|
||||
bool isFileTimeUsed(_In_ PCWSTR source)
|
||||
{
|
||||
bool used = false;
|
||||
static const std::array patterns = { std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$Y" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$M" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$D" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$h" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$m" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$s" }, std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$f" } };
|
||||
static const std::array patterns = {
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$Y" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$M" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$D" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$h" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$m" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$s" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$f" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$H" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$T" },
|
||||
std::wregex{ L"(([^\\$]|^)(\\$\\$)*)\\$t" }
|
||||
};
|
||||
|
||||
for (size_t i = 0; !used && i < patterns.size(); i++)
|
||||
{
|
||||
if (std::regex_search(source, patterns[i]))
|
||||
@@ -275,6 +287,12 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
StringCchCopy(localeName, LOCALE_NAME_MAX_LENGTH, L"en_US");
|
||||
}
|
||||
|
||||
int hour12 = (fileTime.wHour % 12);
|
||||
if (hour12 == 0)
|
||||
{
|
||||
hour12 = 12;
|
||||
}
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%04d"), L"$01", fileTime.wYear);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$YYYY"), replaceTerm);
|
||||
|
||||
@@ -316,6 +334,18 @@ HRESULT GetDatedFileName(_Out_ PWSTR result, UINT cchMax, _In_ PCWSTR source, SY
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", fileTime.wDay);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$D"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", hour12);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$HH"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%d"), L"$01", hour12);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$H"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", (fileTime.wHour < 12) ? L"AM" : L"PM");
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$TT"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%s"), L"$01", (fileTime.wHour < 12) ? L"am" : L"pm");
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$tt"), replaceTerm);
|
||||
|
||||
StringCchPrintf(replaceTerm, MAX_PATH, TEXT("%s%02d"), L"$01", fileTime.wHour);
|
||||
res = regex_replace(res, std::wregex(L"(([^\\$]|^)(\\$\\$)*)\\$hh"), replaceTerm);
|
||||
|
||||
|
||||
@@ -127,5 +127,53 @@ TEST_METHOD(VerifyLookbehind)
|
||||
CoTaskMemFree(result);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD (Verify12and24HourTimeFormats)
|
||||
{
|
||||
CComPtr<IPowerRenameRegEx> renameRegEx;
|
||||
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
|
||||
DWORD flags = MatchAllOccurrences | UseRegularExpressions;
|
||||
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
|
||||
|
||||
struct TimeTestCase {
|
||||
SYSTEMTIME time; // Input time
|
||||
PCWSTR formatString; // Format pattern
|
||||
PCWSTR expectedResult; // Expected output
|
||||
PCWSTR description; // Description of what we're testing
|
||||
};
|
||||
|
||||
struct TimeTestCase testCases[] = {
|
||||
// Midnight (00:00 / 12:00 AM)
|
||||
{ { 2025, 4, 4, 10, 0, 0, 0, 0 }, L"[$hh:$mm] [$H:$mm $tt]", L"[00:00] [12:00 am]", L"Midnight formatting" },
|
||||
|
||||
// Noon (12:00 / 12:00 PM)
|
||||
{ { 2025, 4, 4, 10, 12, 0, 0, 0 }, L"[$hh:$mm] [$H:$mm $tt]", L"[12:00] [12:00 pm]", L"Noon formatting" },
|
||||
|
||||
// 1:05 AM
|
||||
{ { 2025, 4, 4, 10, 1, 5, 0, 0 }, L"[$h:$m] [$H:$m $tt] [$hh:$mm] [$HH:$mm $TT]",
|
||||
L"[1:5] [1:5 am] [01:05] [01:05 AM]", L"1 AM with various formats" },
|
||||
|
||||
// 11 PM
|
||||
{ { 2025, 4, 4, 10, 23, 45, 0, 0 }, L"[$h:$m] [$H:$m $tt] [$hh:$mm] [$HH:$mm $TT]",
|
||||
L"[23:45] [11:45 pm] [23:45] [11:45 PM]", L"11 PM with various formats" },
|
||||
|
||||
// Mixed formats in complex pattern
|
||||
{ { 2025, 4, 4, 10, 14, 30, 0, 0 }, L"Date: $YYYY-$MM-$DD Time: $hh:$mm (24h) / $H:$mm $tt (12h)",
|
||||
L"Date: 2025-04-10 Time: 14:30 (24h) / 2:30 pm (12h)", L"Complex combined format" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testCases); i++)
|
||||
{
|
||||
PWSTR result = nullptr;
|
||||
Assert::IsTrue(renameRegEx->PutSearchTerm(L"test") == S_OK);
|
||||
Assert::IsTrue(renameRegEx->PutReplaceTerm(testCases[i].formatString) == S_OK);
|
||||
Assert::IsTrue(renameRegEx->PutFileTime(testCases[i].time) == S_OK);
|
||||
unsigned long index = {};
|
||||
Assert::IsTrue(renameRegEx->Replace(L"test", &result, index) == S_OK);
|
||||
Assert::IsTrue(wcscmp(result, testCases[i].expectedResult) == 0,
|
||||
(std::wstring(L"Failed test case: ") + testCases[i].description).c_str());
|
||||
CoTaskMemFree(result);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -207,5 +207,53 @@ TEST_METHOD(VerifyLookbehindFails)
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD (Verify12and24HourTimeFormats)
|
||||
{
|
||||
CComPtr<IPowerRenameRegEx> renameRegEx;
|
||||
Assert::IsTrue(CPowerRenameRegEx::s_CreateInstance(&renameRegEx) == S_OK);
|
||||
DWORD flags = MatchAllOccurrences | UseRegularExpressions;
|
||||
Assert::IsTrue(renameRegEx->PutFlags(flags) == S_OK);
|
||||
|
||||
struct TimeTestCase {
|
||||
SYSTEMTIME time; // Input time
|
||||
PCWSTR formatString; // Format pattern
|
||||
PCWSTR expectedResult; // Expected output
|
||||
PCWSTR description; // Description of what we're testing
|
||||
};
|
||||
|
||||
struct TimeTestCase testCases[] = {
|
||||
// Midnight (00:00 / 12:00 AM)
|
||||
{ { 2025, 4, 4, 10, 0, 0, 0, 0 }, L"[$hh:$mm] [$H:$mm $tt]", L"[00:00] [12:00 am]", L"Midnight formatting" },
|
||||
|
||||
// Noon (12:00 / 12:00 PM)
|
||||
{ { 2025, 4, 4, 10, 12, 0, 0, 0 }, L"[$hh:$mm] [$H:$mm $tt]", L"[12:00] [12:00 pm]", L"Noon formatting" },
|
||||
|
||||
// 1:05 AM
|
||||
{ { 2025, 4, 4, 10, 1, 5, 0, 0 }, L"[$h:$m] [$H:$m $tt] [$hh:$mm] [$HH:$mm $TT]",
|
||||
L"[1:5] [1:5 am] [01:05] [01:05 AM]", L"1 AM with various formats" },
|
||||
|
||||
// 11 PM
|
||||
{ { 2025, 4, 4, 10, 23, 45, 0, 0 }, L"[$h:$m] [$H:$m $tt] [$hh:$mm] [$HH:$mm $TT]",
|
||||
L"[23:45] [11:45 pm] [23:45] [11:45 PM]", L"11 PM with various formats" },
|
||||
|
||||
// Mixed formats in complex pattern
|
||||
{ { 2025, 4, 4, 10, 14, 30, 0, 0 }, L"Date: $YYYY-$MM-$DD Time: $hh:$mm (24h) / $H:$mm $tt (12h)",
|
||||
L"Date: 2025-04-10 Time: 14:30 (24h) / 2:30 pm (12h)", L"Complex combined format" },
|
||||
};
|
||||
|
||||
for (int i = 0; i < ARRAYSIZE(testCases); i++)
|
||||
{
|
||||
PWSTR result = nullptr;
|
||||
Assert::IsTrue(renameRegEx->PutSearchTerm(L"test") == S_OK);
|
||||
Assert::IsTrue(renameRegEx->PutReplaceTerm(testCases[i].formatString) == S_OK);
|
||||
Assert::IsTrue(renameRegEx->PutFileTime(testCases[i].time) == S_OK);
|
||||
unsigned long index = {};
|
||||
Assert::IsTrue(renameRegEx->Replace(L"test", &result, index) == S_OK);
|
||||
Assert::IsTrue(wcscmp(result, testCases[i].expectedResult) == 0,
|
||||
(std::wstring(L"Failed test case: ") + testCases[i].description).c_str());
|
||||
CoTaskMemFree(result);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user