Program for generating a Snowflake ID

Hello all,

here is a little program I wrote that prints a Snowflake ID from the current system time. As per Snowflake ID format, Unix timestamp, machine number and sequence ID are embedded into a 64-bit integer variable to form a complete Snowflake ID.

I used the excellent M_time module from @urbanjost to do some heavy lifting with Unix time conversions.

To build and run it I used fpm 0.13.0 and gfortran 15.2.1 .

Feedback, comments, etc. are welcome.

app/main.f90

! 
! Generates and prints the current time in snowflake ID format.
! Value is printed with given machine ID and sequence number as command-line 
! arguments.
! 
program main
    use, intrinsic :: iso_fortran_env, only: int64
    use :: M_time, only: realtime, date_to_unix
    implicit none
    integer(kind=int64) :: snowflake
    integer(kind=int64) :: timestamp
    integer(kind=int64) :: machine_id
    integer(kind=int64) :: sequence_num
    integer :: num_args
    integer :: ios
    character(len=100) :: arg
    
    num_args = command_argument_count()
    
    if (num_args /= 2) then
        write(*,*) 'error: machineId (0..1023) or sequenceNum (0..4095) missing.'
        stop 1
    end if
    
    call get_command_argument(number=1, value=arg)
    read(arg, '(i4)', iostat=ios) machine_id
    if (ios /= 0) then
        write(*, '(a)') 'error reading machineId value.'
        stop 1
    end if
    
    call get_command_argument(number=2, value=arg)
    read(arg, '(i4)', iostat=ios) sequence_num
    if (ios /= 0) then
        write(*, '(a)') 'error reading sequenceNum value.'
        stop 1
    end if
    
    if (machine_id < 0 .or. machine_id > 1023) then
        write(*, '(a,i0)') 'error: invalid machineId: ', machine_id
        stop 1
    end if
    if (sequence_num < 0 .or. sequence_num > 4095) then
        write(*, '(a,i0)') 'error: invalid sequenceNum: ', sequence_num
        stop 1
    end if
    
    snowflake = 0_int64
    
    call getTimestamp(timestamp)
    
    call mvbits(from=timestamp, frompos=0, len=41, to=snowflake, topos=22) 
    call mvbits(from=machine_id, frompos=0, len=10, to=snowflake, topos=12)
    call mvbits(from=sequence_num, frompos=0, len=12, to=snowflake, topos=0)
    
    write(*,'(i0)') snowflake 
    
contains
    
    ! Place current time into timestamp in snowflake ID format
    subroutine getTimestamp(timestamp)
        integer(kind=int64), intent(out) :: timestamp
        real(kind=realtime) :: unixtime_rt
        real(kind=realtime) :: epoch_rt
        real(kind=realtime) :: difftime_rt
        integer(kind=int64) :: unixtime
        integer(kind=int64) :: epoch
        integer :: timestampdata(8)
        integer, parameter :: epochdata(8) = [2010, 11, 4, 0, 1, 42, 54, 657]
        integer :: ierr
        
        call date_and_time(values=timestampdata)
        call date_to_unix(timestampdata, unixtime_rt, ierr)
        call date_to_unix(epochdata, epoch_rt, ierr)
        unixtime = anint(unixtime_rt * 1000.0_realtime)
        epoch = anint(epoch_rt * 1000.0_realtime)
        timestamp = unixtime - epoch
    end subroutine
end program main

1 Like