AvailableResultsList.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System; 6 using System.Collections.Generic; 7 using System.Globalization; 8 using System.Linq; 9 using System.Text.RegularExpressions; 10 using ManagedCommon; 11 12 namespace Microsoft.CmdPal.Ext.TimeDate.Helpers; 13 14 internal static class AvailableResultsList 15 { 16 /// <summary> 17 /// Returns a list with all available date time formats 18 /// </summary> 19 /// <param name="timeLongFormat">Required for UnitTest: Show time in long format</param> 20 /// <param name="dateLongFormat">Required for UnitTest: Show date in long format</param> 21 /// <param name="timestamp">Use custom <see cref="DateTime"/> object to calculate results instead of the system date/time</param> 22 /// <param name="firstWeekOfYear">Required for UnitTest: Use custom first week of the year instead of the plugin setting.</param> 23 /// <param name="firstDayOfWeek">Required for UnitTest: Use custom first day of the week instead the plugin setting.</param> 24 /// <returns>List of results</returns> 25 internal static List<AvailableResult> GetList(bool isKeywordSearch, ISettingsInterface settings, bool? timeLongFormat = null, bool? dateLongFormat = null, DateTime? timestamp = null, CalendarWeekRule? firstWeekOfYear = null, DayOfWeek? firstDayOfWeek = null) 26 { 27 var results = new List<AvailableResult>(); 28 var calendar = CultureInfo.CurrentCulture.Calendar; 29 30 var timeExtended = timeLongFormat ?? settings.TimeWithSecond; 31 var dateExtended = dateLongFormat ?? settings.DateWithWeekday; 32 var isSystemDateTime = timestamp is null; 33 var dateTimeNow = timestamp ?? DateTime.Now; 34 var dateTimeNowUtc = dateTimeNow.ToUniversalTime(); 35 var firstWeekRule = firstWeekOfYear ?? TimeAndDateHelper.GetCalendarWeekRule(settings.FirstWeekOfYear); 36 var firstDayOfTheWeek = firstDayOfWeek ?? TimeAndDateHelper.GetFirstDayOfWeek(settings.FirstDayOfWeek); 37 var weekOfYear = calendar.GetWeekOfYear(dateTimeNow, firstWeekRule, firstDayOfTheWeek); 38 39 results.AddRange(new[] 40 { 41 // This range is reserved for the following three results: Time, Date, Now 42 // Don't add any new result in this range! For new results, please use the next range. 43 new AvailableResult() 44 { 45 Value = dateTimeNow.ToString(TimeAndDateHelper.GetStringFormat(FormatStringType.Time, timeExtended, dateExtended), CultureInfo.CurrentCulture), 46 Label = Resources.Microsoft_plugin_timedate_Time, 47 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, string.Empty, "Microsoft_plugin_timedate_SearchTagTimeNow"), 48 IconType = ResultIconType.Time, 49 }, 50 new AvailableResult() 51 { 52 Value = dateTimeNow.ToString(TimeAndDateHelper.GetStringFormat(FormatStringType.Date, timeExtended, dateExtended), CultureInfo.CurrentCulture), 53 Label = Resources.Microsoft_plugin_timedate_Date, 54 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, string.Empty, "Microsoft_plugin_timedate_SearchTagDateNow"), 55 IconType = ResultIconType.Date, 56 }, 57 new AvailableResult() 58 { 59 Value = dateTimeNow.ToString(TimeAndDateHelper.GetStringFormat(FormatStringType.DateTime, timeExtended, dateExtended), CultureInfo.CurrentCulture), 60 Label = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_DateAndTime", "Microsoft_plugin_timedate_Now"), 61 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 62 IconType = ResultIconType.DateTime, 63 }, 64 new AvailableResult() 65 { 66 Value = weekOfYear.ToString(CultureInfo.CurrentCulture), 67 Label = Resources.Microsoft_plugin_timedate_WeekOfYear, 68 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 69 IconType = ResultIconType.Date, 70 }, 71 }); 72 73 if (isKeywordSearch) 74 { 75 // We use long instead of int for unix time stamp because int is too small after 03:14:07 UTC 2038-01-19 76 var unixTimestamp = ((DateTimeOffset)dateTimeNowUtc).ToUnixTimeSeconds(); 77 var unixTimestampMilliseconds = ((DateTimeOffset)dateTimeNowUtc).ToUnixTimeMilliseconds(); 78 var era = DateTimeFormatInfo.CurrentInfo.GetEraName(calendar.GetEra(dateTimeNow)); 79 var eraShort = DateTimeFormatInfo.CurrentInfo.GetAbbreviatedEraName(calendar.GetEra(dateTimeNow)); 80 81 // Custom formats 82 foreach (var f in settings.CustomFormats) 83 { 84 var formatParts = f.Split("=", 2, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries); 85 var formatSyntax = formatParts.Length == 2 ? formatParts[1] : string.Empty; 86 var searchTags = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagCustom"); 87 var dtObject = dateTimeNow; 88 89 // If Length = 0 then empty string. 90 if (formatParts.Length >= 1) 91 { 92 try 93 { 94 // Verify and check input and update search tags 95 if (formatParts.Length == 1) 96 { 97 throw new FormatException("Format syntax part after equal sign is missing."); 98 } 99 100 var containsCustomSyntax = TimeAndDateHelper.StringContainsCustomFormatSyntax(formatSyntax); 101 if (formatSyntax.StartsWith("UTC:", StringComparison.InvariantCulture)) 102 { 103 searchTags = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagCustomUtc"); 104 dtObject = dateTimeNowUtc; 105 } 106 107 // Get formatted date 108 var value = TimeAndDateHelper.ConvertToCustomFormat(dtObject, unixTimestamp, unixTimestampMilliseconds, weekOfYear, eraShort, Regex.Replace(formatSyntax, "^UTC:", string.Empty), firstWeekRule, firstDayOfTheWeek); 109 try 110 { 111 value = dtObject.ToString(value, CultureInfo.CurrentCulture); 112 } 113 catch (Exception ex) 114 { 115 if (!containsCustomSyntax) 116 { 117 Logger.LogError($"Unable to format date time with format: {value}. Error: {ex.Message}"); 118 throw; 119 } 120 else 121 { 122 // Do not fail as we have custom format syntax. Instead fix backslashes. 123 value = Regex.Replace(value, @"(?<!\\)\\", string.Empty).Replace("\\\\", "\\"); 124 } 125 } 126 127 // Add result 128 results.Add(new AvailableResult() 129 { 130 Value = value, 131 Label = formatParts[0], 132 AlternativeSearchTag = searchTags, 133 IconType = ResultIconType.DateTime, 134 }); 135 } 136 catch (ArgumentOutOfRangeException e) 137 { 138 Logger.LogError($"ArgumentOutOfRangeException with format: {formatSyntax}. Error: {e.Message}"); 139 results.Add(new AvailableResult() 140 { 141 Value = Resources.Microsoft_plugin_timedate_ErrorConvertCustomFormat, 142 Label = formatParts[0] + " - " + Resources.Microsoft_plugin_timedate_show_details, 143 AlternativeSearchTag = searchTags, 144 IconType = ResultIconType.Error, 145 ErrorDetails = e.Message, 146 }); 147 } 148 catch (Exception e) 149 { 150 Logger.LogError($"Exception with format: {formatSyntax}. Error: {e.Message}"); 151 results.Add(new AvailableResult() 152 { 153 Value = Resources.Microsoft_plugin_timedate_InvalidCustomFormat + " " + formatSyntax, 154 Label = formatParts[0] + " - " + Resources.Microsoft_plugin_timedate_show_details, 155 AlternativeSearchTag = searchTags, 156 IconType = ResultIconType.Error, 157 ErrorDetails = e.Message, 158 }); 159 } 160 } 161 } 162 163 // Predefined formats 164 results.AddRange(new[] 165 { 166 new AvailableResult() 167 { 168 Value = dateTimeNowUtc.ToString(TimeAndDateHelper.GetStringFormat(FormatStringType.Time, timeExtended, dateExtended), CultureInfo.CurrentCulture), 169 Label = Resources.Microsoft_plugin_timedate_TimeUtc, 170 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, string.Empty, "Microsoft_plugin_timedate_SearchTagTimeNow"), 171 IconType = ResultIconType.Time, 172 }, 173 new AvailableResult() 174 { 175 Value = dateTimeNowUtc.ToString(TimeAndDateHelper.GetStringFormat(FormatStringType.DateTime, timeExtended, dateExtended), CultureInfo.CurrentCulture), 176 Label = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_DateAndTimeUtc", "Microsoft_plugin_timedate_NowUtc"), 177 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 178 IconType = ResultIconType.DateTime, 179 }, 180 new AvailableResult() 181 { 182 Value = unixTimestamp.ToString(CultureInfo.CurrentCulture), 183 Label = Resources.Microsoft_plugin_timedate_Unix, 184 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 185 IconType = ResultIconType.DateTime, 186 }, 187 new AvailableResult() 188 { 189 Value = unixTimestampMilliseconds.ToString(CultureInfo.CurrentCulture), 190 Label = Resources.Microsoft_plugin_timedate_Unix_Milliseconds, 191 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 192 IconType = ResultIconType.DateTime, 193 }, 194 new AvailableResult() 195 { 196 Value = dateTimeNow.Hour.ToString(CultureInfo.CurrentCulture), 197 Label = Resources.Microsoft_plugin_timedate_Hour, 198 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagTime"), 199 IconType = ResultIconType.Time, 200 }, 201 new AvailableResult() 202 { 203 Value = dateTimeNow.Minute.ToString(CultureInfo.CurrentCulture), 204 Label = Resources.Microsoft_plugin_timedate_Minute, 205 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagTime"), 206 IconType = ResultIconType.Time, 207 }, 208 new AvailableResult() 209 { 210 Value = dateTimeNow.Second.ToString(CultureInfo.CurrentCulture), 211 Label = Resources.Microsoft_plugin_timedate_Second, 212 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagTime"), 213 IconType = ResultIconType.Time, 214 }, 215 new AvailableResult() 216 { 217 Value = dateTimeNow.Millisecond.ToString(CultureInfo.CurrentCulture), 218 Label = Resources.Microsoft_plugin_timedate_Millisecond, 219 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagTime"), 220 IconType = ResultIconType.Time, 221 }, 222 new AvailableResult() 223 { 224 Value = DateTimeFormatInfo.CurrentInfo.GetDayName(dateTimeNow.DayOfWeek), 225 Label = Resources.Microsoft_plugin_timedate_Day, 226 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 227 IconType = ResultIconType.Date, 228 }, 229 new AvailableResult() 230 { 231 Value = TimeAndDateHelper.GetNumberOfDayInWeek(dateTimeNow, firstDayOfTheWeek).ToString(CultureInfo.CurrentCulture), 232 Label = Resources.Microsoft_plugin_timedate_DayOfWeek, 233 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 234 IconType = ResultIconType.Date, 235 }, 236 new AvailableResult() 237 { 238 Value = dateTimeNow.Day.ToString(CultureInfo.CurrentCulture), 239 Label = Resources.Microsoft_plugin_timedate_DayOfMonth, 240 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 241 IconType = ResultIconType.Date, 242 }, 243 new AvailableResult() 244 { 245 Value = DateTime.DaysInMonth(dateTimeNow.Year, dateTimeNow.Month).ToString(CultureInfo.CurrentCulture), 246 Label = Resources.Microsoft_plugin_timedate_DaysInMonth, 247 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 248 IconType = ResultIconType.Date, 249 }, 250 new AvailableResult() 251 { 252 Value = dateTimeNow.DayOfYear.ToString(CultureInfo.CurrentCulture), 253 Label = Resources.Microsoft_plugin_timedate_DayOfYear, 254 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 255 IconType = ResultIconType.Date, 256 }, 257 new AvailableResult() 258 { 259 Value = TimeAndDateHelper.GetWeekOfMonth(dateTimeNow, firstDayOfTheWeek).ToString(CultureInfo.CurrentCulture), 260 Label = Resources.Microsoft_plugin_timedate_WeekOfMonth, 261 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 262 IconType = ResultIconType.Date, 263 }, 264 new AvailableResult() 265 { 266 Value = DateTimeFormatInfo.CurrentInfo.GetMonthName(dateTimeNow.Month), 267 Label = Resources.Microsoft_plugin_timedate_Month, 268 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 269 IconType = ResultIconType.Date, 270 }, 271 new AvailableResult() 272 { 273 Value = dateTimeNow.Month.ToString(CultureInfo.CurrentCulture), 274 Label = Resources.Microsoft_plugin_timedate_MonthOfYear, 275 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 276 IconType = ResultIconType.Date, 277 }, 278 new AvailableResult() 279 { 280 Value = dateTimeNow.ToString("M", CultureInfo.CurrentCulture), 281 Label = Resources.Microsoft_plugin_timedate_DayMonth, 282 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 283 IconType = ResultIconType.Date, 284 }, 285 new AvailableResult() 286 { 287 Value = calendar.GetYear(dateTimeNow).ToString(CultureInfo.CurrentCulture), 288 Label = Resources.Microsoft_plugin_timedate_Year, 289 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 290 IconType = ResultIconType.Date, 291 }, 292 new AvailableResult() 293 { 294 Value = DateTime.IsLeapYear(dateTimeNow.Year) ? Resources.Microsoft_plugin_timedate_LeapYear : Resources.Microsoft_plugin_timedate_NoLeapYear, 295 Label = Resources.Microsoft_plugin_timedate_LeapYear, 296 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 297 IconType = ResultIconType.Date, 298 }, 299 new AvailableResult() 300 { 301 Value = era, 302 Label = Resources.Microsoft_plugin_timedate_Era, 303 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagEra"), 304 IconType = ResultIconType.Date, 305 }, 306 new AvailableResult() 307 { 308 Value = era != eraShort ? eraShort : string.Empty, // Setting value to empty string if 'era == eraShort'. This result will be filtered later. 309 Label = Resources.Microsoft_plugin_timedate_EraAbbreviation, 310 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagEra"), 311 IconType = ResultIconType.Date, 312 }, 313 new AvailableResult() 314 { 315 Value = dateTimeNow.ToString("Y", CultureInfo.CurrentCulture), 316 Label = Resources.Microsoft_plugin_timedate_MonthYear, 317 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagDate"), 318 IconType = ResultIconType.Date, 319 }, 320 }); 321 322 try 323 { 324 results.Add(new AvailableResult() 325 { 326 Value = dateTimeNow.ToFileTime().ToString(CultureInfo.CurrentCulture), 327 Label = Resources.Microsoft_plugin_timedate_WindowsFileTime, 328 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 329 IconType = ResultIconType.DateTime, 330 }); 331 } 332 catch (Exception ex) 333 { 334 Logger.LogError($"Unable to convert to Windows file time: {ex.Message}"); 335 results.Add(new AvailableResult() 336 { 337 Value = Resources.Microsoft_plugin_timedate_ErrorConvertWft, 338 Label = Resources.Microsoft_plugin_timedate_WindowsFileTime, 339 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 340 IconType = ResultIconType.Error, 341 }); 342 } 343 344 results.AddRange(new[] 345 { 346 new AvailableResult() 347 { 348 Value = dateTimeNowUtc.ToString("u"), 349 Label = Resources.Microsoft_plugin_timedate_UniversalTime, 350 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 351 IconType = ResultIconType.DateTime, 352 }, 353 new AvailableResult() 354 { 355 Value = dateTimeNow.ToString("s"), 356 Label = Resources.Microsoft_plugin_timedate_Iso8601, 357 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 358 IconType = ResultIconType.DateTime, 359 }, 360 new AvailableResult() 361 { 362 Value = dateTimeNowUtc.ToString("yyyy-MM-ddTHH:mm:ss", CultureInfo.InvariantCulture), 363 Label = Resources.Microsoft_plugin_timedate_Iso8601Utc, 364 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 365 IconType = ResultIconType.DateTime, 366 }, 367 new AvailableResult() 368 { 369 Value = dateTimeNow.ToString("yyyy-MM-ddTHH:mm:ssK", CultureInfo.InvariantCulture), 370 Label = Resources.Microsoft_plugin_timedate_Iso8601Zone, 371 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 372 IconType = ResultIconType.DateTime, 373 }, 374 new AvailableResult() 375 { 376 Value = dateTimeNowUtc.ToString("yyyy-MM-ddTHH:mm:ss'Z'", CultureInfo.InvariantCulture), 377 Label = Resources.Microsoft_plugin_timedate_Iso8601ZoneUtc, 378 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 379 IconType = ResultIconType.DateTime, 380 }, 381 new AvailableResult() 382 { 383 Value = dateTimeNow.ToString("R"), 384 Label = Resources.Microsoft_plugin_timedate_Rfc1123, 385 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 386 IconType = ResultIconType.DateTime, 387 }, 388 new AvailableResult() 389 { 390 Value = dateTimeNow.ToString("yyyy-MM-dd_HH-mm-ss", CultureInfo.InvariantCulture), 391 Label = Resources.Microsoft_plugin_timedate_filename_compatible, 392 AlternativeSearchTag = ResultHelper.SelectStringFromResources(isSystemDateTime, "Microsoft_plugin_timedate_SearchTagFormat"), 393 IconType = ResultIconType.DateTime, 394 }, 395 }); 396 } 397 398 // Return only results where value is not empty 399 // This can happen, for example, when we can't read the 'era' or when 'era == era abbreviation' and we set value explicitly to an empty string. 400 return results.Where(x => !string.IsNullOrEmpty(x.Value)).ToList(); 401 } 402 }