Repository: arrow
Updated Branches:
  refs/heads/master 4381845b5 -> 681afabb4


ARROW-977: [java] Add Timezone aware timestamp vectors

Author: Julien Le Dem <jul...@apache.org>

Closes #644 from julienledem/TZ and squashes the following commits:

37987b9 [Julien Le Dem] add integration tests
a58fcae [Julien Le Dem] add integration test
39966aa [Julien Le Dem] add other vectors and tests
bf245ce [Julien Le Dem] add TZ vectors


Project: http://git-wip-us.apache.org/repos/asf/arrow/repo
Commit: http://git-wip-us.apache.org/repos/asf/arrow/commit/681afabb
Tree: http://git-wip-us.apache.org/repos/asf/arrow/tree/681afabb
Diff: http://git-wip-us.apache.org/repos/asf/arrow/diff/681afabb

Branch: refs/heads/master
Commit: 681afabb4fa138e7dab694fa63f60220810eb17e
Parents: 4381845
Author: Julien Le Dem <jul...@apache.org>
Authored: Mon May 15 16:16:53 2017 -0400
Committer: Wes McKinney <wes.mckin...@twosigma.com>
Committed: Mon May 15 16:16:53 2017 -0400

----------------------------------------------------------------------
 integration/integration_test.py                 |   6 +-
 .../src/main/codegen/data/ValueVectorTypes.tdd  |  36 ++-
 .../codegen/templates/AbstractFieldWriter.java  |  10 +-
 .../AbstractPromotableFieldWriter.java          |  31 ++-
 .../src/main/codegen/templates/BaseWriter.java  |   4 +-
 .../main/codegen/templates/ComplexCopier.java   |   7 +-
 .../codegen/templates/FixedValueVectors.java    |  50 ++--
 .../src/main/codegen/templates/MapWriters.java  |  38 ++-
 .../codegen/templates/NullableValueVectors.java |  36 ++-
 .../main/codegen/templates/UnionListWriter.java |   2 +-
 .../src/main/codegen/templates/UnionWriter.java |   6 +-
 .../templates/VariableLengthVectors.java        |  47 ++--
 .../arrow/vector/file/json/JsonFileReader.java  |  20 +-
 .../org/apache/arrow/vector/types/Types.java    |  79 +++++--
 .../complex/writer/TestComplexWriter.java       | 232 ++++++++++++++-----
 .../apache/arrow/vector/file/BaseFileTest.java  |  13 +-
 .../apache/arrow/vector/pojo/TestConvert.java   |   3 +-
 17 files changed, 429 insertions(+), 191 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/integration/integration_test.py
----------------------------------------------------------------------
diff --git a/integration/integration_test.py b/integration/integration_test.py
index 6466469..cc59593 100644
--- a/integration/integration_test.py
+++ b/integration/integration_test.py
@@ -620,7 +620,11 @@ def generate_datetime_case():
         TimestampType('f7', 'ms'),
         TimestampType('f8', 'us'),
         TimestampType('f9', 'ns'),
-        TimestampType('f10', 'ms', tz=None)
+        TimestampType('f10', 'ms', tz=None),
+        TimestampType('f11', 's', tz='UTC'),
+        TimestampType('f12', 'ms', tz='US/Eastern'),
+        TimestampType('f13', 'us', tz='Europe/Paris'),
+        TimestampType('f14', 'ns', tz='US/Pacific')
     ]
 
     batch_sizes = [7, 10]

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/data/ValueVectorTypes.tdd
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/data/ValueVectorTypes.tdd 
b/java/vector/src/main/codegen/data/ValueVectorTypes.tdd
index ca6d9ec..4d8c99e 100644
--- a/java/vector/src/main/codegen/data/ValueVectorTypes.tdd
+++ b/java/vector/src/main/codegen/data/ValueVectorTypes.tdd
@@ -71,12 +71,28 @@
       minor: [
         { class: "BigInt"},
         { class: "UInt8" },
-        { class: "Float8",         javaType: "double", boxedType: "Double",    
                          fields: [{name: "value", type: "double"}], },
-        { class: "DateMilli",      javaType: "long",                      
friendlyType: "LocalDateTime" },
-        { class: "TimeStampSec",   javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
-        { class: "TimeStampMilli", javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
-        { class: "TimeStampMicro", javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
-        { class: "TimeStampNano",  javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
+        { class: "Float8",           javaType: "double", boxedType: "Double", 
fields: [{name: "value", type: "double"}] },
+        { class: "DateMilli",        javaType: "long",                      
friendlyType: "LocalDateTime" },
+        { class: "TimeStampSec",     javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
+        { class: "TimeStampMilli",   javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
+        { class: "TimeStampMicro",   javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
+        { class: "TimeStampNano",    javaType: "long",   boxedType: "Long", 
friendlyType: "LocalDateTime" },
+        { class: "TimeStampSecTZ", javaType: "long",   boxedType: "Long",
+                                     typeParams: [ {name: "timezone", type: 
"String"} ],
+                                     arrowType: 
"org.apache.arrow.vector.types.pojo.ArrowType.Timestamp",
+                                     arrowTypeConstructorParams: 
["org.apache.arrow.vector.types.TimeUnit.SECOND", "timezone"] },
+        { class: "TimeStampMilliTZ", javaType: "long",   boxedType: "Long",
+                                     typeParams: [ {name: "timezone", type: 
"String"} ],
+                                     arrowType: 
"org.apache.arrow.vector.types.pojo.ArrowType.Timestamp",
+                                     arrowTypeConstructorParams: 
["org.apache.arrow.vector.types.TimeUnit.MILLISECOND", "timezone"] },
+        { class: "TimeStampMicroTZ", javaType: "long",   boxedType: "Long",
+                                     typeParams: [ {name: "timezone", type: 
"String"} ],
+                                     arrowType: 
"org.apache.arrow.vector.types.pojo.ArrowType.Timestamp",
+                                     arrowTypeConstructorParams: 
["org.apache.arrow.vector.types.TimeUnit.MICROSECOND", "timezone"] },
+        { class: "TimeStampNanoTZ", javaType: "long",   boxedType: "Long",
+                                     typeParams: [ {name: "timezone", type: 
"String"} ],
+                                     arrowType: 
"org.apache.arrow.vector.types.pojo.ArrowType.Timestamp",
+                                     arrowTypeConstructorParams: 
["org.apache.arrow.vector.types.TimeUnit.NANOSECOND", "timezone"] },
         { class: "TimeMicro" },
         { class: "TimeNano" }
       ]
@@ -97,7 +113,13 @@
       boxedType: "ArrowBuf",
 
       minor: [
-        { class: "Decimal", maxPrecisionDigits: 38, nDecimalDigits: 4, 
friendlyType: "BigDecimal", fields: [{name: "start", type: "int"}, {name: 
"buffer", type: "ArrowBuf"}, {name: "scale", type: "int", include: false}, 
{name: "precision", type: "int", include: false}] }
+        {
+          class: "Decimal",
+          maxPrecisionDigits: 38, nDecimalDigits: 4, friendlyType: 
"BigDecimal",
+          typeParams: [ {name: "scale", type: "int"}, { name: "precision", 
type: "int"}],
+          arrowType: "org.apache.arrow.vector.types.pojo.ArrowType.Decimal",
+          fields: [{name: "start", type: "int"}, {name: "buffer", type: 
"ArrowBuf"}, {name: "scale", type: "int", include: false}, {name: "precision", 
type: "int", include: false}]
+        }
       ]
     },
     {

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/AbstractFieldWriter.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/AbstractFieldWriter.java 
b/java/vector/src/main/codegen/templates/AbstractFieldWriter.java
index de076fc..65bcc05 100644
--- a/java/vector/src/main/codegen/templates/AbstractFieldWriter.java
+++ b/java/vector/src/main/codegen/templates/AbstractFieldWriter.java
@@ -59,7 +59,7 @@ abstract class AbstractFieldWriter extends AbstractBaseWriter 
implements FieldWr
   }
 
   <#if minor.class == "Decimal">
-  public void writeDecimal(int start, ArrowBuf buffer) {
+  public void write${minor.class}(int start, ArrowBuf buffer) {
     fail("${name}");
   }
   <#else>
@@ -114,9 +114,11 @@ abstract class AbstractFieldWriter extends 
AbstractBaseWriter implements FieldWr
   <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
   <#assign upperName = minor.class?upper_case />
   <#assign capName = minor.class?cap_first />
-  <#if minor.class?starts_with("Decimal") >
-  public ${capName}Writer ${lowerName}(String name, int scale, int precision) {
-    fail("${capName}");
+  <#if minor.typeParams?? >
+
+  @Override
+  public ${capName}Writer ${lowerName}(String name<#list minor.typeParams as 
typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
+    fail("${capName}(" + <#list minor.typeParams as 
typeParam>"${typeParam.name}: " + ${typeParam.name} + ", " + </#list>")");
     return null;
   }
   </#if>

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java
----------------------------------------------------------------------
diff --git 
a/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java 
b/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java
index ada0b1d..636b305 100644
--- a/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java
+++ b/java/vector/src/main/codegen/templates/AbstractPromotableFieldWriter.java
@@ -72,31 +72,23 @@ abstract class AbstractPromotableFieldWriter extends 
AbstractFieldWriter {
   }
 
   <#list vv.types as type><#list type.minor as minor><#assign name = 
minor.class?cap_first />
-  <#assign fields = minor.fields!type.fields />
-  <#if !minor.class?starts_with("Decimal") >
+    <#assign fields = minor.fields!type.fields />
   @Override
   public void write(${name}Holder holder) {
     getWriter(MinorType.${name?upper_case}).write(holder);
   }
 
+    <#if minor.class == "Decimal">
+  public void write${minor.class}(int start, ArrowBuf buffer) {
+    getWriter(MinorType.${name?upper_case}).write${minor.class}(start, buffer);
+  }
+    <#else>
   public void write${minor.class}(<#list fields as field>${field.type} 
${field.name}<#if field_has_next>, </#if></#list>) {
     getWriter(MinorType.${name?upper_case}).write${minor.class}(<#list fields 
as field>${field.name}<#if field_has_next>, </#if></#list>);
   }
-
-  <#else>
-  @Override
-  public void write(DecimalHolder holder) {
-    getWriter(MinorType.DECIMAL).write(holder);
-  }
-
-  public void writeDecimal(int start, ArrowBuf buffer) {
-    getWriter(MinorType.DECIMAL).writeDecimal(start, buffer);
-  }
-
-  </#if>
+    </#if>
 
   </#list></#list>
-
   public void writeNull() {
   }
 
@@ -125,10 +117,13 @@ abstract class AbstractPromotableFieldWriter extends 
AbstractFieldWriter {
   <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
   <#assign upperName = minor.class?upper_case />
   <#assign capName = minor.class?cap_first />
-  <#if minor.class?starts_with("Decimal") >
-  public ${capName}Writer ${lowerName}(String name, int scale, int precision) {
-    return getWriter(MinorType.MAP).${lowerName}(name, scale, precision);
+
+  <#if minor.typeParams?? >
+  @Override
+  public ${capName}Writer ${lowerName}(String name<#list minor.typeParams as 
typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
+    return getWriter(MinorType.MAP).${lowerName}(name<#list minor.typeParams 
as typeParam>, ${typeParam.name}</#list>);
   }
+
   </#if>
   @Override
   public ${capName}Writer ${lowerName}(String name) {

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/BaseWriter.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/BaseWriter.java 
b/java/vector/src/main/codegen/templates/BaseWriter.java
index 3da02b0..405f466 100644
--- a/java/vector/src/main/codegen/templates/BaseWriter.java
+++ b/java/vector/src/main/codegen/templates/BaseWriter.java
@@ -53,8 +53,8 @@ public interface BaseWriter extends AutoCloseable, 
Positionable {
     <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
     <#assign upperName = minor.class?upper_case />
     <#assign capName = minor.class?cap_first />
-    <#if minor.class?starts_with("Decimal") >
-    ${capName}Writer ${lowerName}(String name, int scale, int precision);
+    <#if minor.typeParams?? >
+    ${capName}Writer ${lowerName}(String name<#list minor.typeParams as 
typeParam>, ${typeParam.type} ${typeParam.name}</#list>);
     </#if>
     ${capName}Writer ${lowerName}(String name);
     </#list></#list>

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/ComplexCopier.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/ComplexCopier.java 
b/java/vector/src/main/codegen/templates/ComplexCopier.java
index fb7ae0f..518ad5d 100644
--- a/java/vector/src/main/codegen/templates/ComplexCopier.java
+++ b/java/vector/src/main/codegen/templates/ComplexCopier.java
@@ -72,7 +72,8 @@ public class ComplexCopier {
   <#list vv.types as type><#list type.minor as minor><#assign name = 
minor.class?cap_first />
   <#assign fields = minor.fields!type.fields />
   <#assign uncappedName = name?uncap_first/>
-  <#if !minor.class?starts_with("Decimal")>
+
+  <#if !minor.typeParams?? >
 
       case ${name?upper_case}:
         if (reader.isSet()) {
@@ -94,7 +95,7 @@ public class ComplexCopier {
     <#list vv.types as type><#list type.minor as minor><#assign name = 
minor.class?cap_first />
     <#assign fields = minor.fields!type.fields />
     <#assign uncappedName = name?uncap_first/>
-    <#if !minor.class?starts_with("Decimal")>
+    <#if !minor.typeParams?? >
     case ${name?upper_case}:
       return (FieldWriter) writer.<#if name == 
"Int">integer<#else>${uncappedName}</#if>(name);
     </#if>
@@ -113,7 +114,7 @@ public class ComplexCopier {
     <#list vv.types as type><#list type.minor as minor><#assign name = 
minor.class?cap_first />
     <#assign fields = minor.fields!type.fields />
     <#assign uncappedName = name?uncap_first/>
-    <#if !minor.class?starts_with("Decimal")>
+    <#if !minor.typeParams?? >
     case ${name?upper_case}:
     return (FieldWriter) writer.<#if name == 
"Int">integer<#else>${uncappedName}</#if>();
     </#if>

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/FixedValueVectors.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/FixedValueVectors.java 
b/java/vector/src/main/codegen/templates/FixedValueVectors.java
index f403ecf..5d80b66 100644
--- a/java/vector/src/main/codegen/templates/FixedValueVectors.java
+++ b/java/vector/src/main/codegen/templates/FixedValueVectors.java
@@ -25,9 +25,10 @@ import java.util.concurrent.TimeUnit;
 <#list vv.types as type>
 <#list type.minor as minor>
 <#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+<#assign className = "${minor.class}Vector" />
 
 <#if type.major == "Fixed">
-<@pp.changeOutputFile 
name="/org/apache/arrow/vector/${minor.class}Vector.java" />
+<@pp.changeOutputFile name="/org/apache/arrow/vector/${className}.java" />
 <#include "/@includes/license.ftl" />
 
 package org.apache.arrow.vector;
@@ -43,8 +44,8 @@ package org.apache.arrow.vector;
  *
  * NB: this class is automatically generated from ${.template_name} and 
ValueVectorTypes.tdd using FreeMarker.
  */
-public final class ${minor.class}Vector extends BaseDataValueVector implements 
FixedWidthVector{
-  private static final org.slf4j.Logger logger = 
org.slf4j.LoggerFactory.getLogger(${minor.class}Vector.class);
+public final class ${className} extends BaseDataValueVector implements 
FixedWidthVector{
+  private static final org.slf4j.Logger logger = 
org.slf4j.LoggerFactory.getLogger(${className}.class);
 
   public static final int TYPE_WIDTH = ${type.width};
 
@@ -53,24 +54,25 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements F
 
   private int allocationSizeInBytes = INITIAL_VALUE_ALLOCATION * ${type.width};
   private int allocationMonitor = 0;
+  <#if minor.typeParams??>
 
-  <#if minor.class == "Decimal">
+     <#list minor.typeParams as typeParam>
+  private final ${typeParam.type} ${typeParam.name};
+    </#list>
 
-  private int precision;
-  private int scale;
-
-  public ${minor.class}Vector(String name, BufferAllocator allocator, int 
precision, int scale) {
+  public ${className}(String name, BufferAllocator allocator<#list 
minor.typeParams as typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
     super(name, allocator);
-    this.precision = precision;
-    this.scale = scale;
+    <#list minor.typeParams as typeParam>
+    this.${typeParam.name} = ${typeParam.name};
+    </#list>
   }
   <#else>
-  public ${minor.class}Vector(String name, BufferAllocator allocator) {
+
+  public ${className}(String name, BufferAllocator allocator) {
     super(name, allocator);
   }
   </#if>
 
-
   @Override
   public MinorType getMinorType() {
     return MinorType.${minor.class?upper_case};
@@ -219,17 +221,17 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements F
 
   @Override
   public TransferPair makeTransferPair(ValueVector to) {
-    return new TransferImpl((${minor.class}Vector) to);
+    return new TransferImpl((${className}) to);
   }
 
-  public void transferTo(${minor.class}Vector target){
+  public void transferTo(${className} target){
     target.clear();
     target.data = data.transferOwnership(target.allocator).buffer;
     target.data.writerIndex(data.writerIndex());
     clear();
   }
 
-  public void splitAndTransferTo(int startIndex, int length, 
${minor.class}Vector target) {
+  public void splitAndTransferTo(int startIndex, int length, ${className} 
target) {
     final int startPoint = startIndex * ${type.width};
     final int sliceLength = length * ${type.width};
     target.clear();
@@ -238,22 +240,18 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements F
   }
 
   private class TransferImpl implements TransferPair{
-    private ${minor.class}Vector to;
+    private ${className} to;
 
     public TransferImpl(String name, BufferAllocator allocator){
-      <#if minor.class == "Decimal">
-      to = new ${minor.class}Vector(name, allocator, precision, scale);
-      <#else>
-      to = new ${minor.class}Vector(name, allocator);
-      </#if>
+      to = new ${className}(name, allocator<#if minor.typeParams??><#list 
minor.typeParams as typeParam>,  
${className}.this.${typeParam.name}</#list></#if>);
     }
 
-    public TransferImpl(${minor.class}Vector to) {
+    public TransferImpl(${className} to) {
       this.to = to;
     }
 
     @Override
-    public ${minor.class}Vector getTo(){
+    public ${className} getTo(){
       return to;
     }
 
@@ -269,11 +267,11 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements F
 
     @Override
     public void copyValueSafe(int fromIndex, int toIndex) {
-      to.copyFromSafe(fromIndex, toIndex, ${minor.class}Vector.this);
+      to.copyFromSafe(fromIndex, toIndex, ${className}.this);
     }
   }
 
-  public void copyFrom(int fromIndex, int thisIndex, ${minor.class}Vector 
from){
+  public void copyFrom(int fromIndex, int thisIndex, ${className} from){
     <#if (type.width > 8 || minor.class == "IntervalDay")>
     from.data.getBytes(fromIndex * ${type.width}, data, thisIndex * 
${type.width}, ${type.width});
     <#else> <#-- type.width <= 8 -->
@@ -283,7 +281,7 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements F
     </#if> <#-- type.width -->
   }
 
-  public void copyFromSafe(int fromIndex, int thisIndex, ${minor.class}Vector 
from){
+  public void copyFromSafe(int fromIndex, int thisIndex, ${className} from){
     while(thisIndex >= getValueCapacity()) {
         reAlloc();
     }

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/MapWriters.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/MapWriters.java 
b/java/vector/src/main/codegen/templates/MapWriters.java
index d3e6de9..05048c5 100644
--- a/java/vector/src/main/codegen/templates/MapWriters.java
+++ b/java/vector/src/main/codegen/templates/MapWriters.java
@@ -56,7 +56,8 @@ public class ${mode}MapWriter extends AbstractFieldWriter {
     </#if>
     this.container = container;
     for (Field child : container.getField().getChildren()) {
-      switch (Types.getMinorTypeForArrowType(child.getType())) {
+      MinorType minorType = Types.getMinorTypeForArrowType(child.getType());
+      switch (minorType) {
       case MAP:
         map(child.getName());
         break;
@@ -71,15 +72,18 @@ public class ${mode}MapWriter extends AbstractFieldWriter {
 <#assign lowerName = minor.class?uncap_first />
 <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
 <#assign upperName = minor.class?upper_case />
-      case ${upperName}:
-        <#if lowerName == "decimal" >
-        Decimal decimal = (Decimal)child.getType();
-        decimal(child.getName(), decimal.getScale(), decimal.getPrecision());
+      case ${upperName}: {
+        <#if minor.typeParams?? >
+        ${minor.arrowType} arrowType = (${minor.arrowType})child.getType();
+        ${lowerName}(child.getName()<#list minor.typeParams as typeParam>, 
arrowType.get${typeParam.name?cap_first}()</#list>);
         <#else>
         ${lowerName}(child.getName());
-       </#if>
+        </#if>
         break;
+      }
 </#list></#list>
+        default:
+          throw new UnsupportedOperationException("Unknown type: " + 
minorType);
       }
     }
   }
@@ -205,7 +209,8 @@ public class ${mode}MapWriter extends AbstractFieldWriter {
   <#assign vectName = capName />
   <#assign vectName = "Nullable${capName}" />
 
-  <#if minor.class?starts_with("Decimal") >
+  <#if minor.typeParams?? >
+  @Override
   public ${minor.class}Writer ${lowerName}(String name) {
     // returns existing writer
     final FieldWriter writer = fields.get(handleCase(name));
@@ -213,7 +218,8 @@ public class ${mode}MapWriter extends AbstractFieldWriter {
     return writer;
   }
 
-  public ${minor.class}Writer ${lowerName}(String name, int scale, int 
precision) {
+  @Override
+  public ${minor.class}Writer ${lowerName}(String name<#list minor.typeParams 
as typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
   <#else>
   @Override
   public ${minor.class}Writer ${lowerName}(String name) {
@@ -223,7 +229,21 @@ public class ${mode}MapWriter extends AbstractFieldWriter {
       ValueVector vector;
       ValueVector currentVector = container.getChild(name);
       ${vectName}Vector v = container.addOrGet(name, 
-          FieldType.nullable(<#if minor.class == "Decimal">new 
Decimal(precision, scale)<#else>MinorType.${upperName}.getType()</#if>),
+          FieldType.nullable(
+          <#if minor.typeParams??>
+            <#if minor.arrowTypeConstructorParams??>
+              <#assign constructorParams = minor.arrowTypeConstructorParams />
+            <#else>
+              <#assign constructorParams = [] />
+              <#list minor.typeParams as typeParam>
+                <#assign constructorParams = constructorParams + [ 
typeParam.name ] />
+              </#list>
+            </#if>    
+            new ${minor.arrowType}(${constructorParams?join(", ")})
+          <#else>
+            MinorType.${upperName}.getType()
+          </#if>
+          ),
           ${vectName}Vector.class);
       writer = new PromotableWriter(v, container, 
getNullableMapWriterFactory());
       vector = v;

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/NullableValueVectors.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/NullableValueVectors.java 
b/java/vector/src/main/codegen/templates/NullableValueVectors.java
index ed2418e..3231c4c 100644
--- a/java/vector/src/main/codegen/templates/NullableValueVectors.java
+++ b/java/vector/src/main/codegen/templates/NullableValueVectors.java
@@ -61,12 +61,27 @@ public final class ${className} extends BaseDataValueVector 
implements <#if type
 
   private final List<BufferBacked> innerVectors;
 
-  <#if minor.class == "Decimal">
-  private final int precision;
-  private final int scale;
+  <#if minor.typeParams??>
+     <#list minor.typeParams as typeParam>
+  private final ${typeParam.type} ${typeParam.name};
+    </#list>
 
-  public ${className}(String name, BufferAllocator allocator, int precision, 
int scale) {
-    this(name, FieldType.nullable(new Decimal(precision, scale)), allocator);
+  /**
+   * Assumes the type is nullable and not dictionary encoded
+   * @param name name of the field
+   * @param allocator allocator to use to resize the vector<#list 
minor.typeParams as typeParam>
+   * @param ${typeParam.name} type parameter ${typeParam.name}</#list>
+   */
+  public ${className}(String name, BufferAllocator allocator<#list 
minor.typeParams as typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
+    <#if minor.arrowTypeConstructorParams??>
+       <#assign constructorParams = minor.arrowTypeConstructorParams />
+    <#else>
+       <#assign constructorParams = [] />
+       <#list minor.typeParams as typeParam>
+         <#assign constructorParams = constructorParams + [ typeParam.name ] />
+      </#list>
+    </#if>
+    this(name, FieldType.nullable(new 
${minor.arrowType}(${constructorParams?join(", ")})), allocator);
   }
   <#else>
   public ${className}(String name, BufferAllocator allocator) {
@@ -76,11 +91,12 @@ public final class ${className} extends BaseDataValueVector 
implements <#if type
 
   public ${className}(String name, FieldType fieldType, BufferAllocator 
allocator) {
     super(name, allocator);
-    <#if minor.class == "Decimal">
-    Decimal decimal = (Decimal)fieldType.getType();
-    this.precision = decimal.getPrecision();
-    this.scale = decimal.getScale();
-    this.values = new ${valuesName}(valuesField, allocator, precision, scale);
+    <#if minor.typeParams??>
+    ${minor.arrowType} arrowType = (${minor.arrowType})fieldType.getType();
+    <#list minor.typeParams as typeParam>
+    this.${typeParam.name} = arrowType.get${typeParam.name?cap_first}();
+    </#list>
+    this.values = new ${valuesName}(valuesField, allocator<#list 
minor.typeParams as typeParam>, ${typeParam.name}</#list>);
     <#else>
     this.values = new ${valuesName}(valuesField, allocator);
     </#if>

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/UnionListWriter.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/UnionListWriter.java 
b/java/vector/src/main/codegen/templates/UnionListWriter.java
index d980830..d019a1e 100644
--- a/java/vector/src/main/codegen/templates/UnionListWriter.java
+++ b/java/vector/src/main/codegen/templates/UnionListWriter.java
@@ -94,7 +94,7 @@ public class UnionListWriter extends AbstractFieldWriter {
   <#assign fields = minor.fields!type.fields />
   <#assign uncappedName = name?uncap_first/>
 
-  <#if !minor.class?starts_with("Decimal")>
+  <#if !minor.typeParams?? >
 
   @Override
   public ${name}Writer <#if uncappedName == 
"int">integer<#else>${uncappedName}</#if>() {

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/UnionWriter.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/UnionWriter.java 
b/java/vector/src/main/codegen/templates/UnionWriter.java
index 880f537..4a7c472 100644
--- a/java/vector/src/main/codegen/templates/UnionWriter.java
+++ b/java/vector/src/main/codegen/templates/UnionWriter.java
@@ -121,7 +121,7 @@ public class UnionWriter extends AbstractFieldWriter 
implements FieldWriter {
       <#assign name = minor.class?cap_first />
       <#assign fields = minor.fields!type.fields />
       <#assign uncappedName = name?uncap_first/>
-      <#if !minor.class?starts_with("Decimal")>
+      <#if !minor.typeParams??>
     case ${name?upper_case}:
       return get${name}Writer();
       </#if>
@@ -136,7 +136,7 @@ public class UnionWriter extends AbstractFieldWriter 
implements FieldWriter {
   <#assign fields = minor.fields!type.fields />
   <#assign uncappedName = name?uncap_first/>
 
-          <#if !minor.class?starts_with("Decimal")>
+          <#if !minor.typeParams?? >
 
   private ${name}Writer ${name?uncap_first}Writer;
 
@@ -206,7 +206,7 @@ public class UnionWriter extends AbstractFieldWriter 
implements FieldWriter {
   <#if lowerName == "int" ><#assign lowerName = "integer" /></#if>
   <#assign upperName = minor.class?upper_case />
   <#assign capName = minor.class?cap_first />
-  <#if !minor.class?starts_with("Decimal")>
+  <#if !minor.typeParams?? >
   @Override
   public ${capName}Writer ${lowerName}(String name) {
     data.getMutator().setType(idx(), MinorType.MAP);

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/codegen/templates/VariableLengthVectors.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/codegen/templates/VariableLengthVectors.java 
b/java/vector/src/main/codegen/templates/VariableLengthVectors.java
index 3d933ad..f13291b 100644
--- a/java/vector/src/main/codegen/templates/VariableLengthVectors.java
+++ b/java/vector/src/main/codegen/templates/VariableLengthVectors.java
@@ -28,6 +28,7 @@ import org.apache.drill.exec.vector.VariableWidthVector;
 <#list type.minor as minor>
 
 <#assign friendlyType = (minor.friendlyType!minor.boxedType!type.boxedType) />
+<#assign className = "${minor.class}Vector" />
 
 <#if type.major == "VarLen">
 <@pp.changeOutputFile 
name="/org/apache/arrow/vector/${minor.class}Vector.java" />
@@ -48,8 +49,8 @@ package org.apache.arrow.vector;
  *
  * NB: this class is automatically generated from ${.template_name} and 
ValueVectorTypes.tdd using FreeMarker.
  */
-public final class ${minor.class}Vector extends BaseDataValueVector implements 
VariableWidthVector{
-  private static final org.slf4j.Logger logger = 
org.slf4j.LoggerFactory.getLogger(${minor.class}Vector.class);
+public final class ${className} extends BaseDataValueVector implements 
VariableWidthVector{
+  private static final org.slf4j.Logger logger = 
org.slf4j.LoggerFactory.getLogger(${className}.class);
 
   private static final int DEFAULT_RECORD_BYTE_COUNT = 8;
   private static final int INITIAL_BYTE_COUNT = 4096 * 
DEFAULT_RECORD_BYTE_COUNT;
@@ -66,22 +67,22 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements V
   private int allocationSizeInBytes = INITIAL_BYTE_COUNT;
   private int allocationMonitor = 0;
 
-  <#if minor.class == "Decimal">
+  <#if minor.typeParams??>
+     <#list minor.typeParams as typeParam>
+  private final ${typeParam.type} ${typeParam.name};
+    </#list>
 
-  private final int precision;
-  private final int scale;
-
-  public ${minor.class}Vector(String name, BufferAllocator allocator, int 
precision, int scale) {
+  public ${className}(String name, BufferAllocator allocator<#list 
minor.typeParams as typeParam>, ${typeParam.type} ${typeParam.name}</#list>) {
     super(name, allocator);
     this.oAccessor = offsetVector.getAccessor();
     this.accessor = new Accessor();
     this.mutator = new Mutator();
-    this.precision = precision;
-    this.scale = scale;
+    <#list minor.typeParams as typeParam>
+    this.${typeParam.name} = ${typeParam.name};
+    </#list>
   }
   <#else>
-
-  public ${minor.class}Vector(String name, BufferAllocator allocator) {
+  public ${className}(String name, BufferAllocator allocator) {
     super(name, allocator);
     this.oAccessor = offsetVector.getAccessor();
     this.accessor = new Accessor();
@@ -188,10 +189,10 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements V
 
   @Override
   public TransferPair makeTransferPair(ValueVector to) {
-    return new TransferImpl((${minor.class}Vector) to);
+    return new TransferImpl((${className}) to);
   }
 
-  public void transferTo(${minor.class}Vector target){
+  public void transferTo(${className} target){
     target.clear();
     this.offsetVector.transferTo(target.offsetVector);
     target.data = data.transferOwnership(target.allocator).buffer;
@@ -199,7 +200,7 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements V
     clear();
   }
 
-  public void splitAndTransferTo(int startIndex, int length, 
${minor.class}Vector target) {
+  public void splitAndTransferTo(int startIndex, int length, ${className} 
target) {
     UInt${type.width}Vector.Accessor offsetVectorAccessor = 
this.offsetVector.getAccessor();
     final int startPoint = offsetVectorAccessor.get(startIndex);
     final int sliceLength = offsetVectorAccessor.get(startIndex + length) - 
startPoint;
@@ -214,7 +215,7 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements V
     target.getMutator().setValueCount(length);
 }
 
-  protected void copyFrom(int fromIndex, int thisIndex, ${minor.class}Vector 
from){
+  protected void copyFrom(int fromIndex, int thisIndex, ${className} from){
     final UInt4Vector.Accessor fromOffsetVectorAccessor = 
from.offsetVector.getAccessor();
     final int start = fromOffsetVectorAccessor.get(fromIndex);
     final int end = fromOffsetVectorAccessor.get(fromIndex + 1);
@@ -225,7 +226,7 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements V
     offsetVector.data.set${(minor.javaType!type.javaType)?cap_first}( 
(thisIndex+1) * ${type.width}, outputStart + len);
   }
 
-  public boolean copyFromSafe(int fromIndex, int thisIndex, 
${minor.class}Vector from){
+  public boolean copyFromSafe(int fromIndex, int thisIndex, ${className} from){
     final UInt${type.width}Vector.Accessor fromOffsetVectorAccessor = 
from.offsetVector.getAccessor();
     final int start = fromOffsetVectorAccessor.get(fromIndex);
     final int end =   fromOffsetVectorAccessor.get(fromIndex + 1);
@@ -242,22 +243,18 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements V
   }
 
   private class TransferImpl implements TransferPair{
-    ${minor.class}Vector to;
+    ${className} to;
 
     public TransferImpl(String name, BufferAllocator allocator){
-      <#if minor.class == "Decimal">
-      to = new ${minor.class}Vector(name, allocator, precision, scale);
-      <#else>
-      to = new ${minor.class}Vector(name, allocator);
-      </#if>
+      to = new ${className}(name, allocator<#if minor.typeParams??><#list 
minor.typeParams as typeParam>,  
${className}.this.${typeParam.name}</#list></#if>);
     }
 
-    public TransferImpl(${minor.class}Vector to){
+    public TransferImpl(${className} to){
       this.to = to;
     }
 
     @Override
-    public ${minor.class}Vector getTo(){
+    public ${className} getTo(){
       return to;
     }
 
@@ -273,7 +270,7 @@ public final class ${minor.class}Vector extends 
BaseDataValueVector implements V
 
     @Override
     public void copyValueSafe(int fromIndex, int toIndex) {
-      to.copyFromSafe(fromIndex, toIndex, ${minor.class}Vector.this);
+      to.copyFromSafe(fromIndex, toIndex, ${className}.this);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/java/org/apache/arrow/vector/file/json/JsonFileReader.java
----------------------------------------------------------------------
diff --git 
a/java/vector/src/main/java/org/apache/arrow/vector/file/json/JsonFileReader.java
 
b/java/vector/src/main/java/org/apache/arrow/vector/file/json/JsonFileReader.java
index 21aa037..3ef1484 100644
--- 
a/java/vector/src/main/java/org/apache/arrow/vector/file/json/JsonFileReader.java
+++ 
b/java/vector/src/main/java/org/apache/arrow/vector/file/json/JsonFileReader.java
@@ -43,9 +43,13 @@ import org.apache.arrow.vector.TimeMicroVector;
 import org.apache.arrow.vector.TimeMilliVector;
 import org.apache.arrow.vector.TimeNanoVector;
 import org.apache.arrow.vector.TimeSecVector;
+import org.apache.arrow.vector.TimeStampMicroTZVector;
 import org.apache.arrow.vector.TimeStampMicroVector;
+import org.apache.arrow.vector.TimeStampMilliTZVector;
 import org.apache.arrow.vector.TimeStampMilliVector;
+import org.apache.arrow.vector.TimeStampNanoTZVector;
 import org.apache.arrow.vector.TimeStampNanoVector;
+import org.apache.arrow.vector.TimeStampSecTZVector;
 import org.apache.arrow.vector.TimeStampSecVector;
 import org.apache.arrow.vector.TinyIntVector;
 import org.apache.arrow.vector.UInt1Vector;
@@ -61,14 +65,14 @@ import org.apache.arrow.vector.complex.NullableMapVector;
 import org.apache.arrow.vector.schema.ArrowVectorType;
 import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.Schema;
+import org.apache.commons.codec.DecoderException;
+import org.apache.commons.codec.binary.Hex;
 
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.core.JsonParser;
 import com.fasterxml.jackson.core.JsonToken;
 import com.fasterxml.jackson.databind.MappingJsonFactory;
 import com.google.common.base.Objects;
-import org.apache.commons.codec.DecoderException;
-import org.apache.commons.codec.binary.Hex;
 
 public class JsonFileReader implements AutoCloseable {
   private final File inputFile;
@@ -278,6 +282,18 @@ public class JsonFileReader implements AutoCloseable {
     case TIMESTAMPNANO:
       ((TimeStampNanoVector)valueVector).getMutator().set(i, 
parser.readValueAs(Long.class));
       break;
+    case TIMESTAMPSECTZ:
+      ((TimeStampSecTZVector)valueVector).getMutator().set(i, 
parser.readValueAs(Long.class));
+      break;
+    case TIMESTAMPMILLITZ:
+      ((TimeStampMilliTZVector)valueVector).getMutator().set(i, 
parser.readValueAs(Long.class));
+      break;
+    case TIMESTAMPMICROTZ:
+      ((TimeStampMicroTZVector)valueVector).getMutator().set(i, 
parser.readValueAs(Long.class));
+      break;
+    case TIMESTAMPNANOTZ:
+      ((TimeStampNanoTZVector)valueVector).getMutator().set(i, 
parser.readValueAs(Long.class));
+      break;
     default:
       throw new UnsupportedOperationException("minor type: " + 
valueVector.getMinorType());
     }

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/main/java/org/apache/arrow/vector/types/Types.java
----------------------------------------------------------------------
diff --git a/java/vector/src/main/java/org/apache/arrow/vector/types/Types.java 
b/java/vector/src/main/java/org/apache/arrow/vector/types/Types.java
index 2a0e47b..6591a4b 100644
--- a/java/vector/src/main/java/org/apache/arrow/vector/types/Types.java
+++ b/java/vector/src/main/java/org/apache/arrow/vector/types/Types.java
@@ -38,9 +38,13 @@ import org.apache.arrow.vector.NullableTimeMicroVector;
 import org.apache.arrow.vector.NullableTimeMilliVector;
 import org.apache.arrow.vector.NullableTimeNanoVector;
 import org.apache.arrow.vector.NullableTimeSecVector;
+import org.apache.arrow.vector.NullableTimeStampMicroTZVector;
 import org.apache.arrow.vector.NullableTimeStampMicroVector;
+import org.apache.arrow.vector.NullableTimeStampMilliTZVector;
 import org.apache.arrow.vector.NullableTimeStampMilliVector;
+import org.apache.arrow.vector.NullableTimeStampNanoTZVector;
 import org.apache.arrow.vector.NullableTimeStampNanoVector;
+import org.apache.arrow.vector.NullableTimeStampSecTZVector;
 import org.apache.arrow.vector.NullableTimeStampSecVector;
 import org.apache.arrow.vector.NullableTinyIntVector;
 import org.apache.arrow.vector.NullableUInt1Vector;
@@ -71,9 +75,13 @@ import 
org.apache.arrow.vector.complex.impl.TimeMicroWriterImpl;
 import org.apache.arrow.vector.complex.impl.TimeMilliWriterImpl;
 import org.apache.arrow.vector.complex.impl.TimeNanoWriterImpl;
 import org.apache.arrow.vector.complex.impl.TimeSecWriterImpl;
+import org.apache.arrow.vector.complex.impl.TimeStampMicroTZWriterImpl;
 import org.apache.arrow.vector.complex.impl.TimeStampMicroWriterImpl;
+import org.apache.arrow.vector.complex.impl.TimeStampMilliTZWriterImpl;
 import org.apache.arrow.vector.complex.impl.TimeStampMilliWriterImpl;
+import org.apache.arrow.vector.complex.impl.TimeStampNanoTZWriterImpl;
 import org.apache.arrow.vector.complex.impl.TimeStampNanoWriterImpl;
+import org.apache.arrow.vector.complex.impl.TimeStampSecTZWriterImpl;
 import org.apache.arrow.vector.complex.impl.TimeStampSecWriterImpl;
 import org.apache.arrow.vector.complex.impl.TinyIntWriterImpl;
 import org.apache.arrow.vector.complex.impl.UInt1WriterImpl;
@@ -369,11 +377,6 @@ public class Types {
     },
     DECIMAL(null) {
       @Override
-      public ArrowType getType() {
-        throw new UnsupportedOperationException("Cannot get simple type for 
Decimal type");
-      }
-
-      @Override
       public FieldVector getNewVector(String name, FieldType fieldType, 
BufferAllocator allocator, CallBack schemaChangeCallback) {
         return new NullableDecimalVector(name, fieldType, allocator);
       }
@@ -440,11 +443,6 @@ public class Types {
     },
     FIXED_SIZE_LIST(null) {
       @Override
-      public ArrowType getType() {
-        throw new UnsupportedOperationException("Cannot get simple type for 
FixedSizeList type");
-      }
-
-      @Override
       public FieldVector getNewVector(String name, FieldType fieldType, 
BufferAllocator allocator, CallBack schemaChangeCallback) {
         return new FixedSizeListVector(name, allocator, fieldType, 
schemaChangeCallback);
       }
@@ -467,6 +465,50 @@ public class Types {
       public FieldWriter getNewFieldWriter(ValueVector vector) {
         return new UnionWriter((UnionVector) vector);
       }
+    },
+    TIMESTAMPSECTZ(null) {
+      @Override
+      public FieldVector getNewVector(String name, FieldType fieldType, 
BufferAllocator allocator, CallBack schemaChangeCallback) {
+        return new NullableTimeStampSecTZVector(name, fieldType, allocator);
+      }
+
+      @Override
+      public FieldWriter getNewFieldWriter(ValueVector vector) {
+        return new TimeStampSecTZWriterImpl((NullableTimeStampSecTZVector) 
vector);
+      }
+    },
+    TIMESTAMPMILLITZ(null) {
+      @Override
+      public FieldVector getNewVector(String name, FieldType fieldType, 
BufferAllocator allocator, CallBack schemaChangeCallback) {
+        return new NullableTimeStampMilliTZVector(name, fieldType, allocator);
+      }
+
+      @Override
+      public FieldWriter getNewFieldWriter(ValueVector vector) {
+        return new TimeStampMilliTZWriterImpl((NullableTimeStampMilliTZVector) 
vector);
+      }
+    },
+    TIMESTAMPMICROTZ(null) {
+      @Override
+      public FieldVector getNewVector(String name, FieldType fieldType, 
BufferAllocator allocator, CallBack schemaChangeCallback) {
+        return new NullableTimeStampMicroTZVector(name, fieldType, allocator);
+      }
+
+      @Override
+      public FieldWriter getNewFieldWriter(ValueVector vector) {
+        return new TimeStampMicroTZWriterImpl((NullableTimeStampMicroTZVector) 
vector);
+      }
+    },
+    TIMESTAMPNANOTZ(null) {
+      @Override
+      public FieldVector getNewVector(String name, FieldType fieldType, 
BufferAllocator allocator, CallBack schemaChangeCallback) {
+        return new NullableTimeStampNanoTZVector(name, fieldType, allocator);
+      }
+
+      @Override
+      public FieldWriter getNewFieldWriter(ValueVector vector) {
+        return new TimeStampNanoTZWriterImpl((NullableTimeStampNanoTZVector) 
vector);
+      }
     };
 
     private final ArrowType type;
@@ -475,7 +517,10 @@ public class Types {
       this.type = type;
     }
 
-    public ArrowType getType() {
+    public final ArrowType getType() {
+      if (type == null) {
+        throw new UnsupportedOperationException("Cannot get simple type for 
type " + name());
+      }
       return type;
     }
 
@@ -579,18 +624,16 @@ public class Types {
       }
 
       @Override public MinorType visit(Timestamp type) {
-        if (type.getTimezone() != null) {
-          throw new IllegalArgumentException("only timezone-less timestamps 
are supported for now: " + type);
-        }
+        String tz = type.getTimezone();
         switch (type.getUnit()) {
           case SECOND:
-            return MinorType.TIMESTAMPSEC;
+            return tz == null ? MinorType.TIMESTAMPSEC : 
MinorType.TIMESTAMPSECTZ;
           case MILLISECOND:
-            return MinorType.TIMESTAMPMILLI;
+            return tz == null ? MinorType.TIMESTAMPMILLI : 
MinorType.TIMESTAMPMILLITZ;
           case MICROSECOND:
-            return MinorType.TIMESTAMPMICRO;
+            return tz == null ? MinorType.TIMESTAMPMICRO : 
MinorType.TIMESTAMPMICROTZ;
           case NANOSECOND:
-            return MinorType.TIMESTAMPNANO;
+            return tz == null ? MinorType.TIMESTAMPNANO : 
MinorType.TIMESTAMPNANOTZ;
           default:
             throw new IllegalArgumentException("unknown unit: " + type);
         }

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java
----------------------------------------------------------------------
diff --git 
a/java/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java
 
b/java/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java
index 1613936..ede8d65 100644
--- 
a/java/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java
+++ 
b/java/vector/src/test/java/org/apache/arrow/vector/complex/writer/TestComplexWriter.java
@@ -42,15 +42,18 @@ import org.apache.arrow.vector.complex.reader.FieldReader;
 import org.apache.arrow.vector.complex.writer.BaseWriter.ComplexWriter;
 import org.apache.arrow.vector.complex.writer.BaseWriter.ListWriter;
 import org.apache.arrow.vector.complex.writer.BaseWriter.MapWriter;
+import org.apache.arrow.vector.holders.NullableTimeStampNanoTZHolder;
 import org.apache.arrow.vector.types.pojo.ArrowType;
 import org.apache.arrow.vector.types.pojo.ArrowType.ArrowTypeID;
 import org.apache.arrow.vector.types.pojo.ArrowType.Int;
 import org.apache.arrow.vector.types.pojo.ArrowType.Struct;
+import org.apache.arrow.vector.types.pojo.ArrowType.Timestamp;
 import org.apache.arrow.vector.types.pojo.ArrowType.Union;
 import org.apache.arrow.vector.types.pojo.ArrowType.Utf8;
 import org.apache.arrow.vector.types.pojo.Field;
 import org.apache.arrow.vector.types.pojo.FieldType;
 import org.apache.arrow.vector.util.CallBack;
+import org.apache.arrow.vector.util.DateUtility;
 import org.apache.arrow.vector.util.JsonStringArrayList;
 import org.apache.arrow.vector.util.JsonStringHashMap;
 import org.apache.arrow.vector.util.Text;
@@ -592,85 +595,198 @@ public class TestComplexWriter {
   }
 
   @Test
-  public void timeStampWriters() throws Exception {
+  public void timeStampSecWriter() throws Exception {
     // test values
-    final long expectedNanos = 981173106123456789L;
-    final long expectedMicros = 981173106123456L;
-    final long expectedMillis = 981173106123L;
     final long expectedSecs = 981173106L;
     final LocalDateTime expectedSecDateTime = new LocalDateTime(2001, 2, 3, 4, 
5, 6, 0);
+
+    // write
+    MapVector parent = new MapVector("parent", allocator, null);
+    ComplexWriter writer = new ComplexWriterImpl("root", parent);
+    MapWriter rootWriter = writer.rootAsMap();
+
+    {
+      TimeStampSecWriter timeStampSecWriter = rootWriter.timeStampSec("sec");
+      timeStampSecWriter.setPosition(0);
+      timeStampSecWriter.writeTimeStampSec(expectedSecs);
+    }
+    {
+      TimeStampSecTZWriter timeStampSecTZWriter = 
rootWriter.timeStampSecTZ("secTZ", "UTC");
+      timeStampSecTZWriter.setPosition(1);
+      timeStampSecTZWriter.writeTimeStampSecTZ(expectedSecs);
+    }
+    // schema
+    List<Field> children = 
parent.getField().getChildren().get(0).getChildren();
+    checkTimestampField(children.get(0), "sec");
+    checkTimestampTZField(children.get(1), "secTZ", "UTC");
+
+    // read
+    MapReader rootReader = new SingleMapReaderImpl(parent).reader("root");
+    {
+      FieldReader secReader = rootReader.reader("sec");
+      secReader.setPosition(0);
+      LocalDateTime secDateTime = secReader.readLocalDateTime();
+      Assert.assertEquals(expectedSecDateTime, secDateTime);
+      long secLong = secReader.readLong();
+      Assert.assertEquals(expectedSecs, secLong);
+    }
+    {
+      FieldReader secTZReader = rootReader.reader("secTZ");
+      secTZReader.setPosition(1);
+      long secTZLong = secTZReader.readLong();
+      Assert.assertEquals(expectedSecs, secTZLong);
+    }
+  }
+
+  @Test
+  public void timeStampMilliWriters() throws Exception {
+    // test values
+    final long expectedMillis = 981173106123L;
     final LocalDateTime expectedMilliDateTime = new LocalDateTime(2001, 2, 3, 
4, 5, 6, 123);
-    final LocalDateTime expectedMicroDateTime = expectedMilliDateTime;
-    final LocalDateTime expectedNanoDateTime = expectedMilliDateTime;
 
     // write
     MapVector parent = MapVector.empty("parent", allocator);
     ComplexWriter writer = new ComplexWriterImpl("root", parent);
     MapWriter rootWriter = writer.rootAsMap();
+    {
+      TimeStampMilliWriter timeStampWriter = 
rootWriter.timeStampMilli("milli");
+      timeStampWriter.setPosition(0);
+      timeStampWriter.writeTimeStampMilli(expectedMillis);
+    }
+    String tz = DateUtility.getTimeZone(10);
+    {
+      TimeStampMilliTZWriter timeStampTZWriter = 
rootWriter.timeStampMilliTZ("milliTZ", tz);
+      timeStampTZWriter.setPosition(0);
+      timeStampTZWriter.writeTimeStampMilliTZ(expectedMillis);
+    }
+    // schema
+    List<Field> children = 
parent.getField().getChildren().get(0).getChildren();
+    checkTimestampField(children.get(0), "milli");
+    checkTimestampTZField(children.get(1), "milliTZ", tz);
+
+    // read
+    MapReader rootReader = new SingleMapReaderImpl(parent).reader("root");
+
+    {
+      FieldReader milliReader = rootReader.reader("milli");
+      milliReader.setPosition(0);
+      LocalDateTime milliDateTime = milliReader.readLocalDateTime();
+      Assert.assertEquals(expectedMilliDateTime, milliDateTime);
+      long milliLong = milliReader.readLong();
+      Assert.assertEquals(expectedMillis, milliLong);
+    }
+    {
+      FieldReader milliTZReader = rootReader.reader("milliTZ");
+      milliTZReader.setPosition(0);
+      long milliTZLong = milliTZReader.readLong();
+      Assert.assertEquals(expectedMillis, milliTZLong);
+    }
 
-    TimeStampSecWriter timeStampSecWriter = rootWriter.timeStampSec("sec");
-    timeStampSecWriter.setPosition(0);
-    timeStampSecWriter.writeTimeStampSec(expectedSecs);
+  }
 
-    TimeStampMilliWriter timeStampWriter = rootWriter.timeStampMilli("milli");
-    timeStampWriter.setPosition(1);
-    timeStampWriter.writeTimeStampMilli(expectedMillis);
+  private void checkTimestampField(Field field, String name) {
+    Assert.assertEquals(name, field.getName());
+    Assert.assertEquals(ArrowType.Timestamp.TYPE_TYPE, 
field.getType().getTypeID());
+  }
 
-    TimeStampMicroWriter timeStampMicroWriter = 
rootWriter.timeStampMicro("micro");
-    timeStampMicroWriter.setPosition(2);
-    timeStampMicroWriter.writeTimeStampMicro(expectedMicros);
+  private void checkTimestampTZField(Field field, String name, String tz) {
+    checkTimestampField(field, name);
+    Assert.assertEquals(tz, ((Timestamp)field.getType()).getTimezone());
+  }
 
-    TimeStampNanoWriter timeStampNanoWriter = rootWriter.timeStampNano("nano");
-    timeStampNanoWriter.setPosition(3);
-    timeStampNanoWriter.writeTimeStampNano(expectedNanos);
+  @Test
+  public void timeStampMicroWriters() throws Exception {
+    // test values
+    final long expectedMicros = 981173106123456L;
+    final LocalDateTime expectedMicroDateTime = new LocalDateTime(2001, 2, 3, 
4, 5, 6, 123);
+
+    // write
+    MapVector parent = new MapVector("parent", allocator, null);
+    ComplexWriter writer = new ComplexWriterImpl("root", parent);
+    MapWriter rootWriter = writer.rootAsMap();
+
+    {
+      TimeStampMicroWriter timeStampMicroWriter = 
rootWriter.timeStampMicro("micro");
+      timeStampMicroWriter.setPosition(0);
+      timeStampMicroWriter.writeTimeStampMicro(expectedMicros);
+    }
+    String tz = DateUtility.getTimeZone(5);
+    {
+      TimeStampMicroTZWriter timeStampMicroWriter = 
rootWriter.timeStampMicroTZ("microTZ", tz);
+      timeStampMicroWriter.setPosition(1);
+      timeStampMicroWriter.writeTimeStampMicroTZ(expectedMicros);
+    }
 
     // schema
-    Field secField = 
parent.getField().getChildren().get(0).getChildren().get(0);
-    Assert.assertEquals("sec", secField.getName());
-    Assert.assertEquals(ArrowType.Timestamp.TYPE_TYPE, 
secField.getType().getTypeID());
+    List<Field> children = 
parent.getField().getChildren().get(0).getChildren();
+    checkTimestampField(children.get(0), "micro");
+    checkTimestampTZField(children.get(1), "microTZ", tz);
+
+    // read
+    MapReader rootReader = new SingleMapReaderImpl(parent).reader("root");
+    {
+      FieldReader microReader = rootReader.reader("micro");
+      microReader.setPosition(0);
+      LocalDateTime microDateTime = microReader.readLocalDateTime();
+      Assert.assertEquals(expectedMicroDateTime, microDateTime);
+      long microLong = microReader.readLong();
+      Assert.assertEquals(expectedMicros, microLong);
+    }
+    {
+      FieldReader microReader = rootReader.reader("microTZ");
+      microReader.setPosition(1);
+      long microLong = microReader.readLong();
+      Assert.assertEquals(expectedMicros, microLong);
+    }
 
-    Field milliField = 
parent.getField().getChildren().get(0).getChildren().get(1);
-    Assert.assertEquals("milli", milliField.getName());
-    Assert.assertEquals(ArrowType.Timestamp.TYPE_TYPE, 
milliField.getType().getTypeID());
+  }
 
-    Field microField = 
parent.getField().getChildren().get(0).getChildren().get(2);
-    Assert.assertEquals("micro", microField.getName());
-    Assert.assertEquals(ArrowType.Timestamp.TYPE_TYPE, 
microField.getType().getTypeID());
+  @Test
+  public void timeStampNanoWriters() throws Exception {
+    // test values
+    final long expectedNanos = 981173106123456789L;
+    final LocalDateTime expectedNanoDateTime = new LocalDateTime(2001, 2, 3, 
4, 5, 6, 123);
 
-    Field nanoField = 
parent.getField().getChildren().get(0).getChildren().get(3);
-    Assert.assertEquals("nano", nanoField.getName());
-    Assert.assertEquals(ArrowType.Timestamp.TYPE_TYPE, 
nanoField.getType().getTypeID());
+    // write
+    MapVector parent = new MapVector("parent", allocator, null);
+    ComplexWriter writer = new ComplexWriterImpl("root", parent);
+    MapWriter rootWriter = writer.rootAsMap();
 
+    {
+      TimeStampNanoWriter timeStampNanoWriter = 
rootWriter.timeStampNano("nano");
+      timeStampNanoWriter.setPosition(0);
+      timeStampNanoWriter.writeTimeStampNano(expectedNanos);
+    }
+    String tz = DateUtility.getTimeZone(3);
+    {
+      TimeStampNanoTZWriter timeStampNanoWriter = 
rootWriter.timeStampNanoTZ("nanoTZ", tz);
+      timeStampNanoWriter.setPosition(0);
+      timeStampNanoWriter.writeTimeStampNanoTZ(expectedNanos);
+    }
+    // schema
+    List<Field> children = 
parent.getField().getChildren().get(0).getChildren();
+    checkTimestampField(children.get(0), "nano");
+    checkTimestampTZField(children.get(1), "nanoTZ", tz);
     // read
     MapReader rootReader = new SingleMapReaderImpl(parent).reader("root");
 
-    FieldReader secReader = rootReader.reader("sec");
-    secReader.setPosition(0);
-    LocalDateTime secDateTime = secReader.readLocalDateTime();
-    Assert.assertEquals(expectedSecDateTime, secDateTime);
-    long secLong = secReader.readLong();
-    Assert.assertEquals(expectedSecs, secLong);
-
-    FieldReader milliReader = rootReader.reader("milli");
-    milliReader.setPosition(1);
-    LocalDateTime milliDateTime = milliReader.readLocalDateTime();
-    Assert.assertEquals(expectedMilliDateTime, milliDateTime);
-    long milliLong = milliReader.readLong();
-    Assert.assertEquals(expectedMillis, milliLong);
-
-    FieldReader microReader = rootReader.reader("micro");
-    microReader.setPosition(2);
-    LocalDateTime microDateTime = microReader.readLocalDateTime();
-    Assert.assertEquals(expectedMicroDateTime, microDateTime);
-    long microLong = microReader.readLong();
-    Assert.assertEquals(expectedMicros, microLong);
-
-    FieldReader nanoReader = rootReader.reader("nano");
-    nanoReader.setPosition(3);
-    LocalDateTime nanoDateTime = nanoReader.readLocalDateTime();
-    Assert.assertEquals(expectedNanoDateTime, nanoDateTime);
-    long nanoLong = nanoReader.readLong();
-    Assert.assertEquals(expectedNanos, nanoLong);
+    {
+      FieldReader nanoReader = rootReader.reader("nano");
+      nanoReader.setPosition(0);
+      LocalDateTime nanoDateTime = nanoReader.readLocalDateTime();
+      Assert.assertEquals(expectedNanoDateTime, nanoDateTime);
+      long nanoLong = nanoReader.readLong();
+      Assert.assertEquals(expectedNanos, nanoLong);
+    }
+    {
+      FieldReader nanoReader = rootReader.reader("nanoTZ");
+      nanoReader.setPosition(0);
+      long nanoLong = nanoReader.readLong();
+      Assert.assertEquals(expectedNanos, nanoLong);
+      NullableTimeStampNanoTZHolder h = new NullableTimeStampNanoTZHolder();
+      nanoReader.read(h);
+      Assert.assertEquals(expectedNanos, h.value);
+    }
   }
 
   @Test
@@ -710,4 +826,4 @@ public class TestComplexWriter {
     innerMap = (JsonStringHashMap<?,?>) object.get(3);
     assertEquals(2, innerMap.get("a"));
   }
-}
\ No newline at end of file
+}

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/test/java/org/apache/arrow/vector/file/BaseFileTest.java
----------------------------------------------------------------------
diff --git 
a/java/vector/src/test/java/org/apache/arrow/vector/file/BaseFileTest.java 
b/java/vector/src/test/java/org/apache/arrow/vector/file/BaseFileTest.java
index 5cc36a3..63027e6 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/file/BaseFileTest.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/file/BaseFileTest.java
@@ -37,8 +37,10 @@ import org.apache.arrow.vector.complex.writer.BigIntWriter;
 import org.apache.arrow.vector.complex.writer.DateMilliWriter;
 import org.apache.arrow.vector.complex.writer.IntWriter;
 import org.apache.arrow.vector.complex.writer.TimeMilliWriter;
+import org.apache.arrow.vector.complex.writer.TimeStampMilliTZWriter;
 import org.apache.arrow.vector.complex.writer.TimeStampMilliWriter;
 import org.apache.arrow.vector.holders.NullableTimeStampMilliHolder;
+import org.apache.arrow.vector.util.DateUtility;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDateTime;
 import org.junit.After;
@@ -155,18 +157,21 @@ public class BaseFileTest {
     DateMilliWriter dateWriter = rootWriter.dateMilli("date");
     TimeMilliWriter timeWriter = rootWriter.timeMilli("time");
     TimeStampMilliWriter timeStampMilliWriter = 
rootWriter.timeStampMilli("timestamp-milli");
+    TimeStampMilliTZWriter timeStampMilliTZWriter = 
rootWriter.timeStampMilliTZ("timestamp-milliTZ", "Europe/Paris");
     for (int i = 0; i < count; i++) {
       LocalDateTime dt = makeDateTimeFromCount(i);
       // Number of days in milliseconds since epoch, stored as 64-bit integer, 
only date part is used
       dateWriter.setPosition(i);
-      long dateLong = 
org.apache.arrow.vector.util.DateUtility.toMillis(dt.minusMillis(dt.getMillisOfDay()));
+      long dateLong = 
DateUtility.toMillis(dt.minusMillis(dt.getMillisOfDay()));
       dateWriter.writeDateMilli(dateLong);
       // Time is a value in milliseconds since midnight, stored as 32-bit 
integer
       timeWriter.setPosition(i);
       timeWriter.writeTimeMilli(dt.getMillisOfDay());
       // Timestamp is milliseconds since the epoch, stored as 64-bit integer
       timeStampMilliWriter.setPosition(i);
-      
timeStampMilliWriter.writeTimeStampMilli(org.apache.arrow.vector.util.DateUtility.toMillis(dt));
+      timeStampMilliWriter.writeTimeStampMilli(DateUtility.toMillis(dt));
+      timeStampMilliTZWriter.setPosition(i);
+      timeStampMilliTZWriter.writeTimeStampMilliTZ(DateUtility.toMillis(dt));
     }
     writer.setValueCount(count);
   }
@@ -178,11 +183,13 @@ public class BaseFileTest {
       long dateVal = 
((NullableDateMilliVector)root.getVector("date")).getAccessor().get(i);
       LocalDateTime dt = makeDateTimeFromCount(i);
       LocalDateTime dateExpected = dt.minusMillis(dt.getMillisOfDay());
-      
Assert.assertEquals(org.apache.arrow.vector.util.DateUtility.toMillis(dateExpected),
 dateVal);
+      Assert.assertEquals(DateUtility.toMillis(dateExpected), dateVal);
       long timeVal = 
((NullableTimeMilliVector)root.getVector("time")).getAccessor().get(i);
       Assert.assertEquals(dt.getMillisOfDay(), timeVal);
       Object timestampMilliVal = 
root.getVector("timestamp-milli").getAccessor().getObject(i);
       Assert.assertEquals(dt, timestampMilliVal);
+      Object timestampMilliTZVal = 
root.getVector("timestamp-milliTZ").getAccessor().getObject(i);
+      Assert.assertEquals(DateUtility.toMillis(dt), timestampMilliTZVal);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/arrow/blob/681afabb/java/vector/src/test/java/org/apache/arrow/vector/pojo/TestConvert.java
----------------------------------------------------------------------
diff --git 
a/java/vector/src/test/java/org/apache/arrow/vector/pojo/TestConvert.java 
b/java/vector/src/test/java/org/apache/arrow/vector/pojo/TestConvert.java
index 64f7970..e2dae29 100644
--- a/java/vector/src/test/java/org/apache/arrow/vector/pojo/TestConvert.java
+++ b/java/vector/src/test/java/org/apache/arrow/vector/pojo/TestConvert.java
@@ -83,7 +83,8 @@ public class TestConvert {
         )));
     childrenBuilder.add(new Field("child5", FieldType.nullable(new 
Union(UnionMode.Sparse, new int[] { MinorType.TIMESTAMPMILLI.ordinal(), 
MinorType.FLOAT8.ordinal() } )), ImmutableList.<Field>of(
         new Field("child5.1", FieldType.nullable(new 
Timestamp(TimeUnit.MILLISECOND, null)), null),
-        new Field("child5.2", FieldType.nullable(new FloatingPoint(DOUBLE)), 
ImmutableList.<Field>of())
+        new Field("child5.2", FieldType.nullable(new FloatingPoint(DOUBLE)), 
ImmutableList.<Field>of()),
+        new Field("child5.3", true, new Timestamp(TimeUnit.MILLISECOND, 
"UTC"), null)
         )));
     Schema initialSchema = new Schema(childrenBuilder.build());
     run(initialSchema);

Reply via email to