Как да конвертирате дати от различни източници на данни в python DateTime.
Времевите клейма са най-важният елемент от данните за специалиста по данни. Времевите отпечатъци осигуряват дълбочина и слоеве на данните. И така, какъв е проблемът? Различни формати! Как да се справя с това?
Сценарият
В един проект събирам записи на данни за събития и транзакции от много различни източници на данни и ги вмъквам в една таблица. Имам нужда от клеймото за време, за да подредя събитията. Всички файлове идват в различни формати. В някои случаи ми се предоставят данни от друга група. Дори не знам какъв може да е източникът на данни. Това създава доста загуба на време за проучване на източника на данни и съответния формат.
Решението
Преди да мога да трансформирам данните, трябва да разпозная в какъв възможен формат е пристигнал. Това изисква малко тестване с нови формати, особено тези, които са персонализирани. Създадох много основен скрипт за форматиране на клеймо за време в python за тези, които използвам най-често.
Работата ми не зависи от часовите зони, така че не се работи в тази област. Планирам да споделя някои функции за часова зона, добавени към Python 3.9 в друга статия.
За моето тестване използвах предстоящия петък 13-ти, за да отпразнувам предстоящите празници Хелоуин.
# import packages import re import string import datetime import dateutil.parser import time # test input list = [ '1605291193' # epoch , '1605291193000' # epoch with milliseconds , '2020-11-13T13:13:13.000Z' # ISO, Oracle, MongoDB , '2020–11–13–13.13.13.000000' # db2a , '2020–11–13–13:13:13:000000' # db2b , 'Fri Nov 13 13:13:13 +0000 2020' # twitter , 'Fri Nov 13 13:13:13 2020' # SAS , 'FRI Nov 13 13:13:13 2020' # SAS shouting! , 'Nov 13, 2020, 01:13:13 PM' # UTC , '2020-11-13 13:13:13' # 'standard', google big query, pandas , '2020-11-13 13:13:13.000' # presto , '11/13/2020' # mm/dd/yyyy American #, '13/11/2020' # dd/mm/yyyy European ] # constants european_flag = 'N' months = ['jan', 'feb', 'mar', 'apr', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'] days_of_week = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'] centuries = ['20', '19'] db2_time_sep = ['.', ':'] db2_dt_sep = ['-'] standard_dt_sep = [ ' '] iso_dt_sep = ['T'] validation_date = '2020-11-13 13:13:13' # processing all timestamps on the test input for ix in list: # initialize possible_ts_type = ' ' has_century = has_year = has_space = has_T = has_month = has_day = 'N' converted_value = db2_formatted = db2_month = db2_day= db2_minutes = db2_seconds = 'x' i_num = lenght_i = 0 # parse incoming data i = ix century = i[0:2] year = i[0:4] time_sep = i[13:14] time_sep2 = i[16:17] dt_sep = i[10:11] first_three = str(i[0:3]).lower() print() print('Starting timestamp: ' + str(i)) # does it start with a year? if century in centuries: has_century = 'Y' if re.match('^[0-9]*$', year): has_year = 'Y' # is the time separator a : or .? if dt_sep != ' ': if dt_sep != 'T': if time_sep in db2_time_sep: if has_year == 'Y': possible_ts_type = 'DB2' db2_month = i[5:7] db2_day = i[8:10] db2_hour = i[11:13] db2_minutes = i[14:16] db2_seconds = i[17:19] db2_formatted = str(year) + '-' + \ str(db2_month) + '-' + \ str(db2_day) + ' ' + \ str(db2_hour) + '.' + \ str(db2_minutes) + '.' + \ str(db2_seconds) converted_value = datetime.datetime.strptime(db2_formatted, '%Y-%m-%d %H.%M.%S') # does it contain a T? if dt_sep in iso_dt_sep: possible_ts_type = 'ISO' has_T = 'Y' converted_value = datetime.datetime.strptime(i, "%Y-%m-%dT%H:%M:%S.%fZ") # is the entire string numberic? if re.match('^[0-9]*$', i): possible_ts_type = 'epoch' i_num = int(i) length_i = len(i) if length_i > 10: i_num = int(i_num/1000) converted_value_temp = datetime.datetime.fromtimestamp(i_num).strftime('%c') converted_value = dateutil.parser.parse(converted_value_temp) # does it start with a month? if first_three in months: possible_ts_type = 'UTC' converted_value = dateutil.parser.parse(i) # does it start with a day of the week? if first_three in days_of_week : if i[20:21] == '+' : possible_ts_type = 'twitter' converted_value = datetime.datetime.strftime(datetime.datetime.strptime(i,'%a %b %d %H:%M:%S +0000 %Y'), '%Y-%m-%d %H:%M:%S') else: possible_ts_type = 'SAS' converted_value = dateutil.parser.parse(i) has_day = 'Y' # is the separator a space? if i[10:11] == ' ' : has_space = 'Y' if len(i) == 19: if has_space == 'Y': if time_sep == ':': possible_ts_type = 'standard' converted_value = datetime.datetime.strptime(i, '%Y-%m-%d %H:%M:%S') if len(i) == 23: if has_space == 'Y': if time_sep == ':': possible_ts_type = 'presto' converted_value = datetime.datetime.strptime(i, '%Y-%m-%d %H:%M:%S.%f') if '/' in i: if european_flag == 'Y': possible_ts_type = 'european d/m/Y' converted_value = datetime.datetime.strptime(i, "%d/%m/%Y") else: if european_flag == 'N': possible_ts_type = 'american m/d/Y' converted_value = datetime.datetime.strptime(i, "%m/%d/%Y") # Evaluate the results print('Possible Timestamp Type: ' + possible_ts_type) print('Converted Timestamp: ' + str(converted_value)) if str(converted_value) == validation_date: print('Successful Conversion!') else: print('Not a complete match')
Резултатът:
Starting timestamp: 1605291193 Possible Timestamp Type: epoch Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: 1605291193000 Possible Timestamp Type: epoch Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: 2020-11-13T13:13:13.000Z Possible Timestamp Type: ISO Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: 2020–11–13–13.13.13.000000 Possible Timestamp Type: DB2 Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: 2020–11–13–13:13:13:000000 Possible Timestamp Type: DB2 Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: Fri Nov 13 13:13:13 +0000 2020 Possible Timestamp Type: twitter Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: Fri Nov 13 13:13:13 2020 Possible Timestamp Type: SAS Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: FRI Nov 13 13:13:13 2020 Possible Timestamp Type: SAS Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: Nov 13, 2020, 01:13:13 PM Possible Timestamp Type: UTC Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: 2020-11-13 13:13:13 Possible Timestamp Type: standard Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: 2020-11-13 13:13:13.000 Possible Timestamp Type: presto Converted Timestamp: 2020-11-13 13:13:13 Successful Conversion! Starting timestamp: 11/13/2020 Possible Timestamp Type: american m/d/Y Converted Timestamp: 2020-11-13 00:00:00 Not a complete match
Чувствайте се свободни да използвате всеки от този скрипт, който работи за вас. Перфектен ли е? Не. Това ли е най-добрият сценарий? Вероятно не. Ако имате друго решение, моля, споделете го в коментарите. Колкото повече опции имаме, толкова по-добре сме всички.