Skip to content
This repository was archived by the owner on Feb 24, 2026. It is now read-only.

Commit 29fa8b7

Browse files
fix: better ISO8601 compliance (#1589)
* fix: Timestamps parsed using datetimeformater similar to other google libraries Signed-off-by: dark0dave <[email protected]> * 🦉 Updates from OwlBot post-processor See https://github.com/googleapis/repo-automation-bots/blob/main/packages/owl-bot/README.md Co-authored-by: Owl Bot <gcf-owl-bot[bot]@users.noreply.github.com>
1 parent ba21516 commit 29fa8b7

4 files changed

Lines changed: 73 additions & 4 deletions

File tree

google-cloud-bigquerystorage/src/main/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessage.java

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
import com.google.protobuf.Message;
2929
import com.google.protobuf.UninitializedMessageException;
3030
import java.math.BigDecimal;
31-
import java.sql.Timestamp;
3231
import java.time.LocalDate;
3332
import java.util.List;
3433
import java.util.logging.Logger;
@@ -37,6 +36,11 @@
3736
import org.json.JSONObject;
3837
import org.threeten.bp.LocalDateTime;
3938
import org.threeten.bp.LocalTime;
39+
import org.threeten.bp.ZoneOffset;
40+
import org.threeten.bp.format.DateTimeFormatter;
41+
import org.threeten.bp.format.DateTimeFormatterBuilder;
42+
import org.threeten.bp.temporal.ChronoField;
43+
import org.threeten.bp.temporal.TemporalAccessor;
4044

4145
/**
4246
* Converts Json data to protocol buffer messages given the protocol buffer descriptor. The protobuf
@@ -54,6 +58,32 @@ public class JsonToProtoMessage {
5458
.put(FieldDescriptor.Type.STRING, "string")
5559
.put(FieldDescriptor.Type.MESSAGE, "object")
5660
.build();
61+
private static final DateTimeFormatter timestampFormatter =
62+
new DateTimeFormatterBuilder()
63+
.parseLenient()
64+
.append(DateTimeFormatter.ISO_LOCAL_DATE)
65+
.optionalStart()
66+
.appendLiteral('T')
67+
.optionalEnd()
68+
.optionalStart()
69+
.appendLiteral(' ')
70+
.optionalEnd()
71+
.appendValue(ChronoField.HOUR_OF_DAY, 2)
72+
.appendLiteral(':')
73+
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
74+
.optionalStart()
75+
.appendLiteral(':')
76+
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
77+
.optionalStart()
78+
.appendFraction(ChronoField.NANO_OF_SECOND, 6, 9, true)
79+
.optionalStart()
80+
.appendOffset("+HHMM", "+00:00")
81+
.optionalEnd()
82+
.optionalStart()
83+
.appendLiteral('Z')
84+
.optionalEnd()
85+
.toFormatter()
86+
.withZone(ZoneOffset.UTC);
5787

5888
/**
5989
* Converts Json data to protocol buffer messages given the protocol buffer descriptor.
@@ -306,7 +336,11 @@ private static void fillField(
306336
}
307337
} else if (fieldSchema.getType() == TableFieldSchema.Type.TIMESTAMP) {
308338
if (val instanceof String) {
309-
protoMsg.setField(fieldDescriptor, Timestamp.valueOf((String) val).getTime());
339+
TemporalAccessor parsedTime = timestampFormatter.parse((String) val);
340+
protoMsg.setField(
341+
fieldDescriptor,
342+
parsedTime.getLong(ChronoField.INSTANT_SECONDS) * 1000000
343+
+ parsedTime.getLong(ChronoField.MICRO_OF_SECOND));
310344
return;
311345
} else if (val instanceof Long) {
312346
protoMsg.setField(fieldDescriptor, (Long) val);
@@ -515,7 +549,11 @@ private static void fillRepeatedField(
515549
} else if (fieldSchema != null
516550
&& fieldSchema.getType() == TableFieldSchema.Type.TIMESTAMP) {
517551
if (val instanceof String) {
518-
protoMsg.addRepeatedField(fieldDescriptor, Timestamp.valueOf((String) val).getTime());
552+
TemporalAccessor parsedTime = timestampFormatter.parse((String) val);
553+
protoMsg.addRepeatedField(
554+
fieldDescriptor,
555+
parsedTime.getLong(ChronoField.INSTANT_SECONDS) * 1000000
556+
+ parsedTime.getLong(ChronoField.MICRO_OF_SECOND));
519557
} else if (val instanceof Long) {
520558
protoMsg.addRepeatedField(fieldDescriptor, (Long) val);
521559
} else {

google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1/JsonToProtoMessageTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,31 @@ public void testDouble() throws Exception {
656656
assertEquals(expectedProto, protoMsg);
657657
}
658658

659+
@Test
660+
public void testTimestamp() throws Exception {
661+
TableSchema tableSchema =
662+
TableSchema.newBuilder()
663+
.addFields(TableFieldSchema.newBuilder(TEST_TIMESTAMP).setName("test_string").build())
664+
.addFields(
665+
TableFieldSchema.newBuilder(TEST_TIMESTAMP).setName("test_string_T_Z").build())
666+
.addFields(TableFieldSchema.newBuilder(TEST_TIMESTAMP).setName("test_long").build())
667+
.build();
668+
TestTimestamp expectedProto =
669+
TestTimestamp.newBuilder()
670+
.setTestString(10L)
671+
.setTestStringTZ(1648493279000000L)
672+
.setTestLong(0L)
673+
.build();
674+
JSONObject json = new JSONObject();
675+
json.put("test_string", "1970-01-01 00:00:00.000010");
676+
json.put("test_string_T_Z", "2022-03-28T18:47:59.00Z");
677+
json.put("test_long", 0L);
678+
DynamicMessage protoMsg =
679+
JsonToProtoMessage.convertJsonToProtoMessage(
680+
TestTimestamp.getDescriptor(), tableSchema, json);
681+
assertEquals(expectedProto, protoMsg);
682+
}
683+
659684
@Test
660685
public void testDate() throws Exception {
661686
TableSchema tableSchema =

google-cloud-bigquerystorage/src/test/java/com/google/cloud/bigquery/storage/v1/it/ITBigQueryWriteManualClientTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,7 @@ public void testJsonStreamWriterWithDefaultStream()
457457
assertEquals(2, currentRow.get(3).getRepeatedValue().size());
458458
assertEquals("Yg==", currentRow.get(3).getRepeatedValue().get(1).getStringValue());
459459
assertEquals(
460-
Timestamp.valueOf("2022-02-06 07:24:47.84").getTime(),
460+
Timestamp.valueOf("2022-02-06 07:24:47.84").getTime() * 1000,
461461
currentRow.get(4).getTimestampValue()); // timestamp long of "2022-02-06 07:24:47.84"
462462
assertEquals("bbb", iter.next().get(0).getStringValue());
463463
assertEquals("ccc", iter.next().get(0).getStringValue());

google-cloud-bigquerystorage/src/test/proto/jsonTest.proto

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,12 @@ message TestDouble {
134134
optional double string = 7;
135135
}
136136

137+
message TestTimestamp {
138+
optional int64 test_string = 1;
139+
optional int64 test_string_t_z = 2;
140+
optional int64 test_long = 3;
141+
}
142+
137143
message TestDate {
138144
optional int32 test_string = 1;
139145
optional int32 test_long = 2;

0 commit comments

Comments
 (0)