embulk-filter-timestamp_format 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/CHANGELOG.md +7 -0
- data/README.md +46 -1
- data/bench/config_java.yml +14 -0
- data/bench/config_jruby.yml +14 -0
- data/bench/gen_dummy.rb +5 -0
- data/build.gradle +1 -1
- data/example/double.csv +2 -0
- data/example/double.yml +20 -0
- data/example/{json_example.jsonl → example.jsonl} +0 -0
- data/example/example.yml +4 -12
- data/example/example2.csv +2 -0
- data/example/example2.yml +14 -0
- data/example/json_double.jsonl +1 -0
- data/example/json_double.yml +14 -0
- data/example/json_long.jsonl +1 -0
- data/example/json_long.yml +14 -0
- data/example/json_string.jsonl +2 -0
- data/example/json_string.yml +14 -0
- data/example/long.csv +1 -0
- data/example/long.yml +20 -0
- data/example/string.csv +4 -0
- data/example/{string_example.yml → string.yml} +6 -5
- data/example/string_java.yml +23 -0
- data/example/timestamp.csv +2 -0
- data/example/{timestamp_example.yml → timestamp.yml} +4 -4
- data/src/main/java/org/embulk/filter/timestamp_format/ColumnCaster.java +107 -14
- data/src/main/java/org/embulk/filter/timestamp_format/ColumnVisitorImpl.java +104 -33
- data/src/main/java/org/embulk/filter/timestamp_format/JsonCaster.java +61 -4
- data/src/main/java/org/embulk/filter/timestamp_format/JsonVisitor.java +8 -0
- data/src/main/java/org/embulk/filter/timestamp_format/TimestampFormatFilterPlugin.java +28 -17
- data/src/main/java/org/embulk/filter/timestamp_format/TimestampFormatter.java +36 -5
- data/src/main/java/org/embulk/filter/timestamp_format/TimestampParser.java +57 -26
- data/src/main/java/org/embulk/filter/timestamp_format/TimestampUnit.java +112 -0
- data/src/main/java/org/embulk/filter/timestamp_format/TimestampUnitDeserializer.java +54 -0
- data/src/main/java/org/embulk/filter/timestamp_format/cast/DoubleCast.java +32 -0
- data/src/main/java/org/embulk/filter/timestamp_format/cast/LongCast.java +32 -0
- data/src/main/java/org/embulk/filter/timestamp_format/cast/StringCast.java +20 -4
- data/src/main/java/org/embulk/filter/timestamp_format/cast/TimestampCast.java +5 -6
- data/src/test/java/org/embulk/filter/timestamp_format/TestTimestampUnit.java +192 -0
- metadata +29 -8
- data/example/json_example.yml +0 -14
- data/src/test/java/org/embulk/filter/TestTimestampFormatFilterPlugin.java +0 -5
@@ -4,6 +4,7 @@ import org.embulk.spi.DataException;
|
|
4
4
|
import org.embulk.spi.PageReader;
|
5
5
|
import org.embulk.spi.Schema;
|
6
6
|
|
7
|
+
import org.embulk.filter.timestamp_format.TimestampFormatFilterPlugin.ColumnConfig;
|
7
8
|
import org.embulk.filter.timestamp_format.TimestampFormatFilterPlugin.PluginTask;
|
8
9
|
|
9
10
|
import org.embulk.spi.Column;
|
@@ -13,6 +14,7 @@ import org.embulk.spi.PageBuilder;
|
|
13
14
|
import org.slf4j.Logger;
|
14
15
|
|
15
16
|
import java.util.HashMap;
|
17
|
+
import java.util.HashSet;
|
16
18
|
|
17
19
|
public class ColumnVisitorImpl
|
18
20
|
implements ColumnVisitor
|
@@ -23,6 +25,7 @@ public class ColumnVisitorImpl
|
|
23
25
|
private final Schema outputSchema;
|
24
26
|
private final PageReader pageReader;
|
25
27
|
private final PageBuilder pageBuilder;
|
28
|
+
private final HashSet<String> shouldCastSet = new HashSet<>();
|
26
29
|
private final HashMap<String, Column> outputColumnMap = new HashMap<>();
|
27
30
|
private final ColumnCaster columnCaster;
|
28
31
|
|
@@ -35,10 +38,30 @@ public class ColumnVisitorImpl
|
|
35
38
|
this.pageReader = pageReader;
|
36
39
|
this.pageBuilder = pageBuilder;
|
37
40
|
|
41
|
+
buildShouldCastSet();
|
38
42
|
buildOutputColumnMap();
|
39
43
|
this.columnCaster = new ColumnCaster(task, inputSchema, outputSchema, pageReader, pageBuilder);
|
40
44
|
}
|
41
45
|
|
46
|
+
private void buildShouldCastSet()
|
47
|
+
{
|
48
|
+
// columnName => Boolean to avoid unnecessary cast
|
49
|
+
for (ColumnConfig columnConfig : task.getColumns()) {
|
50
|
+
String name = columnConfig.getName();
|
51
|
+
if (name.startsWith("$.")) {
|
52
|
+
String firstName = name.split("\\.", 3)[1]; // check only top level column name
|
53
|
+
shouldCastSet.add(firstName);
|
54
|
+
continue;
|
55
|
+
}
|
56
|
+
shouldCastSet.add(name);
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
private boolean shouldCast(String name)
|
61
|
+
{
|
62
|
+
return shouldCastSet.contains(name);
|
63
|
+
}
|
64
|
+
|
42
65
|
private void buildOutputColumnMap()
|
43
66
|
{
|
44
67
|
// columnName => outputColumn
|
@@ -88,67 +111,115 @@ public class ColumnVisitorImpl
|
|
88
111
|
@Override
|
89
112
|
public void longColumn(final Column inputColumn)
|
90
113
|
{
|
91
|
-
|
92
|
-
|
114
|
+
String name = inputColumn.getName();
|
115
|
+
if (! shouldCast(name)){
|
116
|
+
if (pageReader.isNull(inputColumn)) {
|
117
|
+
pageBuilder.setNull(inputColumn);
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
pageBuilder.setLong(inputColumn, pageReader.getLong(inputColumn));
|
121
|
+
}
|
93
122
|
}
|
94
123
|
else {
|
95
|
-
|
124
|
+
final Column outputColumn = outputColumnMap.get(name);
|
125
|
+
PageBuildable op = new PageBuildable() {
|
126
|
+
public void run() throws DataException {
|
127
|
+
columnCaster.setFromLong(outputColumn, pageReader.getLong(inputColumn));
|
128
|
+
}
|
129
|
+
};
|
130
|
+
withStopOnInvalidRecord(op, inputColumn, outputColumn);
|
96
131
|
}
|
97
132
|
}
|
98
133
|
|
99
134
|
@Override
|
100
135
|
public void doubleColumn(final Column inputColumn)
|
101
136
|
{
|
102
|
-
|
103
|
-
|
137
|
+
String name = inputColumn.getName();
|
138
|
+
if (! shouldCast(name)){
|
139
|
+
if (pageReader.isNull(inputColumn)) {
|
140
|
+
pageBuilder.setNull(inputColumn);
|
141
|
+
}
|
142
|
+
else {
|
143
|
+
pageBuilder.setDouble(inputColumn, pageReader.getDouble(inputColumn));
|
144
|
+
}
|
104
145
|
}
|
105
146
|
else {
|
106
|
-
|
147
|
+
final Column outputColumn = outputColumnMap.get(inputColumn.getName());
|
148
|
+
PageBuildable op = new PageBuildable() {
|
149
|
+
public void run() throws DataException {
|
150
|
+
columnCaster.setFromDouble(outputColumn, pageReader.getDouble(inputColumn));
|
151
|
+
}
|
152
|
+
};
|
153
|
+
withStopOnInvalidRecord(op, inputColumn, outputColumn);
|
107
154
|
}
|
108
155
|
}
|
109
156
|
|
110
157
|
@Override
|
111
158
|
public void stringColumn(final Column inputColumn)
|
112
159
|
{
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
final Column outputColumn = outputColumnMap.get(inputColumn.getName());
|
118
|
-
PageBuildable op = new PageBuildable() {
|
119
|
-
public void run() throws DataException
|
120
|
-
{
|
121
|
-
columnCaster.setFromString(outputColumn, pageReader.getString(inputColumn));
|
160
|
+
String name = inputColumn.getName();
|
161
|
+
if (! shouldCast(name)){
|
162
|
+
if (pageReader.isNull(inputColumn)) {
|
163
|
+
pageBuilder.setNull(inputColumn);
|
122
164
|
}
|
123
|
-
|
124
|
-
|
165
|
+
else {
|
166
|
+
pageBuilder.setString(inputColumn, pageReader.getString(inputColumn));
|
167
|
+
}
|
168
|
+
}
|
169
|
+
else {
|
170
|
+
final Column outputColumn = outputColumnMap.get(inputColumn.getName());
|
171
|
+
PageBuildable op = new PageBuildable() {
|
172
|
+
public void run() throws DataException {
|
173
|
+
columnCaster.setFromString(outputColumn, pageReader.getString(inputColumn));
|
174
|
+
}
|
175
|
+
};
|
176
|
+
withStopOnInvalidRecord(op, inputColumn, outputColumn);
|
177
|
+
}
|
125
178
|
}
|
126
179
|
|
127
180
|
@Override
|
128
181
|
public void timestampColumn(final Column inputColumn)
|
129
182
|
{
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
final Column outputColumn = outputColumnMap.get(inputColumn.getName());
|
135
|
-
PageBuildable op = new PageBuildable() {
|
136
|
-
public void run() throws DataException
|
137
|
-
{
|
138
|
-
columnCaster.setFromTimestamp(outputColumn, pageReader.getTimestamp(inputColumn));
|
183
|
+
String name = inputColumn.getName();
|
184
|
+
if (! shouldCast(name)){
|
185
|
+
if (pageReader.isNull(inputColumn)) {
|
186
|
+
pageBuilder.setNull(inputColumn);
|
139
187
|
}
|
140
|
-
|
141
|
-
|
188
|
+
else {
|
189
|
+
pageBuilder.setTimestamp(inputColumn, pageReader.getTimestamp(inputColumn));
|
190
|
+
}
|
191
|
+
}
|
192
|
+
else {
|
193
|
+
final Column outputColumn = outputColumnMap.get(inputColumn.getName());
|
194
|
+
PageBuildable op = new PageBuildable() {
|
195
|
+
public void run() throws DataException {
|
196
|
+
columnCaster.setFromTimestamp(outputColumn, pageReader.getTimestamp(inputColumn));
|
197
|
+
}
|
198
|
+
};
|
199
|
+
withStopOnInvalidRecord(op, inputColumn, outputColumn);
|
200
|
+
}
|
142
201
|
}
|
143
202
|
|
144
203
|
@Override
|
145
204
|
public void jsonColumn(final Column inputColumn)
|
146
205
|
{
|
147
|
-
|
148
|
-
|
149
|
-
|
206
|
+
String name = inputColumn.getName();
|
207
|
+
if (! shouldCast(name)){
|
208
|
+
if (pageReader.isNull(inputColumn)) {
|
209
|
+
pageBuilder.setNull(inputColumn);
|
210
|
+
}
|
211
|
+
else {
|
212
|
+
pageBuilder.setJson(inputColumn, pageReader.getJson(inputColumn));
|
213
|
+
}
|
214
|
+
}
|
215
|
+
else {
|
216
|
+
final Column outputColumn = outputColumnMap.get(inputColumn.getName());
|
217
|
+
PageBuildable op = new PageBuildable() {
|
218
|
+
public void run() throws DataException {
|
219
|
+
columnCaster.setFromJson(outputColumn, pageReader.getJson(inputColumn));
|
220
|
+
}
|
221
|
+
};
|
222
|
+
withStopOnInvalidRecord(op, inputColumn, outputColumn);
|
150
223
|
}
|
151
|
-
final Column outputColumn = outputColumnMap.get(inputColumn.getName());
|
152
|
-
columnCaster.setFromJson(outputColumn, pageReader.getJson(inputColumn));
|
153
224
|
}
|
154
225
|
}
|
@@ -1,5 +1,8 @@
|
|
1
1
|
package org.embulk.filter.timestamp_format;
|
2
2
|
|
3
|
+
import org.embulk.config.ConfigException;
|
4
|
+
import org.embulk.filter.timestamp_format.cast.DoubleCast;
|
5
|
+
import org.embulk.filter.timestamp_format.cast.LongCast;
|
3
6
|
import org.embulk.filter.timestamp_format.cast.StringCast;
|
4
7
|
import org.embulk.filter.timestamp_format.TimestampFormatFilterPlugin.ColumnConfig;
|
5
8
|
import org.embulk.filter.timestamp_format.TimestampFormatFilterPlugin.PluginTask;
|
@@ -8,6 +11,8 @@ import org.embulk.spi.type.DoubleType;
|
|
8
11
|
import org.embulk.spi.type.LongType;
|
9
12
|
import org.embulk.spi.type.StringType;
|
10
13
|
import org.embulk.spi.type.Type;
|
14
|
+
import org.msgpack.value.FloatValue;
|
15
|
+
import org.msgpack.value.IntegerValue;
|
11
16
|
import org.msgpack.value.StringValue;
|
12
17
|
import org.msgpack.value.Value;
|
13
18
|
import org.msgpack.value.ValueFactory;
|
@@ -22,14 +27,64 @@ class JsonCaster
|
|
22
27
|
private final PluginTask task;
|
23
28
|
private final HashMap<String, TimestampParser> timestampParserMap;
|
24
29
|
private final HashMap<String, TimestampFormatter> timestampFormatterMap;
|
30
|
+
private final HashMap<String, TimestampUnit> fromTimestampUnitMap;
|
31
|
+
private final HashMap<String, TimestampUnit> toTimestampUnitMap;
|
25
32
|
|
26
33
|
JsonCaster(PluginTask task,
|
27
34
|
HashMap<String, TimestampParser> timestampParserMap,
|
28
|
-
HashMap<String, TimestampFormatter> timestampFormatterMap
|
35
|
+
HashMap<String, TimestampFormatter> timestampFormatterMap,
|
36
|
+
HashMap<String, TimestampUnit> fromTimestampUnitMap,
|
37
|
+
HashMap<String, TimestampUnit> toTimestampUnitMap)
|
29
38
|
{
|
30
39
|
this.task = task;
|
31
40
|
this.timestampParserMap = timestampParserMap;
|
32
41
|
this.timestampFormatterMap = timestampFormatterMap;
|
42
|
+
this.fromTimestampUnitMap = fromTimestampUnitMap;
|
43
|
+
this.toTimestampUnitMap = toTimestampUnitMap;
|
44
|
+
}
|
45
|
+
|
46
|
+
public Value fromLong(ColumnConfig columnConfig, IntegerValue value)
|
47
|
+
{
|
48
|
+
Type outputType = columnConfig.getType();
|
49
|
+
TimestampUnit fromUnit = fromTimestampUnitMap.get(columnConfig.getName());
|
50
|
+
if (outputType instanceof StringType) {
|
51
|
+
TimestampFormatter formatter = timestampFormatterMap.get(columnConfig.getName());
|
52
|
+
return ValueFactory.newString(LongCast.asString(value.asLong(), fromUnit, formatter));
|
53
|
+
}
|
54
|
+
else if (outputType instanceof LongType) {
|
55
|
+
TimestampUnit toUnit = toTimestampUnitMap.get(columnConfig.getName());
|
56
|
+
return ValueFactory.newInteger(LongCast.asLong(value.asLong(), fromUnit, toUnit));
|
57
|
+
}
|
58
|
+
else if (outputType instanceof DoubleType) {
|
59
|
+
TimestampUnit toUnit = toTimestampUnitMap.get(columnConfig.getName());
|
60
|
+
return ValueFactory.newFloat(LongCast.asDouble(value.asLong(), fromUnit, toUnit));
|
61
|
+
}
|
62
|
+
else {
|
63
|
+
assert false;
|
64
|
+
throw new RuntimeException();
|
65
|
+
}
|
66
|
+
}
|
67
|
+
|
68
|
+
public Value fromDouble(ColumnConfig columnConfig, FloatValue value)
|
69
|
+
{
|
70
|
+
Type outputType = columnConfig.getType();
|
71
|
+
TimestampUnit fromUnit = fromTimestampUnitMap.get(columnConfig.getName());
|
72
|
+
if (outputType instanceof StringType) {
|
73
|
+
TimestampFormatter formatter = timestampFormatterMap.get(columnConfig.getName());
|
74
|
+
return ValueFactory.newString(DoubleCast.asString(value.toDouble(), fromUnit, formatter));
|
75
|
+
}
|
76
|
+
else if (outputType instanceof LongType) {
|
77
|
+
TimestampUnit toUnit = toTimestampUnitMap.get(columnConfig.getName());
|
78
|
+
return ValueFactory.newInteger(DoubleCast.asLong(value.toDouble(), fromUnit, toUnit));
|
79
|
+
}
|
80
|
+
else if (outputType instanceof DoubleType) {
|
81
|
+
TimestampUnit toUnit = toTimestampUnitMap.get(columnConfig.getName());
|
82
|
+
return ValueFactory.newFloat(DoubleCast.asDouble(value.toDouble(), fromUnit, toUnit));
|
83
|
+
}
|
84
|
+
else {
|
85
|
+
assert false;
|
86
|
+
throw new RuntimeException();
|
87
|
+
}
|
33
88
|
}
|
34
89
|
|
35
90
|
public Value fromString(ColumnConfig columnConfig, StringValue value)
|
@@ -41,14 +96,16 @@ class JsonCaster
|
|
41
96
|
return ValueFactory.newString(StringCast.asString(value.asString(), parser, formatter));
|
42
97
|
}
|
43
98
|
else if (outputType instanceof LongType) {
|
44
|
-
|
99
|
+
TimestampUnit toUnit = toTimestampUnitMap.get(columnConfig.getName());
|
100
|
+
return ValueFactory.newInteger(StringCast.asLong(value.asString(), parser, toUnit));
|
45
101
|
}
|
46
102
|
else if (outputType instanceof DoubleType) {
|
47
|
-
|
103
|
+
TimestampUnit toUnit = toTimestampUnitMap.get(columnConfig.getName());
|
104
|
+
return ValueFactory.newFloat(StringCast.asDouble(value.asString(), parser, toUnit));
|
48
105
|
}
|
49
106
|
else {
|
50
107
|
assert false;
|
51
|
-
|
108
|
+
throw new RuntimeException();
|
52
109
|
}
|
53
110
|
}
|
54
111
|
}
|
@@ -108,6 +108,14 @@ public class JsonVisitor
|
|
108
108
|
}
|
109
109
|
return ValueFactory.newMap(newValue, true);
|
110
110
|
}
|
111
|
+
else if (value.isIntegerValue()) {
|
112
|
+
ColumnConfig columnConfig = jsonPathColumnConfigMap.get(jsonPath);
|
113
|
+
return jsonCaster.fromLong(columnConfig, value.asIntegerValue());
|
114
|
+
}
|
115
|
+
else if (value.isFloatValue()) {
|
116
|
+
ColumnConfig columnConfig = jsonPathColumnConfigMap.get(jsonPath);
|
117
|
+
return jsonCaster.fromDouble(columnConfig, value.asFloatValue());
|
118
|
+
}
|
111
119
|
else if (value.isStringValue()) {
|
112
120
|
ColumnConfig columnConfig = jsonPathColumnConfigMap.get(jsonPath);
|
113
121
|
return jsonCaster.fromString(columnConfig, value.asStringValue());
|
@@ -1,5 +1,6 @@
|
|
1
1
|
package org.embulk.filter.timestamp_format;
|
2
2
|
|
3
|
+
import com.google.common.base.Optional;
|
3
4
|
import com.google.common.collect.ImmutableList;
|
4
5
|
import org.embulk.config.Config;
|
5
6
|
import org.embulk.config.ConfigDefault;
|
@@ -18,9 +19,9 @@ import org.embulk.spi.PageOutput;
|
|
18
19
|
import org.embulk.spi.PageReader;
|
19
20
|
import org.embulk.spi.Schema;
|
20
21
|
|
21
|
-
import org.embulk.spi.
|
22
|
-
import org.embulk.spi.type.
|
23
|
-
import org.embulk.spi.type.
|
22
|
+
import org.embulk.spi.time.Timestamp;
|
23
|
+
import org.embulk.spi.type.BooleanType;
|
24
|
+
import org.embulk.spi.type.JsonType;
|
24
25
|
import org.embulk.spi.type.TimestampType;
|
25
26
|
import org.embulk.spi.type.Type;
|
26
27
|
import org.jruby.embed.ScriptingContainer;
|
@@ -44,6 +45,14 @@ public class TimestampFormatFilterPlugin implements FilterPlugin
|
|
44
45
|
@Config("type")
|
45
46
|
@ConfigDefault("\"string\"")
|
46
47
|
Type getType();
|
48
|
+
|
49
|
+
@Config("from_unit")
|
50
|
+
@ConfigDefault("null")
|
51
|
+
Optional<TimestampUnit> getFromUnit();
|
52
|
+
|
53
|
+
@Config("to_unit")
|
54
|
+
@ConfigDefault("null")
|
55
|
+
Optional<TimestampUnit> getToUnit();
|
47
56
|
}
|
48
57
|
|
49
58
|
interface PluginTask extends Task,
|
@@ -57,6 +66,14 @@ public class TimestampFormatFilterPlugin implements FilterPlugin
|
|
57
66
|
@ConfigDefault("false")
|
58
67
|
Boolean getStopOnInvalidRecord();
|
59
68
|
|
69
|
+
@Config("default_from_timestamp_unit")
|
70
|
+
@ConfigDefault("\"second\"")
|
71
|
+
TimestampUnit getDefaultFromTimestampUnit();
|
72
|
+
|
73
|
+
@Config("default_to_timestamp_unit")
|
74
|
+
@ConfigDefault("\"second\"")
|
75
|
+
TimestampUnit getDefaultToTimestampUnit();
|
76
|
+
|
60
77
|
@ConfigInject
|
61
78
|
ScriptingContainer getJRuby();
|
62
79
|
}
|
@@ -88,24 +105,18 @@ public class TimestampFormatFilterPlugin implements FilterPlugin
|
|
88
105
|
}
|
89
106
|
}
|
90
107
|
|
91
|
-
// throw if column type is not
|
108
|
+
// throw if column type is not supported
|
92
109
|
for (ColumnConfig columnConfig : columns) {
|
110
|
+
String name = columnConfig.getName();
|
93
111
|
Type type = columnConfig.getType();
|
94
|
-
|
95
|
-
|
96
|
-
continue;
|
97
|
-
}
|
98
|
-
else if (type instanceof TimestampType) {
|
99
|
-
continue;
|
112
|
+
if (type instanceof BooleanType) {
|
113
|
+
throw new ConfigException(String.format("casting to boolean is not available: \"%s\"", name));
|
100
114
|
}
|
101
|
-
|
102
|
-
|
115
|
+
if (type instanceof JsonType) {
|
116
|
+
throw new ConfigException(String.format("casting to json is not available: \"%s\"", name));
|
103
117
|
}
|
104
|
-
|
105
|
-
|
106
|
-
}
|
107
|
-
else {
|
108
|
-
throw new ConfigException("column type must be string, timestamp, long, or double");
|
118
|
+
if (name.startsWith("$.") && type instanceof TimestampType) {
|
119
|
+
throw new ConfigException(String.format("casting a json path into timestamp is not available: \"%s\"", name));
|
109
120
|
}
|
110
121
|
}
|
111
122
|
}
|
@@ -15,6 +15,8 @@ import org.joda.time.DateTimeZone;
|
|
15
15
|
import org.jruby.embed.ScriptingContainer;
|
16
16
|
import org.jruby.util.RubyDateFormat;
|
17
17
|
|
18
|
+
import java.text.SimpleDateFormat;
|
19
|
+
import java.util.Date;
|
18
20
|
import java.util.Locale;
|
19
21
|
|
20
22
|
public class TimestampFormatter
|
@@ -41,7 +43,8 @@ public class TimestampFormatter
|
|
41
43
|
Optional<String> getToFormat();
|
42
44
|
}
|
43
45
|
|
44
|
-
private final RubyDateFormat
|
46
|
+
private final RubyDateFormat jrubyFormatter;
|
47
|
+
private final SimpleDateFormat javaFormatter;
|
45
48
|
private final DateTimeZone toTimeZone;
|
46
49
|
|
47
50
|
public TimestampFormatter(PluginTask task, Optional<? extends TimestampColumnOption> columnOption)
|
@@ -58,7 +61,15 @@ public class TimestampFormatter
|
|
58
61
|
public TimestampFormatter(ScriptingContainer jruby, String format, DateTimeZone toTimeZone)
|
59
62
|
{
|
60
63
|
this.toTimeZone = toTimeZone;
|
61
|
-
|
64
|
+
if (format.contains("%")) {
|
65
|
+
this.jrubyFormatter = new RubyDateFormat(format, Locale.ENGLISH, true);
|
66
|
+
this.javaFormatter = null;
|
67
|
+
}
|
68
|
+
else {
|
69
|
+
this.jrubyFormatter = null;
|
70
|
+
this.javaFormatter = new SimpleDateFormat(format, Locale.ENGLISH);
|
71
|
+
javaFormatter.setTimeZone(toTimeZone.toTimeZone());
|
72
|
+
}
|
62
73
|
}
|
63
74
|
|
64
75
|
public DateTimeZone getToTimeZone()
|
@@ -73,10 +84,30 @@ public class TimestampFormatter
|
|
73
84
|
}
|
74
85
|
|
75
86
|
public String format(Timestamp value)
|
87
|
+
{
|
88
|
+
if (jrubyFormatter != null) {
|
89
|
+
return jrubyFormat(value);
|
90
|
+
}
|
91
|
+
else if (javaFormatter != null) {
|
92
|
+
return javaFormat(value);
|
93
|
+
}
|
94
|
+
else {
|
95
|
+
assert false;
|
96
|
+
throw new RuntimeException();
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
private String jrubyFormat(Timestamp value)
|
76
101
|
{
|
77
102
|
// TODO optimize by using reused StringBuilder
|
78
|
-
|
79
|
-
|
80
|
-
return
|
103
|
+
jrubyFormatter.setDateTime(new DateTime(value.getEpochSecond() * 1000, toTimeZone));
|
104
|
+
jrubyFormatter.setNSec(value.getNano());
|
105
|
+
return jrubyFormatter.format(null);
|
106
|
+
}
|
107
|
+
|
108
|
+
private String javaFormat(Timestamp value)
|
109
|
+
{
|
110
|
+
long milliSecond = value.getEpochSecond() * 1000 + value.getNano() / 1000000;
|
111
|
+
return javaFormatter.format(milliSecond);
|
81
112
|
}
|
82
113
|
}
|