Что нового

Время, дата Преобразование любой даты по шаблону к нужному виду

kodges

Новичок
Сообщения
42
Репутация
0
Здравствуйте уважаемые гуру, помогите пожалуйста.
Стоит задача парсить файл в котором колонка с датой может быть в самом разном виде.
Предполагается что имеется шаблон в котором указана дата в файле. Нужна функция которая по шаблону выдернет дату и на выходе выдаст ее в нужном виде.
Помогите с написанием такой функции.

Код:
$date= "05/12/2020-13:08:21"
$shablon = "DD/MM/YYYY-HH:mm:ss" ; Разумеется предполагается что в дате дни недели месяцы могут быть в другом порядке и с другими разделителями, поэтому и надо преобразовывать по шаблону.
$result = "YYYY-MM-DD HH:mm:ss" ; формат в который надо преобразовать исходную дату

MsgBox(1, "Date", dateformat($date, $shablon, $result)  ; Должно вывести дату в формате $result


Func dateformat()
???
EndFunc

Сообщение автоматически объединено:

В идеале конечно бы сделать функцию универсальной предусмотрев использование как совместно с датой и временем, так и отдельно, дата без времени, или время без даты.
 

IMStrelcov

CTPEJIbLLOB
Сообщения
253
Репутация
64
Код:
;чтобы не усложнять и не растягивать рег. выражение, слепил так.
;год всегда должен иметь 4-и цыфры, это так сказать опорная точка, а время иметь часы минуты и секунды.
;на пример если 11-й месяц и 9-е число или 11-е число и 9-й месяц, то с этим ничего не поделать,
;так как не узнать где день, а где месяц, кроме случаев когда число превышает значение 12-и.
;поэтому функция учитывает только год-месяц-число или число-месяц-год,
;а время всегда учитывается как час:мин:сек, а не как мин:сек или час:мин.

;флаг -1 (по умолчанию) вернуть и дату и время (если даты и времени нет, вернуть нуль)
;флаг 0 вернуть и дату и время (если даты или времени нет, вернуть нуль, для каждого отдельный)
;флаг 1 вернуть время (если времени нет, вернуть нуль)
;флаг 2 вернуть дату (если даты нет, вернуть нуль)

Global $sData[9] = [8, _
'12_04_3030 14.10.32', _
'14.10.32 12_04_3030', _
'3030_04_12 14.10.32', _
'14.10.32 3030_04_12', _
'14.10.32', _
'3030_04_12', _
'12_04_3030', _
'']

For $i = 1 To $sData[0]
   ConsoleWrite(ConvertData_($sData[$i], -1)&@CRLF)
Next

Func ConvertData_($_sStr, $_iReturn = 0)
   Local $_aResult = StringRegExp($_sStr, '([0-9]+)', 3)
   Local $_sResult = 0, $_sData, $_sTime
   If UBound($_aResult) > 5 Then
      If StringRegExp($_aResult[0], '([0-9]{4})') Then
         $_sData = $_aResult[0]&'-'&$_aResult[1]&'-'&$_aResult[2]
         $_sTime = $_aResult[3]&':'&$_aResult[4]&':'&$_aResult[5]
      ElseIf StringRegExp($_aResult[2], '([0-9]{4})') Then
         $_sData = $_aResult[2]&'-'&$_aResult[1]&'-'&$_aResult[0]
         $_sTime = $_aResult[3]&':'&$_aResult[4]&':'&$_aResult[5]
      ElseIf StringRegExp($_aResult[3], '([0-9]{4})') Then
         $_sData = $_aResult[3]&'-'&$_aResult[4]&'-'&$_aResult[5]
         $_sTime = $_aResult[0]&':'&$_aResult[1]&':'&$_aResult[2]
      Else
         $_sData = $_aResult[5]&'-'&$_aResult[4]&'-'&$_aResult[3]
         $_sTime = $_aResult[0]&':'&$_aResult[1]&':'&$_aResult[2]
      EndIf
   ElseIf UBound($_aResult) > 1 Then
      If StringRegExp($_sStr, '([0-9]{4})') Then
         If StringRegExp($_aResult[0], '([0-9]{4})') Then
            $_sData = $_aResult[0]&'-'&$_aResult[1]&'-'&$_aResult[2]
         Else
            $_sData = $_aResult[2]&'-'&$_aResult[1]&'-'&$_aResult[0]
         EndIf
      Else
         $_sTime = $_aResult[0]&':'&$_aResult[1]&':'&$_aResult[2]
      EndIf
   EndIf
   Switch $_iReturn
   Case 0
      $_sResult = ($_sData ? $_sData : 0) & ($_sTime ? ' ' & $_sTime : ' ' & 0)
   Case 1
      $_sResult = $_sTime ? $_sTime : 0
   Case 2
      $_sResult = $_sData ? $_sData : 0
   Case Else
      $_sResult = ($_sData ? $_sData : '') & ($_sTime ? ($_sData ? ' ' : '') & $_sTime : '')
      $_sResult = ($_sResult ? $_sResult : 0)
   EndSwitch
   Return $_sResult
EndFunc
 
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
Спасибо за труд, но смысл шаблона как раз в том что в нем явно указывается где находится год, где месяц, где день и т.д.. В этом суть задумки. Это позволит распарсить даже самый извращенный формат даты. То есть по хорошему надо распарсить заданный шаблон, и уже согласно него потом парсить и преобразовывать дату. Тогда не будет проблем с тем что и месяц и день меньше 13.
Сообщение автоматически объединено:

Я может быть некорректно выразился изначально, но если шаблон указан как "DD/MM/YYYY-HH:mm:ss", значит дата в файле записана именно так, именно с такими разделителями как в шаблоне. Если шаблон указан как "YYYY.DD-MM/HH:mm:ss", значит в файле дата именно в таком виде с именно такими разделителями... в общем смысл шаблона в том чтобы задать функции формат в котором находится дата. А функция уже по шаблону должна распарсить дату из файла и слепить из нее нужный формат на выходе.
 
Последнее редактирование:

IMStrelcov

CTPEJIbLLOB
Сообщения
253
Репутация
64
моя функция принимает на вход любые разделители и любые данные, дата + время, время + дата, только дата или время.
так же в зависимости от флага возвращает или дату или время или все вместе, с разделителями и в порядке указанными вами в шапке.
а насчет узнать где месяц а где число, это проблема, вот я напишу 09.08.2020, как вы узнаете что у меня первым число или месяц?
поэтому позиция числа и месяца определяется исходя из того с какой стороны год.
 
Последнее редактирование:
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
вот я напишу 09.08.2020, как вы узнаете что у меня первым число или месяц?
Вот для этого и есть шаблон в котором с помощью DD и MM размечается где день, а где месяц. Ваша функция бесспорно хороша, но мне надо чтобы все работало корректно с любым вариантом написания. Для этого и задумано использование шаблона. То есть предполагается что перед парсингом файла будет указан шаблон в соответствии с которым в файле располагается дата.
 

Alecsis

Осваивающий
Сообщения
98
Репутация
41
М.б. что-то в этом роде подойдёт? Конечно, это склёпано «на табуретке» скорее полуфабрикат, однако на первый взгляд отрабатывает адекватно.
Если что, кидайте в переписку, чтобы не загромождать тему.
 

Вложения

  • Kodges-1.au3
    8.1 КБ · Просмотры: 8

IMStrelcov

CTPEJIbLLOB
Сообщения
253
Репутация
64
Вот еще вариант, может что то упустил, так как код писал после ночной смены.
Но все же может понравится, если это то что требовалось.
Код:
;$_vStr = строка образец, может содержать цифры и разделители
;
;$_vInFrmt = Входной шаблон указывается знаками
;    Y = год
;    M = месяц
;    D = число
;    h = часы
;    m = минуты
;    s = секунды
;разделители игнорируются, так как из строки образца берутся только цифры.
;
;$_vOutFrmt = Выходной шаблот такой же, но уже принимает разделители, которые будут вставлены в результат
;а так же если число например 1, а в шаблоне указать DD, то вернет 01 и так совсеми данными.

;пример DataTimeFormat_('2021.14/8-6=44',  'YMDhs', 'DD.MM.YYYY hh:mm:ss')
;вернет 08.14.2021 06:00:44

;пример DataTimeFormat_('2021.14/8-6=44',  'YMDhs', 'DD.MM.YY')
;вернет 08.14.21

ConsoleWrite(DataTimeFormat_('2021.13.1-14-23-7', 'YMDmhs', 'DD.MM.YYYY hh:mm:ss') &@CRLF)

Func DataTimeFormat_($_vStr, $_vInFrmt, $_vOutFrmt)
   $_vStr = StringRegExp($_vStr, '([0-9]+)', 3)
   $_vInFrmt = StringRegExpReplace($_vInFrmt, '(m)', 'n')
   $_vInFrmt = StringRegExp($_vInFrmt, '([YMDhns])', 3)
   $_iLen = UBound($_vStr)
   If @error Then Return SetError(1)
   $_iFLen = UBound($_vInFrmt)
   If @error Then Return SetError(1)
   If $_iFLen < $_iLen Then $_iLen = $_iFLen
   Local $_sMDay, $_sMon, $_sYear, $_sHour, $_sMin, $_sSec
   For $_i = 0 To $_iLen -1
      Switch $_vInFrmt[$_i]
      Case 'Y'
         $_sYear = $_vStr[$_i]
      Case 'M'
         $_sMon = $_vStr[$_i]
      Case 'D'
         $_sMDay = $_vStr[$_i]
      Case 'h'
         $_sHour = $_vStr[$_i]
      Case 'n'
         $_sMin = $_vStr[$_i]
      Case 's'
         $_sSec = $_vStr[$_i]
      EndSwitch
   Next
   $_vOutFrmt = StringRegExpReplace($_vOutFrmt, '(m)', 'n')
   $_vOutFrmt = StringRegExp($_vOutFrmt, '([YMDhns]+|[^YMDhns]+)', 3)
   $_iLen = UBound($_vOutFrmt)
   If @error Then Return SetError(1)
   $_vStr = ''
   For $_i = 0 To $_iLen -1
      $_iFLen = StringLen($_vOutFrmt[$_i])
      Switch StringLeft($_vOutFrmt[$_i], 1)
      Case 'Y'
         $_vOutFrmt[$_i] = $_sYear
      Case 'M'
         $_vOutFrmt[$_i] = $_sMon
      Case 'D'
         $_vOutFrmt[$_i] = $_sMDay
      Case 'h'
         $_vOutFrmt[$_i] = $_sHour
      Case 'n'
         $_vOutFrmt[$_i] = $_sMin
      Case 's'
         $_vOutFrmt[$_i] = $_sSec
      EndSwitch
      $_vOutFrmt[$_i] = StringRight($_vOutFrmt[$_i], $_iFLen)
      $_vStr &= StringFormat('%0'&$_iFLen&'s', $_vOutFrmt[$_i])
   Next
   Return $_vStr
EndFunc
 
Автор
kodges

kodges

Новичок
Сообщения
42
Репутация
0
Вот еще вариант, может что то упустил, так как код писал после ночной смены.
Но все же может понравится, если это то что требовалось.
Код:
;$_vStr = строка образец, может содержать цифры и разделители
;
;$_vInFrmt = Входной шаблон указывается знаками
;    Y = год
;    M = месяц
;    D = число
;    h = часы
;    m = минуты
;    s = секунды
;разделители игнорируются, так как из строки образца берутся только цифры.
;
;$_vOutFrmt = Выходной шаблот такой же, но уже принимает разделители, которые будут вставлены в результат
;а так же если число например 1, а в шаблоне указать DD, то вернет 01 и так совсеми данными.

;пример DataTimeFormat_('2021.14/8-6=44',  'YMDhs', 'DD.MM.YYYY hh:mm:ss')
;вернет 08.14.2021 06:00:44

;пример DataTimeFormat_('2021.14/8-6=44',  'YMDhs', 'DD.MM.YY')
;вернет 08.14.21

ConsoleWrite(DataTimeFormat_('2021.13.1-14-23-7', 'YMDmhs', 'DD.MM.YYYY hh:mm:ss') &@CRLF)

Func DataTimeFormat_($_vStr, $_vInFrmt, $_vOutFrmt)
   $_vStr = StringRegExp($_vStr, '([0-9]+)', 3)
   $_vInFrmt = StringRegExpReplace($_vInFrmt, '(m)', 'n')
   $_vInFrmt = StringRegExp($_vInFrmt, '([YMDhns])', 3)
   $_iLen = UBound($_vStr)
   If @error Then Return SetError(1)
   $_iFLen = UBound($_vInFrmt)
   If @error Then Return SetError(1)
   If $_iFLen < $_iLen Then $_iLen = $_iFLen
   Local $_sMDay, $_sMon, $_sYear, $_sHour, $_sMin, $_sSec
   For $_i = 0 To $_iLen -1
      Switch $_vInFrmt[$_i]
      Case 'Y'
         $_sYear = $_vStr[$_i]
      Case 'M'
         $_sMon = $_vStr[$_i]
      Case 'D'
         $_sMDay = $_vStr[$_i]
      Case 'h'
         $_sHour = $_vStr[$_i]
      Case 'n'
         $_sMin = $_vStr[$_i]
      Case 's'
         $_sSec = $_vStr[$_i]
      EndSwitch
   Next
   $_vOutFrmt = StringRegExpReplace($_vOutFrmt, '(m)', 'n')
   $_vOutFrmt = StringRegExp($_vOutFrmt, '([YMDhns]+|[^YMDhns]+)', 3)
   $_iLen = UBound($_vOutFrmt)
   If @error Then Return SetError(1)
   $_vStr = ''
   For $_i = 0 To $_iLen -1
      $_iFLen = StringLen($_vOutFrmt[$_i])
      Switch StringLeft($_vOutFrmt[$_i], 1)
      Case 'Y'
         $_vOutFrmt[$_i] = $_sYear
      Case 'M'
         $_vOutFrmt[$_i] = $_sMon
      Case 'D'
         $_vOutFrmt[$_i] = $_sMDay
      Case 'h'
         $_vOutFrmt[$_i] = $_sHour
      Case 'n'
         $_vOutFrmt[$_i] = $_sMin
      Case 's'
         $_vOutFrmt[$_i] = $_sSec
      EndSwitch
      $_vOutFrmt[$_i] = StringRight($_vOutFrmt[$_i], $_iFLen)
      $_vStr &= StringFormat('%0'&$_iFLen&'s', $_vOutFrmt[$_i])
   Next
   Return $_vStr
EndFunc
Вот это уже тянет на шедевр ))
Вариант Alecsis тоже делает все хорошо, но ваш вариант симпотнее и главное работает быстрее. Не спасибо, а СПАСИБИЩЕ!!!
 
Верх