Events and timestamps: When did something really happen?

Every event has a timestamp. But does it really indicate when something happened? A common misconception with consequences.

listen Print view
Man in a suit stamps a document

(Image: Chokniti Khongchum/Shutterstock.com)

6 min. read
By
  • Golo Roden
Contents

Anyone working with events will sooner or later encounter a seemingly simple question: When did something actually happen? And the answer seems obvious, as every event comes with a timestamp. In the case of CloudEvents, for example, there is the time field, which many systems automatically set when an event is stored. It's natural to use this timestamp for business logic, as it's there after all. However, this is precisely what leads to subtle errors and false assumptions.

the next big thing – Golo Roden
the next big thing – Golo Roden

Golo Roden is the founder and CTO of the native web GmbH. He works on the design and development of web and cloud applications and APIs, with a focus on event-driven and service-based distributed architectures. His guiding principle is that software development is not an end in itself, but must always follow an underlying technical expertise.

Let's take a classic library example. A reader borrows a book, and the system generates the following event:

{
"source": "https://library.thenativeweb.io",
"subject": "/books/42",
"type": "io.thenativeweb.library.book-borrowed",
"data": {
"borrowedBy": "/readers/23",
"borrowedUntil": "2026-02-12"
}
}

Do you notice anything? The event contains borrowedUntil (the return date), but no borrowedAt. Anyone who wants to know when the book was actually borrowed would have to rely on the technical timestamp of the event.

But here lies the problem: What if the reader borrowed the book at 2:00 PM, but the system only wrote the event at 2:02 PM? Or if the librarian only entered yesterday's loans this morning? The technical timestamp tells us when the event was stored, not when the loan actually took place.

There are several reasons why the technical timestamp is problematic for business logic. A technical timestamp describes when the system did something. A business timestamp describes when something happened in the real world. These are two fundamentally different concepts, and conflating them can lead to subtle errors.

The time field of an event answers the question:

"When was this event recorded?"

However, the business requirement is often:

"When did this really happen?"

This is not the same question. And importantly, this is not about precision or latency, but rather about semantics.

Furthermore, whether a timestamp field even exists depends on the event format. CloudEvents includes a time field, but other formats may not. Anyone who ever needs to convert events to another format (e.g., for archiving, export, or integration into other systems) risks losing the technical timestamp. If business logic depends on a field that could disappear during a migration, you are building on unstable ground.

And perhaps the strongest argument: events are often recorded only after the actual occurrence. A few examples:

  • A librarian notices that someone entered yesterday's loan with the wrong date. They write the correction event today, even though it refers to something that happened yesterday.
  • A mobile library app records a loan while the device is offline. When it synchronizes hours later, the event is only persisted then, but the actual loan occurred much earlier.
  • Data migration from a legacy system imports years of historical events. The technical timestamps would all show today's date, rendering historical analyses worthless.
  • If the target system was temporarily unreachable, events may be cached and written later. The technical timestamp shows the write time, not the original event.

In all these cases, the technical timestamp provides incorrect answers for business logic.

This means: If time is relevant to the business, it belongs in the event data. Here is the improved version of the loan event:

{
"source": "https://library.thenativeweb.io",
"subject": "/books/42",
"type": "io.thenativeweb.library.book-borrowed",
"data": {
"borrowedBy": "/readers/23",
"borrowedAt": "2026-01-12T14:00:00.000Z",
"borrowedUntil": "2026-02-12"
}
}

Now the semantics are clear:

  • borrowedAt: When the book was actually borrowed (business time)
  • borrowedUntil: When the book must be returned (business time (this was already correct))
  • Event timestamp: When the system recorded this event (technical time)

Interestingly, borrowedUntil was already a business time field. It just lacked its counterpart borrowedAt. This inconsistency is typical: developers often think about including future points in time (deadlines, due dates, expiration dates...), but often forget past times, i.e., when something actually happened.

The pattern can be applied to other events:

  • book-borrowed with borrowedAt: When the book was borrowed
  • book-returned with returnedAt: When the book was returned
  • reader-registered with registeredAt: When the reader registered
  • late-fee-charged with chargedFor: Which period the fee covers

Each of these fields describes when something happened in the real world, regardless of when the system recorded it.

Does this mean you should thoroughly ignore the technical timestamp? No. There are legitimate uses: debugging to trace the order of event persistence. Monitoring to measure system latency and throughput. Audit trails to document when records entered the system.

But these are all technical concerns, not business concerns.

And what about the technical timestamp as a fallback if you forgot to add a business time field? That's a workaround, not a solution. If you find yourself in this situation, you should consider introducing a new version of the event type that includes the explicit time field. Yes, then you'll have to be able to process both versions, but you'll gain clarity and correctness for the future.

You should also not try to sugarcoat the whole thing with

"the latency is small enough"

or

"we don't need high precision"

. These arguments miss the point. It's not about latency or precision, but about semantic clarity. A technical timestamp and a business timestamp answer different questions, regardless of how close their values may be.

Time seems simple until you look closer. When working with events, the distinction between "when something happened" and "when the system recorded it" is fundamental. Blurring this line risks subtle bugs, erroneous reports, and systems that do not accurately reflect reality.

The solution is simple: If time is relevant to the business, it belongs explicitly in the event data. Your future self (and everyone who has to analyze these events later) will thank you. (who)

Don't miss any news – follow us on Facebook, LinkedIn or Mastodon.

This article was originally published in German. It was translated with technical assistance and editorially reviewed before publication.