Generating serial numbers based on current time and date

Share your advanced PureBasic knowledge/code with the community.
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Generating serial numbers based on current time and date

Post by Dreamland Fantasy »

Hi there,

The following routine generates serial numbers based on the current system (or local) time and date:

Code: Select all

Procedure.l GenerateSerialNumber(UseLocalTime.l = 0)
  
  Protected.w lo, hi
  Protected st.SYSTEMTIME
  
  If UseLocalTime
    GetLocalTime_(st)
  Else
    GetSystemTime_(st)
  EndIf
  
  lo = st\wMonth  << 8 + st\wDay
  lo + st\wSecond << 8 + st\wMilliseconds / 10
  
  hi = st\wHour   << 8 + st\wMinute
  hi + st\wYear
  
  ProcedureReturn lo << 16 + hi
  
EndProcedure

Debug "Generated serial number: $" + RSet(Hex(GenerateSerialNumber(#True), #PB_Long), 8, "0")
The Windows API functions GetSystemTime_() and GetLocalTime_() are used in order to obtain the number of milliseconds, but are easily replaced with PureBasic's Date() functions if you don't mind the loss of accuracy:

Code: Select all

Procedure.l GenerateSerialNumber()
  
  Protected.w lo, hi
  Protected st = Date()
  
  lo = Month(st)  << 8 + Day(st)
  lo + Second(st) << 8
  
  hi = Hour(st)   << 8 + Minute(st)
  hi + Year(st)
  
  ProcedureReturn lo << 16 + hi
  
EndProcedure

Debug "Generated serial number: $" + RSet(Hex(GenerateSerialNumber(), #PB_Long), 8, "0")
The method used for generating the serial numbers is based on information I found here.

Kind regards,

Francis
User avatar
skywalk
Addict
Addict
Posts: 4219
Joined: Wed Dec 23, 2009 10:14 pm
Location: Boston, MA

Re: Generating serial numbers based on current time and date

Post by skywalk »

Cool. This can rearrange your SN$ according to a magic string.

Code: Select all

;- Base Conversions and KeyCode$
#Base2$     = "01"                    ; Binary
#Base8$     = "01234567"              ; Octal
#Base10$    = "0123456789"            ; Decimal
#Base16LC$  = "0123456789abcdef"      ; Hex, LCase
#Base16$    = "0123456789ABCDEF"      ; Hex, UCase
#Base26LC$  = "abcdefghijklmnopqrstuvwxyz"                                       ; LCase
#Base26$    = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"                                       ; Caps
#Base36LC$  = "0123456789abcdefghijklmnopqrstuvwxyz"                             ; letters and numerals
#Base36$    = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"                             ; UCase letters and numerals
#Base62$    = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"   ; Upper/Lower Case and numerals
#Base64$    = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/"
Procedure$ SF_IntToBase(x.q, BaseToUse$=#Base36$)
  ; Convert positive integer to baseXX string.
  ; Debug SF_IntToBase(1306270050)            ; LLPWF6
  ; Debug SF_IntToBase(1306270050,#Base62$)   ; 1QOyVm
  Protected.q BaseLen = Len(BaseToUse$)
  Protected.s r$
  If x > 0
    While x <> 0
      r$ = Mid(BaseToUse$, (x % BaseLen) + 1, 1) + r$
      x / BaseLen
    Wend
  Else
    r$ = "0"
  EndIf
  ProcedureReturn r$
EndProcedure

Procedure.q SF_BaseToInt(base$, BaseToUse$=#Base36$)
  ; Convert baseXX string to positive integer.
  ; Debug SF_BaseToInt("LLPWF6")            ; 1306270050
  ; Debug SF_BaseToInt("1QOyVm",#Base62$)   ; 1306270050
  Protected.i i
  Protected.i BaseLen = Len(base$)
  Protected.i UseBaseLen = Len(BaseToUse$)
  Protected.q x
  For i = 1 To BaseLen
    x = (x * UseBaseLen) + (FindString(BaseToUse$, Mid(base$, i, 1)) - 1)
  Next i
  ProcedureReturn x
EndProcedure
Define.q SN = Date(2016,2,11,12,1,2)
Debug SN
Define.s SN$ = SF_IntToBase(SN, #Base62$)
Debug SN$
Debug SF_BaseToInt(SN$, #Base62$)
The nice thing about standards is there are so many to choose from. ~ Andrew Tanenbaum
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Re: Generating serial numbers based on current time and date

Post by Dreamland Fantasy »

skywalk wrote:Cool. This can rearrange your SN$ according to a magic string.
Nice! 8)

Kind regards,

Francis
User avatar
Keya
Addict
Addict
Posts: 1890
Joined: Thu Jun 04, 2015 7:10 am

Re: Generating serial numbers based on current time and date

Post by Keya »

hello,
Dreamland Fantasy wrote:The Windows API functions GetSystemTime_() and GetLocalTime_() are used in order to obtain the number of milliseconds, but are easily replaced with PureBasic's Date() functions if you don't mind the loss of accuracy
perhaps PB's ElapsedMilliseconds() can be used
User avatar
Dreamland Fantasy
Enthusiast
Enthusiast
Posts: 335
Joined: Fri Jun 11, 2004 9:35 pm
Location: Glasgow, UK
Contact:

Re: Generating serial numbers based on current time and date

Post by Dreamland Fantasy »

Keya wrote:perhaps PB's ElapsedMilliseconds() can be used
You would probably need to monitor the number returned by Seconds() constantly to find the moment when it updates and then use ElapsedMilliseconds() to get the offset. Then when you request the current time you can work out the number of milliseconds by doing ElapsedMilliseconds() - msOffset.

Kind regards,

Francis
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

Re: Generating serial numbers based on current time and date

Post by RichardL »

Hi,
I have used ElapsedMilliseconds() as a unique record number / time stamp for entries in an SQLite database.

This was fine when the user was typing each new entry, there were at least 20 seconds between new records.

However, when new records were being created from a batch-file input and taking into consideration the high processing speed of the computer plus the large buffer sizes used in the hard disks for the data coming from the batch file and going into the SQLite database I thought it wise to add some additional resolution.

This was a long time ago and I do not have access to the code I wrote, but it was something like this ... please excuse an error prone aging memory!

Comment off the line with ';**' to confirm operation.
RichardL

Code: Select all




Procedure.q NewSerialNumber()
  Static LastElapT.l  ; Last time we were here
  Static SubmSecCnt.l ; Number of visits this mSec
  Protected T
  
  T = ElapsedMilliseconds()
  
  If LastElapT = T
    SubmSecCnt + 1 ; **
  Else
    SubmSecCnt = 0
  EndIf
  LastElapT = T
  
  ProcedureReturn T + SubmSecCnt
EndProcedure

; Ask for a series of serial numbers
Dim Test.q(1000)
For n = 0 To 1000
  Test(n) = NewSerialNumber()
Next

; Test for duplicates
Identicals = 0
For n = 0 To 999
  If Test(n)= Test(n+1)
    Identicals + 1
  EndIf
Next
MessageRequester("Identicals",Str(Identicals))
Post Reply