Unique Identifier - Using dates & times

I’ve read Mr. Aloo’s tutorial on unique serial numbers by parsing sections of the functions Today() and Now() to generate a unique timestamp record identifier and in trying to implement this for use primarily on an Android phone, the Now() function is giving me erratic results.

If I simply setup a calculation question using once(now()) and then display the result in a text question box the result on the phone is merely the date (ex. 2019-03-15 )while on the preview within web based Kobo the full date and time are displayed (ex. 2019-03-15T09:52:09.608-08:00).

As such, my ability to build a unique serial number based partly on Now() is not successful since the time portion is not being identified in the phone based version.

However, if I use a function like this in a calculation question:
format-date-time(once(now()), “%y%m%d%H%M%S”)
and then have the calculation displayed in a text question the result on the phone is correct as in:
but on the web based form builder the preview screen shows the result as “invalid date”

So, while I get the result I am after on the phone based form, I’m not sure why all the irregularities and I am worried that different phones (or versions of Android) and their system date/time settings will create problems in the future.

Anyone else have difficulties with the Today() and Now() and various formatting functions?


I think I figured this out and will share here in case any one else is interested.

I incorrectly used the once() function. After removing this and having a calculation setup as:
format-date-time(now(), “%y%m%d%H%M%S”)
my unique record identifier is now working correctly.

I then concat the above result with the ${username} to get a unique identifier.

For example I used two calculation questions:
DateTimeID uses the above formula
ObservID is formula: concat(${username},’_’,${DateTimeID})

This captures the username metadata from KoboCollect along with a date time stamp and an example output would look like:
initials _ yymmddhhmmss

Ultimately, we have a unique id for each submission recorded in the ObservID field which is also used as the name to save the form submission using the instance_name setting via XLSForm.

While in large deployments duplicates could exist if two users started a form at the exact same time and with the same user initials, for my small deployment this won’t be a problem.

You shoul use once. if not, then if you recall form to edit, unique ID will be recalculated and change.
here is the mine:
once(format-date-time(now(), ‘%y%m%d%H%M%S%3’))

I take now (date plus time) and format its represantation upto milliseconds (with %S%3)… it gives me 15 digits

1 Like

Hi Mskaraca,

When I first tested the use of once() in my uniqueID function, it didn’t work as expected. The uniqueID generated was the same for each new record/submission. I would get the same uniqueID for subsequent submissions which is not what I wanted. It appears the date-time captured is when the first time it was opened (Fill Blank Form), and never any subsequent openings.

It wasn’t until I removed the once() function that my uniqueID was being correctly built at the start of each new record/submission.

This is not what I understood the once() function to mean, but my use without it now correctly builds the uniqueID on 2 separate test phones.

You are correct that when editing a saved form the uniqueID will get rebuilt and overwritten with the current date-time when not using the once() function. Thanks, I didn’t test or realize this.

I did some more tests on this and am still running into the problem of using once(). Perhaps I don’t understand it correctly and instead I ended up changing my function to use the ${start} metadata field instead of now(). This gives me a unique date-time stamp for when the user first started the form for data entry. It will not change if the form is later edited and it will change on subsequent openings of the form (Fill Blank Form), which is what I’m after.

format-date-time(${start}, “%y%m%d%H%M%S”)

just a hint. Whenever you work with now() or today(), you may encounter the challenge that you trust on the user/device’s correct datetime config. For ex. we experienced problems, when tablet devices totally run down on battery (and as there was no Internet available, datetime was not updated automatically later.)
Why not use uuid(), see community topics, for unique ids.
Best regards

Hi @carl_ak , I have the same problem when I use the next function on my cell phone or tablet:


It shows only 21 and no more.

But, on web version works perfectly.

Somebody knows why happen this and how to resolve?


Hi @segadu78
Could you provide context of exactly what you needed this to do.


Hi @stephanealoo thank you for your response.

Sure, the unique identifier is a code that the enumerator could see to knows exactly the number of their submission to trace them in the next steps:

type name label calculation
calculate cod concat(substr(today(),2,4),substr(today(),7,5),substr(today(),10,8),substr(now(),13,11),substr(now(),16,14),substr(now(),19,17))
begin_group Rx Remisión No. ${cod}

As you can see, the unique identifier works perfectly in web:

But, not works on movile application. I attache an example of that.

¿Do you know why happen this and how to resolve this?


Hello @segadu78,
In your screenshot you have inconsistent naming: calculate code, but group label ${cod}.
(Normally this should not cause this Collect difference.)
Did you test on KoBo Collect and on ODK Collect?

1 Like

I´m sorry @wroos . When I pasted the message I change the name. I would fixe it.

Thank you for your advise.

1 Like

Hi @Kal_Lam

Could you help me with this issue?


@segadu78, there is a similar workaround shown in our support article Creating Unique Serial Numbers in Forms which outlines that it should work smoothly with Enketo.

Thank you for your response. Unfortunately, how I show in this post, the calculate number doesn’t work in the cell phone o Tablet, but works perfectly on Enketo web.

Do you know how I could resolve or why happen this?


Hi @segadu78
I was able to replicate your issue and much to my surprise, it seems this does not work both on KoBoCollect and ODK Collect (I know @wroos had asked this).

I did a search on the issues with string way back in 2017 and @Xiphware had indicated that this was not fully supported on ODK and hence, technically KoBoCollect.

However in this case, and contrary to the issue back in 2017, the calculation seems to happen on both collect variants, but it is limited to only pulling the first concatenation command substr(today(),2,4) and does not operationalize the rest

It seems you may have to devise a different approach in executing this. You could potentially create all the substr commands as separate calculate questions, and then contact the end result of these calculate questions. You may also want to lock this by applying the parameter once(YOUR CALCULATIONS).



Yup, this was true, back in 2017. But substring-before() and substring-after() are now supported by ODK Collect, and consequently most of the recent KoboCollect versions too. :man_dancing: So you might want to switch to use them if substr() is giving you issues.

[aside: interesting historical fact: I’m happen to be the one who added them to javaRosa:grin:]


Minor point, but calling the now() function multiple times in a calculation isnt great programming practice; if you want to generate a particular value from a (dynamic) data source, its better to obtain said data once, then perform whatever translations you wish on it to transform it to your identifier [otherwise there’s always a slight possibility that your data source could change each time you fetch it…]

Also, have you considered using format-date-time() to extract whatever date & time components you are interested in and format them into your custom id string?


I noticed that too, kudos.

Thanks so much, @Xiphware for the recommendation.


1 Like

Thank you for your response @Xiphware,

Could you give me an example using this functions?


Maybe the documentation can help you already

1 Like