Skip to content

Commit

Permalink
fix: better ISO8601 compliance (#1589)
Browse files Browse the repository at this point in the history
* fix: Timestamps parsed using datetimeformater similar to other google libraries

Signed-off-by: dark0dave <dark0dave@mykolab.com>

* 🦉 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>
  • Loading branch information
dark0dave and gcf-owl-bot[bot] committed Mar 31, 2022
1 parent ba21516 commit 29fa8b7
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import com.google.protobuf.Message;
import com.google.protobuf.UninitializedMessageException;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.time.LocalDate;
import java.util.List;
import java.util.logging.Logger;
Expand All @@ -37,6 +36,11 @@
import org.json.JSONObject;
import org.threeten.bp.LocalDateTime;
import org.threeten.bp.LocalTime;
import org.threeten.bp.ZoneOffset;
import org.threeten.bp.format.DateTimeFormatter;
import org.threeten.bp.format.DateTimeFormatterBuilder;
import org.threeten.bp.temporal.ChronoField;
import org.threeten.bp.temporal.TemporalAccessor;

/**
* Converts Json data to protocol buffer messages given the protocol buffer descriptor. The protobuf
Expand All @@ -54,6 +58,32 @@ public class JsonToProtoMessage {
.put(FieldDescriptor.Type.STRING, "string")
.put(FieldDescriptor.Type.MESSAGE, "object")
.build();
private static final DateTimeFormatter timestampFormatter =
new DateTimeFormatterBuilder()
.parseLenient()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.optionalStart()
.appendLiteral('T')
.optionalEnd()
.optionalStart()
.appendLiteral(' ')
.optionalEnd()
.appendValue(ChronoField.HOUR_OF_DAY, 2)
.appendLiteral(':')
.appendValue(ChronoField.MINUTE_OF_HOUR, 2)
.optionalStart()
.appendLiteral(':')
.appendValue(ChronoField.SECOND_OF_MINUTE, 2)
.optionalStart()
.appendFraction(ChronoField.NANO_OF_SECOND, 6, 9, true)
.optionalStart()
.appendOffset("+HHMM", "+00:00")
.optionalEnd()
.optionalStart()
.appendLiteral('Z')
.optionalEnd()
.toFormatter()
.withZone(ZoneOffset.UTC);

/**
* Converts Json data to protocol buffer messages given the protocol buffer descriptor.
Expand Down Expand Up @@ -306,7 +336,11 @@ private static void fillField(
}
} else if (fieldSchema.getType() == TableFieldSchema.Type.TIMESTAMP) {
if (val instanceof String) {
protoMsg.setField(fieldDescriptor, Timestamp.valueOf((String) val).getTime());
TemporalAccessor parsedTime = timestampFormatter.parse((String) val);
protoMsg.setField(
fieldDescriptor,
parsedTime.getLong(ChronoField.INSTANT_SECONDS) * 1000000
+ parsedTime.getLong(ChronoField.MICRO_OF_SECOND));
return;
} else if (val instanceof Long) {
protoMsg.setField(fieldDescriptor, (Long) val);
Expand Down Expand Up @@ -515,7 +549,11 @@ private static void fillRepeatedField(
} else if (fieldSchema != null
&& fieldSchema.getType() == TableFieldSchema.Type.TIMESTAMP) {
if (val instanceof String) {
protoMsg.addRepeatedField(fieldDescriptor, Timestamp.valueOf((String) val).getTime());
TemporalAccessor parsedTime = timestampFormatter.parse((String) val);
protoMsg.addRepeatedField(
fieldDescriptor,
parsedTime.getLong(ChronoField.INSTANT_SECONDS) * 1000000
+ parsedTime.getLong(ChronoField.MICRO_OF_SECOND));
} else if (val instanceof Long) {
protoMsg.addRepeatedField(fieldDescriptor, (Long) val);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,31 @@ public void testDouble() throws Exception {
assertEquals(expectedProto, protoMsg);
}

@Test
public void testTimestamp() throws Exception {
TableSchema tableSchema =
TableSchema.newBuilder()
.addFields(TableFieldSchema.newBuilder(TEST_TIMESTAMP).setName("test_string").build())
.addFields(
TableFieldSchema.newBuilder(TEST_TIMESTAMP).setName("test_string_T_Z").build())
.addFields(TableFieldSchema.newBuilder(TEST_TIMESTAMP).setName("test_long").build())
.build();
TestTimestamp expectedProto =
TestTimestamp.newBuilder()
.setTestString(10L)
.setTestStringTZ(1648493279000000L)
.setTestLong(0L)
.build();
JSONObject json = new JSONObject();
json.put("test_string", "1970-01-01 00:00:00.000010");
json.put("test_string_T_Z", "2022-03-28T18:47:59.00Z");
json.put("test_long", 0L);
DynamicMessage protoMsg =
JsonToProtoMessage.convertJsonToProtoMessage(
TestTimestamp.getDescriptor(), tableSchema, json);
assertEquals(expectedProto, protoMsg);
}

@Test
public void testDate() throws Exception {
TableSchema tableSchema =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ public void testJsonStreamWriterWithDefaultStream()
assertEquals(2, currentRow.get(3).getRepeatedValue().size());
assertEquals("Yg==", currentRow.get(3).getRepeatedValue().get(1).getStringValue());
assertEquals(
Timestamp.valueOf("2022-02-06 07:24:47.84").getTime(),
Timestamp.valueOf("2022-02-06 07:24:47.84").getTime() * 1000,
currentRow.get(4).getTimestampValue()); // timestamp long of "2022-02-06 07:24:47.84"
assertEquals("bbb", iter.next().get(0).getStringValue());
assertEquals("ccc", iter.next().get(0).getStringValue());
Expand Down
6 changes: 6 additions & 0 deletions google-cloud-bigquerystorage/src/test/proto/jsonTest.proto
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,12 @@ message TestDouble {
optional double string = 7;
}

message TestTimestamp {
optional int64 test_string = 1;
optional int64 test_string_t_z = 2;
optional int64 test_long = 3;
}

message TestDate {
optional int32 test_string = 1;
optional int32 test_long = 2;
Expand Down

0 comments on commit 29fa8b7

Please sign in to comment.