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