Page 1 of 1

Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Posted: Sat Aug 20, 2016 8:33 am
by wilbert
Not as flexible as ParseDate since the offset of each component is hard coded
but the code is easy to adapt to a format like YYYY-MM-DD HH:MM:SS .

You have to make sure yourself the strings contain valid information; no checks are performed. The focus is on speed.
It's much faster as the PB procedure ParseDate and returns a quad value so no problem with dates beyond 2037.

Code: Select all

#DT_Unicode = #True; set to #False for parsing Ascii strings

Macro GetDigits(reg, pos)
  CompilerIf #DT_Unicode
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
      !mov reg, [r8 + pos * 2]
    CompilerElse
      !mov reg, [esi + pos * 2]
    CompilerEndIf
    !sub  reg, 0x00300030
    !imul reg, 0x0a000100
  CompilerElse
    CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
      !movzx reg, word [r8 + pos]
    CompilerElse
      !movzx reg, word [esi + pos]
    CompilerEndIf
    !sub  reg, 0x00003030
    !imul reg, 0x0a010000
  CompilerEndIf
  !shr reg, 24
EndMacro

Procedure.q ParseDateTimeStamp(*dt) ; yyyymmddhhiiss
  
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !mov r8, [p.p_dt]
    !lea r9, [pdts_month_table]
  CompilerElse
    !mov eax, [p.p_dt]
    !push esi
    !mov esi, eax
  CompilerEndIf
  
  ; *** get date part ***
  GetDigits(ecx, 0); years (first two digits)
  !imul eax, ecx, 36524
  !shl ecx, 8
  GetDigits(edx, 2); years (last two digits)
  !or ecx, edx
  !imul edx, 365
  !add eax, edx
  GetDigits(edx, 4); months
  !and edx, 15
  ; leap correction
  !cmp edx, 3
  !sbb ecx, 0xfffffc00
  !and ecx, 0x0000fcff
  !bt ecx, 7
  !adc ch, cl
  !shr ecx, 10
  !add eax, ecx
  ; lookup and add month offset
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !movsx ecx, word [r9 + rdx * 2]
  CompilerElse
    !movsx ecx, word [pdts_month_table + edx * 2]
  CompilerEndIf
  !add eax, ecx
  ; add days
  GetDigits(ecx, 6); days
  !add eax, ecx
  
  ; *** get time part ***
  GetDigits(ecx, 8); hours
  !imul ecx, 3600
  GetDigits(edx, 10); minutes
  !imul edx, 60
  !add ecx, edx
  GetDigits(edx, 12); seconds
  !add ecx, edx

  ; combine days and seconds and return result
  !sub eax, 0xafaa9; 1/1/1970 offset (use 0xb2576 for 1/1/2000 offset)
  !mov edx, 86400
  !imul edx
  CompilerIf #PB_Compiler_Processor = #PB_Processor_x64
    !shl rdx, 32
    !or rax, rdx
    !add rax, rcx
  CompilerElse
    !add eax, ecx
    !adc edx, 0
    !pop esi
  CompilerEndIf
  ProcedureReturn
  !pdts_month_table:
  !dw 0,0,31,59,90,120,151,181,212,243,273,304,334,0,0,0
EndProcedure

Re: Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Posted: Sat Aug 20, 2016 8:35 am
by wilbert
Example

Code: Select all

Debug ParseDate("%yyyy%mm%dd%hh%ii%ss", "20160820093000")
Debug ParseDateTimeStamp(@"20160820093000")
Debug ParseDateTimeStamp(@"21160820093000")

Re: Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Posted: Fri Sep 02, 2016 2:17 pm
by Crusiatus Black
Thanks for sharing Wilbert!

Re: Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Posted: Fri Sep 02, 2016 7:17 pm
by davido
@wilbert,

Excellent, thank you for sharing. :D