Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Bare metal programming in PureBasic, for experienced users
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Post 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
Windows (x64)
Raspberry Pi OS (Arm64)
wilbert
PureBasic Expert
PureBasic Expert
Posts: 3870
Joined: Sun Aug 08, 2004 5:21 am
Location: Netherlands

Re: Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Post by wilbert »

Example

Code: Select all

Debug ParseDate("%yyyy%mm%dd%hh%ii%ss", "20160820093000")
Debug ParseDateTimeStamp(@"20160820093000")
Debug ParseDateTimeStamp(@"21160820093000")
Windows (x64)
Raspberry Pi OS (Arm64)
User avatar
Crusiatus Black
Enthusiast
Enthusiast
Posts: 389
Joined: Mon May 12, 2008 1:25 pm
Location: The Netherlands
Contact:

Re: Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Post by Crusiatus Black »

Thanks for sharing Wilbert!
Image
Bas Groothedde,
Imagine Programming

I live in a philosophical paradoxal randome filled with enigma's!
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Fast parsing of datetime strings (like YYYYMMDDHHMMSS)

Post by davido »

@wilbert,

Excellent, thank you for sharing. :D
DE AA EB
Post Reply