/ src / modules / cmdpal / ext / Microsoft.CmdPal.Ext.TimeDate / Helpers / AvailableResultsList.cs
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  }