Skip to content

Nested RECORD TIMESTAMP fields returned as RFC3339 strings instead of epoch microseconds #482

@odsod

Description

@odsod

Description

When querying a table that has TIMESTAMP fields inside a nested RECORD (struct), the emulator returns the timestamp value as an RFC3339 string (e.g., "2026-05-20T11:00:00Z") instead of the integer microseconds-since-epoch format that real BigQuery uses (e.g., "1716202200000000").

Top-level TIMESTAMP fields are returned correctly as epoch microseconds.

This causes the Go BigQuery client (cloud.google.com/go/bigquery) to fail with:

strconv.ParseInt: parsing "2026-05-20T11:00:00Z": invalid syntax

...because convertBasicType for TimestampFieldType expects a numeric string.

Reproduction

package main

import (
	"context"
	"fmt"
	"time"

	"cloud.google.com/go/bigquery"
	"google.golang.org/api/iterator"
	"google.golang.org/api/option"
)

type bqRow map[string]bigquery.Value

func (r bqRow) Save() (map[string]bigquery.Value, string, error) {
	return map[string]bigquery.Value(r), bigquery.NoDedupeID, nil
}

func main() {
	ctx := context.Background()
	client, _ := bigquery.NewClient(ctx, "local",
		option.WithEndpoint("http://localhost:9050"),
		option.WithoutAuthentication(),
	)
	defer client.Close()

	_ = client.Dataset("ts_test").Create(ctx, &bigquery.DatasetMetadata{})
	_ = client.Dataset("ts_test").Table("nested_ts").Delete(ctx)

	schema := bigquery.Schema{
		{Name: "id", Type: bigquery.StringFieldType},
		{Name: "top_ts", Type: bigquery.TimestampFieldType},
		{Name: "nested", Type: bigquery.RecordFieldType, Repeated: true, Schema: bigquery.Schema{
			{Name: "name", Type: bigquery.StringFieldType},
			{Name: "nested_ts", Type: bigquery.TimestampFieldType},
		}},
	}
	_ = client.Dataset("ts_test").Table("nested_ts").Create(ctx, &bigquery.TableMetadata{Schema: schema})

	r := bqRow{
		"id":     "test-1",
		"top_ts": time.Date(2026, 5, 20, 10, 30, 0, 0, time.UTC),
		"nested": []map[string]bigquery.Value{
			{"name": "activity-1", "nested_ts": time.Date(2026, 5, 20, 11, 0, 0, 0, time.UTC)},
		},
	}
	_ = client.Dataset("ts_test").Table("nested_ts").Inserter().Put(ctx, r)

	q := client.Query("SELECT * FROM `local.ts_test.nested_ts`")
	it, _ := q.Read(ctx)

	var values []bigquery.Value
	err := it.Next(&values)
	fmt.Printf("error: %v\n", err) // strconv.ParseInt: parsing "2026-05-20T11:00:00Z": invalid syntax
}

Expected behavior

Nested TIMESTAMP fields should be returned in the same format as top-level TIMESTAMP fields — integer microseconds since Unix epoch encoded as a string (e.g., "1716202200000000").

Environment

  • Emulator image: ghcr.io/goccy/bigquery-emulator:latest
  • Go BigQuery client: cloud.google.com/go/bigquery v1.77.0
  • Started with: bigquery-emulator --project=local --port=9050

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions