Практически все значения дат и времени в PowerShell представлены в виде DateTime. Это класс .Net, позволяющий легко сравнивать различные значение и производить с ними различные операции.
Однако зачастую приходится обрабатывать источники данных в которых значения времени представлены в виде простого текста — например логи. И так уж сложилось, что у различных разработчиков есть разные взгляды на то как следует записывать время в текстовом виде. И тут возникает вопрос — как разобрать эту строку, и сконвертировать её в тип DateTime? В посте про оператор -replace я уже показывал один из вариантов как это можно сделать. Но честно говоря тот способ несколько…. не «прямой». 😉 А проблема часто возникающая. Так что я решил более подробно рассмотреть эту тему.
Начнем с простейшего. PowerShell (или .Net) может легко сконвертировать текстовую строку в тип DateTime если время в этой строке написано в определённом формате. А точнее в американском, например «2/22/2008 23:12:33.1233», короче говоря — «месяц/число/год часы:минуты:секунды.миллисекунды».
[PS <19> C:\Root] [datetime]"2/22/2008 23:12:33.1233" 22 февраля 2008 г. 23:12:33 [PS <20> C:\Root] [datetime]"2/22/2008 23:12:33.1233" | format-list * DateTime : 22 февраля 2008 г. 23:12:33 Date : 22.02.2008 0:00:00 Day : 22 DayOfWeek : Friday DayOfYear : 53 Hour : 23 Kind : Unspecified Millisecond : 123 Minute : 12 Month : 2 Second : 33 Ticks : 633393187531233000 TimeOfDay : 23:12:33.1233000 Year : 2008
Что интересно — это не зависит от региональных настроек системы — по умолчанию формат всегда американский. Так было сделано для того чтобы скрипты работали одинаково на системах с любыми региональными настройками.
Если всё же необходимо разобрать дату в соответствии с региональными настроками, то следует использовать статический метод Parse класса DateTime:
[PS <21> C:\Root] [datetime]::parse("22/2/2008 23:12:33.1233") 22 февраля 2008 г. 23:12:33
В обоих случаях, в строке не обязательно должны присутствовать все элементы. Можно указать только дату, только время, или например не указывать милисекунды.
[PS <22> C:\Root] [datetime]"2/22/2008" 22 февраля 2008 г. 0:00:00 [PS <23> C:\Root] [datetime]"23:12:33" 2 июля 2008 г. 23:12:33 [PS <24> C:\Root] [datetime]"23:12" 2 июля 2008 г. 23:12:00 [PS <25> C:\Root] [datetime]::parse("22/2/2008") 22 февраля 2008 г. 0:00:00
Как видно из примеров, если не указана дата, то будет подставлен текущий день, а в случае отсутствия времени подставится 0:00:00.
Ну и вернёмся к первоначальной задаче. Как разобрать дату если она записана в каком то ином формате. Тут понадобится метод ParseExact (спасибо MoW за подсказку 😉 ). Он позволяет указать любой свой формат для разбора строки в дату.
[PS <26> C:\Root] [datetime]::ParseExact('11222008-13~44~14','MMddyyyy-ss~mm~HH',$null) 22 ноября 2008 г. 14:44:13
В качестве первого параметра указывается разбираемая строка, а второй параметр — маска по которой будет происходить разбор. MM — означает 2 цифры месяца, dd — 2 цифры дня, yyyy — 4 цифры года, ss — секунды, mm — минуты, HH — часы в 24-часовом формате (для 12 часового используется hh). Подробнее про возможные символы и их значения можно прочитать тут. Кстати еще есть возможность не вводить маску полностью самому, а использовать предопределенные:
[PS <27> C:\Root] [datetime]::ParseExact('Wed, 02 Jul 2008 12:27:01 GMT','r',$null) 2 июля 2008 г. 12:27:01
Приятного парсинга логов 😉
9.9.2008 в 8:41
[…] на приемы работы с датами которые я тут использовал: ParseExact и оператор […]