Skip to content

feat: enable microsecond timestamps in client - #14057

Open
kanchi12P wants to merge 2 commits into
googleapis:mainfrom
kanchi12P:feature-microsecond-timestamps
Open

feat: enable microsecond timestamps in client#14057
kanchi12P wants to merge 2 commits into
googleapis:mainfrom
kanchi12P:feature-microsecond-timestamps

Conversation

@kanchi12P

Copy link
Copy Markdown
  • Enable microsecond timestamp flag in stub settings
  • Plumb timestamp origin to Mutation setCell
  • Skip emulator in mutation-based integration tests to prevent failures

This pulls in the proto changes for microsecond timestamps from google3
and generates the corresponding Java classes in proto-google-cloud-bigtable-v2.

Change-Id: I32650601b901f6e64a106e24a280a2ee608ce5e6
@kanchi12P
kanchi12P requested review from a team as code owners August 12, 2026 20:14
- Enable microsecond timestamp flag in stub settings
- Plumb timestamp origin to Mutation setCell
- Skip emulator in mutation-based integration tests to prevent failures

Change-Id: Ifd8824a5934f17c9d6a5e0e8cf8b0a0a7343ccb1

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces microsecond timestamp granularity for Bigtable mutations, including setting the timestamp origin (client auto-generated vs. user-specified) and enabling the microsecond timestamp feature flag in stub settings. Integration tests are updated to skip emulator environments that do not support this granularity, and several protobuf-generated files are regenerated. The review feedback suggests avoiding a potential JDK overflow bug in the year 2262 by directly calculating microseconds since epoch instead of using Instant.until, and recommends adding a @Nonnull annotation to the timestampOrigin parameter for consistency.

public Mutation setCell(
@Nonnull String familyName, @Nonnull ByteString qualifier, @Nonnull ByteString value) {
long timestamp = System.currentTimeMillis() * 1_000;
long timestamp = Instant.EPOCH.until(Instant.now(), ChronoUnit.MICROS);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Using Instant.EPOCH.until(Instant.now(), ChronoUnit.MICROS) has a subtle but critical drawback in Java: the JDK implementation of Instant.until(..., ChronoUnit.MICROS) internally calculates the difference in nanoseconds first (nanosUntil) and then divides by 1000. Because nanoseconds since epoch overflow a long in the year 2262, this call will throw an ArithmeticException after that date, even though microseconds since epoch can easily fit in a long for another 292,000 years.

Additionally, it introduces unnecessary overhead due to temporal unit dispatching and multiple overflow-checked math operations.

We can compute the microseconds since epoch directly and safely using:

Instant now = Instant.now();
long timestamp = now.getEpochSecond() * 1_000_000L + now.getNano() / 1_000;

This is more efficient, avoids the JDK overflow bug, and is extremely clean.

Suggested change
long timestamp = Instant.EPOCH.until(Instant.now(), ChronoUnit.MICROS);
Instant now = Instant.now();
long timestamp = now.getEpochSecond() * 1_000_000L + now.getNano() / 1_000;

Comment on lines +176 to +181
private Mutation setCell(
@Nonnull String familyName,
@Nonnull ByteString qualifier,
long timestamp,
@Nonnull ByteString value,
TimestampOrigin timestampOrigin) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The timestampOrigin parameter is not annotated with @Nonnull, whereas other object parameters in this method (and other overloads) are. Adding @Nonnull improves type safety and consistency.

Suggested change
private Mutation setCell(
@Nonnull String familyName,
@Nonnull ByteString qualifier,
long timestamp,
@Nonnull ByteString value,
TimestampOrigin timestampOrigin) {
private Mutation setCell(
@Nonnull String familyName,
@Nonnull ByteString qualifier,
long timestamp,
@Nonnull ByteString value,
@Nonnull TimestampOrigin timestampOrigin) {

@Test
public void setCellTest() {
long minTimestamp = System.currentTimeMillis() * 1_000;
long minTimestamp = Instant.EPOCH.until(Instant.now(), ChronoUnit.MICROS);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid the JDK overflow bug in Instant.until(..., ChronoUnit.MICROS) (which throws ArithmeticException after the year 2262 due to internal nanosecond calculations) and to improve performance, we can compute the microseconds since epoch directly.

Suggested change
long minTimestamp = Instant.EPOCH.until(Instant.now(), ChronoUnit.MICROS);
Instant minInstant = Instant.now();
long minTimestamp = minInstant.getEpochSecond() * 1_000_000L + minInstant.getNano() / 1_000;

List<com.google.bigtable.v2.Mutation> actual = mutation.getMutations();

long maxTimestamp = System.currentTimeMillis() * 1_000;
long maxTimestamp = Instant.EPOCH.until(Instant.now(), ChronoUnit.MICROS);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

To avoid the JDK overflow bug in Instant.until(..., ChronoUnit.MICROS) (which throws ArithmeticException after the year 2262 due to internal nanosecond calculations) and to improve performance, we can compute the microseconds since epoch directly.

Suggested change
long maxTimestamp = Instant.EPOCH.until(Instant.now(), ChronoUnit.MICROS);
Instant maxInstant = Instant.now();
long maxTimestamp = maxInstant.getEpochSecond() * 1_000_000L + maxInstant.getNano() / 1_000;

@kanchi12P
kanchi12P force-pushed the feature-microsecond-timestamps branch from fe7343e to 41eff3e Compare August 12, 2026 20:17
@kanchi12P

Copy link
Copy Markdown
Author

@mutianf Please review

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant