Re: [Cbor] Multiple ways of expressing the same time via draft-bormann-cbor-time-tag

Carsten Bormann <> Fri, 09 April 2021 09:18 UTC

Return-Path: <>
Received: from localhost (localhost []) by (Postfix) with ESMTP id 6CA7A3A1987 for <>; Fri, 9 Apr 2021 02:18:36 -0700 (PDT)
X-Virus-Scanned: amavisd-new at
X-Spam-Flag: NO
X-Spam-Score: -4.219
X-Spam-Status: No, score=-4.219 tagged_above=-999 required=5 tests=[BAYES_00=-1.9, RCVD_IN_DNSWL_MED=-2.3, RCVD_IN_MSPIKE_H4=-0.01, RCVD_IN_MSPIKE_WL=-0.01, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, URIBL_BLOCKED=0.001] autolearn=ham autolearn_force=no
Received: from ([]) by localhost ( []) (amavisd-new, port 10024) with ESMTP id Krl95tTU_5rj for <>; Fri, 9 Apr 2021 02:18:32 -0700 (PDT)
Received: from ( []) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by (Postfix) with ESMTPS id D580D3A1983 for <>; Fri, 9 Apr 2021 02:18:30 -0700 (PDT)
Received: from [] ( []) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by (Postfix) with ESMTPSA id 4FGsxc5hRjz16gP; Fri, 9 Apr 2021 11:18:28 +0200 (CEST)
Content-Type: text/plain; charset="utf-8"
Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.\))
From: Carsten Bormann <>
In-Reply-To: <>
Date: Fri, 09 Apr 2021 11:18:28 +0200
X-Mao-Original-Outgoing-Id: 639652708.164252-eeaa7bdc059d6bfc9dc8262e6721af6b
Content-Transfer-Encoding: quoted-printable
Message-Id: <>
References: <>
To: Emile Cormier <>
X-Mailer: Apple Mail (2.3608.
Archived-At: <>
Subject: Re: [Cbor] Multiple ways of expressing the same time via draft-bormann-cbor-time-tag
X-Mailman-Version: 2.1.29
Precedence: list
List-Id: "Concise Binary Object Representation \(CBOR\)" <>
List-Unsubscribe: <>, <>
List-Archive: <>
List-Post: <>
List-Help: <>
List-Subscribe: <>, <>
X-List-Received-Date: Fri, 09 Apr 2021 09:18:36 -0000

Hi Emile,

On 2021-04-06, at 22:35, Emile Cormier <> wrote:
> I'm implementing tags 1001 and 1002 in my C++ library to exchange time points and durations (refer to
> I'm in the situation where I''m not sure which is the "expected" way to encode time as nanoseconds since the Unix epoch. I'm specifically referring to std::chrono::system_clock::time_point, which is a 64 bit integer. There are currently three ways I could encode such a value.
> 1. The whole number of seconds under Key 1, with the remaining nanoseconds under Key -9.
> 2. The total number of nanoseconds under Key -9, with a value of zero under Key 1.
> 3. The total number of nanoseconds expressed as a Decimal Fraction under Key 4.

Oh.  You are pointing out a deficiency of the current text.  The *intention* was that Key 1 is an integer and Key -3*n is supplying the fractional part.  E.g., like UNIX struct timeval for -6 (old) and struct timespec for -9 (new) do.
So that would be your Option 1.

But since you raise it, we probably should entertain the question.

The issue really is whether the onus is on the sender/encoder or the recipient/decoder.

Restricting the value for key -3*n to be less than 10**(3*n) places the onus on the sender, who would need to do a modulo if that is not the way the data is already represented on the sender’s platform.
Not adding this restriction places the onus on the recipient, who would then need to do the modulo in case the recipient’s platform representation is like one of the UNIX ones.

> Option #2 is the easiest and most efficient because it doesn't involve a division/subtraction calculation.

… for the sender.

> However, a receiver that discards Key -9 will end up with zero seconds. At least with option #1, the receiver will know the number of whole seconds if Key -9 is ignored.

Which indeed maybe also is a concern.

> Option #3 requires that the sender and receiver understand Tag 4 (Decimal Fraction), or at least the concept of decimal fractions within the context of tags 1001-1003.

That would seem to be the easier case; “understanding” Tag 4 in this context is limited to being able to parse the 4([-6, microseconds]) arrangement, unless the sender’s code looks for trailing zeros and does stunts like 4([-5, tens-of-microseconds]) in these cases, which of course cannot be excluded.

> I'm guessing that option #1 is the "canonical" way, but I'm not entirely sure. Some guidance would be appreciated. Perhaps a few words concerning this should be added to the standard's text?

Definitely, either way.

I think I’m mildly in favor of placing the onus on the sender, i.e., Option 1.

etime = #6.1001({
  1: int,
  ? (
    -3: uint .lt 1000 //
    -6: uint .lt 1000000 //
    -9: uint .lt 1000000000 //
    -12: uint .lt 1000000000000 //
    -15: uint .lt 1000000000000000 //
    -18: uint .lt 1000000000000000000

> On the receiving side, my library would ideally handle all three scenarios. It's on the sending side I'm more concerned about when I need to interoperate with CBOR decoders other than mine.

Right, be conservative…liberal…

Thanks for bringing this up!

One always learns a lot from implementation efforts.

Grüße, Carsten