forked from duckdb/duckdb-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDuckDBTimestamp.java
More file actions
183 lines (156 loc) · 6.44 KB
/
DuckDBTimestamp.java
File metadata and controls
183 lines (156 loc) · 6.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
package org.duckdb;
import java.sql.Date;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.*;
import java.time.temporal.ChronoUnit;
public class DuckDBTimestamp {
static {
// LocalDateTime reference of epoch
RefLocalDateTime = LocalDateTime.ofEpochSecond(0, 0, ZoneOffset.UTC);
}
public DuckDBTimestamp(long timeMicros) {
this.timeMicros = timeMicros;
}
public DuckDBTimestamp(LocalDateTime localDateTime) {
this.timeMicros = localDateTime2Micros(localDateTime);
}
public DuckDBTimestamp(OffsetDateTime offsetDateTime) {
this.timeMicros = DuckDBTimestamp.RefLocalDateTime.until(offsetDateTime.withOffsetSameInstant(ZoneOffset.UTC),
ChronoUnit.MICROS);
}
public DuckDBTimestamp(Timestamp sqlTimestamp) {
this.timeMicros = DuckDBTimestamp.RefLocalDateTime.until(sqlTimestamp.toLocalDateTime(), ChronoUnit.MICROS);
}
final static LocalDateTime RefLocalDateTime;
protected long timeMicros;
private static Instant createInstant(long value, ChronoUnit unit) throws SQLException {
switch (unit) {
case SECONDS:
return Instant.ofEpochSecond(value);
case MILLIS:
return Instant.ofEpochMilli(value);
case MICROS: {
long epochSecond = value / 1_000_000;
int nanoAdjustment = nanosPartMicros(value);
return Instant.ofEpochSecond(epochSecond, nanoAdjustment);
}
case NANOS: {
long epochSecond = value / 1_000_000_000;
long nanoAdjustment = nanosPartNanos(value);
return Instant.ofEpochSecond(epochSecond, nanoAdjustment);
}
default:
throw new SQLException("Unsupported unit type: [" + unit + "]");
}
}
public static LocalDateTime localDateTimeFromTimestampWithTimezone(long value, ChronoUnit unit,
ZoneId zoneIdNullable) throws SQLException {
Instant instant = createInstant(value, unit);
ZoneId zoneId = zoneIdNullable != null ? zoneIdNullable : ZoneId.systemDefault();
return LocalDateTime.ofInstant(instant, zoneId);
}
public static LocalDateTime localDateTimeFromTimestamp(long value, ChronoUnit unit, ZoneId zoneIdNullable)
throws SQLException {
Instant instant = createInstant(value, unit);
LocalDateTime ldt = LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
if (null == zoneIdNullable) {
return ldt;
}
ZoneId zoneIdDefault = ZoneId.systemDefault();
LocalDateTime ldtDefault = LocalDateTime.ofInstant(instant, zoneIdDefault);
LocalDateTime ldtZoned = LocalDateTime.ofInstant(instant, zoneIdNullable);
Duration duration = Duration.between(ldtZoned, ldtDefault);
LocalDateTime ldtAdjusted = ldt.plus(duration);
return ldtAdjusted;
}
public static OffsetTime toOffsetTime(long timeBits) {
long timeMicros = timeBits >> 24; // High 40 bits are micros
long offset = timeBits & 0x0FFFFFF; // Low 24 bits are inverted biased offset in seconds
long max_offset = 16 * 60 * 60 - 1; // ±15:59:59
offset = max_offset - offset;
int sign = (offset < 0) ? -1 : 1;
offset = Math.abs(offset);
int ss = (int) offset % 60;
offset = offset / 60;
int mm = (int) offset % 60;
int hh = (int) offset / 60;
if (hh > 15) {
return OffsetTime.of(toLocalTime(timeMicros), ZoneOffset.UTC);
} else {
return OffsetTime.of(toLocalTime(timeMicros),
ZoneOffset.ofHoursMinutesSeconds(sign * hh, sign * mm, sign * ss));
}
}
private static LocalTime toLocalTime(long timeMicros) {
return LocalTime.ofNanoOfDay(timeMicros * 1000);
}
public static long localDateTime2Micros(LocalDateTime localDateTime) {
return DuckDBTimestamp.RefLocalDateTime.until(localDateTime, ChronoUnit.MICROS);
}
// TODO: move this to C++ side
public static Object valueOf(Object x) {
// Change sql.Timestamp to DuckDBTimestamp
if (x instanceof Timestamp) {
x = new DuckDBTimestamp((Timestamp) x);
} else if (x instanceof LocalDateTime) {
x = new DuckDBTimestamp((LocalDateTime) x);
} else if (x instanceof LocalDate) {
x = new DuckDBDate(Date.valueOf((LocalDate) x));
} else if (x instanceof OffsetDateTime) {
x = new DuckDBTimestampTZ((OffsetDateTime) x);
} else if (x instanceof Date) {
x = new DuckDBDate((Date) x);
} else if (x instanceof Time) {
x = new DuckDBTime((Time) x);
}
return x;
}
public Timestamp toSqlTimestamp() {
return Timestamp.valueOf(this.toLocalDateTime());
}
public LocalDateTime toLocalDateTime() {
return LocalDateTime.ofEpochSecond(micros2seconds(timeMicros), nanosPartMicros(timeMicros), ZoneOffset.UTC);
}
public OffsetDateTime toOffsetDateTime() {
return OffsetDateTime.of(toLocalDateTime(), ZoneOffset.UTC);
}
public static long getMicroseconds(Timestamp sqlTimestamp) {
return DuckDBTimestamp.RefLocalDateTime.until(sqlTimestamp.toLocalDateTime(), ChronoUnit.MICROS);
}
public long getMicrosEpoch() {
return this.timeMicros;
}
public String toString() {
return this.toLocalDateTime().toString();
}
private static long micros2seconds(long micros) {
if ((micros % 1000_000L) >= 0) {
return micros / 1000_000L;
} else {
return (micros / 1000_000L) - 1;
}
}
private static int nanosPartMicros(long micros) {
if ((micros % 1000_000L) >= 0) {
return (int) ((micros % 1000_000L) * 1000);
} else {
return (int) ((1000_000L + (micros % 1000_000L)) * 1000);
}
}
private static long nanos2seconds(long nanos) {
if ((nanos % 1_000_000_000L) >= 0) {
return nanos / 1_000_000_000L;
} else {
return (nanos / 1_000_000_000L) - 1;
}
}
private static int nanosPartNanos(long nanos) {
if ((nanos % 1_000_000_000L) >= 0) {
return (int) ((nanos % 1_000_000_000L));
} else {
return (int) ((1_000_000_000L + (nanos % 1_000_000_000L)));
}
}
}