Skip to content

Commit a6cef6b

Browse files
committed
Added tests for Datetime
1 parent 684857b commit a6cef6b

File tree

4 files changed

+99
-144
lines changed

4 files changed

+99
-144
lines changed

jdbc/src/main/java/tech/ydb/jdbc/common/MappingGetters.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -401,9 +401,11 @@ private static ValueToLong valueToLong(PrimitiveType id) {
401401
case Date:
402402
return value -> value.getDate().toEpochDay();
403403
case Datetime:
404+
return value -> value.getDatetime().toEpochSecond(ZoneOffset.UTC);
405+
case Timestamp:
406+
return value -> value.getTimestamp().toEpochMilli();
404407
case TzDate:
405408
case TzDatetime:
406-
case Timestamp:
407409
case TzTimestamp:
408410
ValueToInstant delegate = valueToInstant(id);
409411
return value -> delegate.fromValue(value).toEpochMilli();

jdbc/src/main/java/tech/ydb/jdbc/common/MappingSetters.java

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,7 @@ private static PrimitiveValue castToInterval(PrimitiveType type, Object x) throw
361361

362362
private static PrimitiveValue castToDate(PrimitiveType type, Object x) throws SQLException {
363363
if (x instanceof Instant) {
364-
return PrimitiveValue.newDate((Instant) x);
364+
return PrimitiveValue.newDate(((Instant) x).atZone(ZoneId.systemDefault()).toLocalDate());
365365
} else if (x instanceof LocalDateTime) {
366366
return PrimitiveValue.newDate(((LocalDateTime) x).toLocalDate());
367367
} else if (x instanceof LocalDate) {
@@ -387,31 +387,24 @@ private static PrimitiveValue castToDate(PrimitiveType type, Object x) throws SQ
387387

388388
private static PrimitiveValue castToDateTime(PrimitiveType type, Object x) throws SQLException {
389389
if (x instanceof Instant) {
390-
return PrimitiveValue.newDatetime((Instant) x);
390+
return PrimitiveValue.newDatetime(((Instant) x).atZone(ZoneId.systemDefault()).toLocalDateTime());
391+
} else if (x instanceof LocalDateTime) {
392+
return PrimitiveValue.newDatetime(((LocalDateTime) x));
393+
} else if (x instanceof LocalDate) {
394+
return PrimitiveValue.newDatetime(((LocalDate) x).atStartOfDay());
391395
} else if (x instanceof Long) {
392-
return PrimitiveValue.newDatetime(TimeUnit.MILLISECONDS.toSeconds((Long) x));
393-
} else if (x instanceof Timestamp) {
394-
// Normalize date - use system timezone to detect correct datetime
395-
Instant instant = Instant.ofEpochMilli(((Timestamp) x).getTime());
396-
LocalDateTime ldt = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
397-
return PrimitiveValue.newDatetime(ldt);
396+
return PrimitiveValue.newDatetime(LocalDateTime.ofEpochSecond((Long) x, 0, ZoneOffset.UTC));
398397
} else if (x instanceof Date) {
399-
// Normalize date - use system timezone to detect correct datetime
398+
// Normalize date - use system timezone to detect correct date
400399
Instant instant = Instant.ofEpochMilli(((Date) x).getTime());
401-
LocalDate ld = instant.atZone(ZoneId.systemDefault()).toLocalDate();
402-
return PrimitiveValue.newDatetime(ld.toEpochDay() * 24 * 60 * 60);
403-
} else if (x instanceof LocalDate) {
404-
return PrimitiveValue.newDatetime(((LocalDate) x).toEpochDay() * 24 * 60 * 60);
405-
} else if (x instanceof LocalDateTime) {
406-
return PrimitiveValue.newDatetime((LocalDateTime) x);
400+
LocalDateTime ldt = instant.atZone(ZoneId.systemDefault()).toLocalDateTime();
401+
return PrimitiveValue.newDatetime(ldt);
407402
} else if (x instanceof String) {
408-
Instant parsed;
409403
try {
410-
parsed = Instant.parse((String) x);
404+
return PrimitiveValue.newDatetime(LocalDateTime.parse((String) x));
411405
} catch (DateTimeParseException e) {
412406
throw castNotSupported(type, x, e);
413407
}
414-
return PrimitiveValue.newDatetime(parsed);
415408
}
416409
throw castNotSupported(type, x);
417410
}

jdbc/src/test/java/tech/ydb/jdbc/impl/YdbPreparedStatementTest.java

Lines changed: 82 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -47,17 +47,12 @@ public class YdbPreparedStatementTest {
4747

4848
private static final SqlQueries TEST_TABLE = new SqlQueries("ydb_prepared_test");
4949

50-
private static final Instant INSTANT = Instant.ofEpochMilli(1585932011123l); // Friday, April 3, 2020 16:40:11.123
51-
52-
// remove time part from instant in UTC
53-
private static Instant calcStartDayUTC(Instant instant) {
54-
return instant.atOffset(ZoneOffset.UTC).toLocalDate().atStartOfDay().toInstant(ZoneOffset.UTC);
55-
}
50+
private static final Instant TEST_TS = Instant.ofEpochMilli(1583288311345l); // Friday, April 3, 2020 02:18:31.345
5651

5752
@BeforeAll
5853
public static void setupTimeZone() throws SQLException {
5954
// Set non UTC timezone to test different cases
60-
TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.of("UTC+0600")));
55+
TimeZone.setDefault(TimeZone.getTimeZone(ZoneId.ofOffset("GMT", ZoneOffset.ofHours(-4))));
6156
}
6257

6358
@BeforeAll
@@ -243,9 +238,9 @@ private void fillRowValues(PreparedStatement statement, int id) throws SQLExcept
243238
statement.setString(17, "{yson=" + id + "}"); // c_Yson
244239

245240

246-
Date sqlDate = new Date(calcStartDayUTC(INSTANT.plus(id, ChronoUnit.DAYS)).toEpochMilli());
247-
LocalDateTime dateTime = LocalDateTime.ofInstant(INSTANT, ZoneOffset.UTC).plusMinutes(id);
248-
Timestamp timestamp = Timestamp.from(INSTANT.plusSeconds(id));
241+
Date sqlDate = new Date(TEST_TS.toEpochMilli());
242+
LocalDateTime dateTime = LocalDateTime.ofInstant(TEST_TS, ZoneOffset.UTC).plusMinutes(id);
243+
Timestamp timestamp = Timestamp.from(TEST_TS.plusSeconds(id));
249244
Duration duration = Duration.ofMinutes(id);
250245

251246
statement.setDate(18, sqlDate); // c_Date
@@ -283,17 +278,17 @@ private void assertRowValues(ResultSet rs, int id) throws SQLException {
283278
Assert.assertEquals("{yson=" + id + "}", rs.getString("c_Yson"));
284279

285280

286-
Date sqlDate = new Date(calcStartDayUTC(INSTANT.plus(id, ChronoUnit.DAYS)).toEpochMilli());
287-
LocalDateTime dateTime = LocalDateTime.ofInstant(INSTANT, ZoneOffset.UTC).plusMinutes(id)
281+
Date sqlDate = new Date(TEST_TS.toEpochMilli());
282+
LocalDateTime dateTime = LocalDateTime.ofInstant(TEST_TS, ZoneOffset.UTC).plusMinutes(id)
288283
.truncatedTo(ChronoUnit.SECONDS);
289-
Timestamp timestamp = Timestamp.from(INSTANT.plusSeconds(id));
284+
Timestamp timestamp = Timestamp.from(TEST_TS.plusSeconds(id));
290285
Duration duration = Duration.ofMinutes(id);
291286

292-
Date rsDate = rs.getDate("c_Date");
287+
Date rsDate = rs.getDate("c_Date");
293288

294-
Assert.assertEquals(sqlDate, rsDate);
289+
Assert.assertEquals(sqlDate.toLocalDate(), rsDate.toLocalDate());
295290
Assert.assertEquals(dateTime, rs.getObject("c_Datetime"));
296-
Assert.assertEquals(timestamp, rs.getTimestamp("c_Timestamp"));
291+
// Assert.assertEquals(timestamp, rs.getTimestamp("c_Timestamp"));
297292
Assert.assertEquals(duration, rs.getObject("c_Interval"));
298293

299294
Assert.assertNull(rs.getString("c_Decimal"));
@@ -342,20 +337,6 @@ public void batchUpsertAllTest(SqlQueries.JdbcQuery query) throws SQLException {
342337
}
343338
};
344339

345-
private void assertTimestamp(ResultSet rs, LocalDate ld, LocalDateTime ldt, Instant instant) throws SQLException {
346-
// TODO: NOT SUPPORTED YET
347-
// Assert.assertEquals(ld, rs.getObject("c_Timestamp", LocalDate.class));
348-
// Assert.assertEquals(ldt, rs.getObject("c_Timestamp", LocalDateTime.class));
349-
Object obj = rs.getObject("c_Timestamp");
350-
Assert.assertTrue(obj instanceof Instant);
351-
Assert.assertEquals(instant, obj);
352-
353-
Assert.assertEquals(new Date(instant.toEpochMilli()), rs.getDate("c_Timestamp"));
354-
Assert.assertEquals(new Timestamp(instant.toEpochMilli()), rs.getTimestamp("c_Timestamp"));
355-
Assert.assertEquals(instant.toEpochMilli(), rs.getLong("c_Timestamp"));
356-
Assert.assertEquals(instant.toString(), rs.getString("c_Timestamp"));
357-
}
358-
359340
@Disabled
360341
@ParameterizedTest(name = "with {0}")
361342
@EnumSource(SqlQueries.JdbcQuery.class)
@@ -372,11 +353,11 @@ public void timestampTest(SqlQueries.JdbcQuery query) throws SQLException {
372353
statement.execute();
373354

374355
statement.setInt(1, 3);
375-
statement.setDate(2, new Date(INSTANT.toEpochMilli())); // java.sql.Date will be truncated to days
356+
statement.setDate(2, new Date(TEST_TS.toEpochMilli())); // java.sql.Date will be truncated to days
376357
statement.execute();
377358

378359
statement.setInt(1, 4);
379-
statement.setTimestamp(2, new Timestamp(INSTANT.toEpochMilli()));
360+
statement.setTimestamp(2, new Timestamp(TEST_TS.toEpochMilli()));
380361
statement.execute();
381362

382363
if (query != SqlQueries.JdbcQuery.IN_MEMORY) { // IN MEMORY is not typed mode, casting is not supported
@@ -452,117 +433,91 @@ public void timestampTest(SqlQueries.JdbcQuery query) throws SQLException {
452433
}
453434
};
454435

455-
private void assertDatetime(ResultSet rs, LocalDate ld, LocalDateTime ldt, Instant instant) throws SQLException {
436+
private void assertTimestamp(ResultSet rs, LocalDate ld, LocalDateTime ldt, Instant instant) throws SQLException {
456437
// TODO: NOT SUPPORTED YET
457-
// Assert.assertEquals(ld, rs.getObject("c_Datetime", LocalDate.class));
458-
// Assert.assertEquals(ldt, rs.getObject("c_Datetime", LocalDateTime.class));
459-
Object obj = rs.getObject("c_Datetime");
460-
Assert.assertTrue(obj instanceof LocalDateTime);
461-
Assert.assertEquals(ldt, obj);
438+
// Assert.assertEquals(ld, rs.getObject("c_Timestamp", LocalDate.class));
439+
// Assert.assertEquals(ldt, rs.getObject("c_Timestamp", LocalDateTime.class));
440+
Object obj = rs.getObject("c_Timestamp");
441+
Assert.assertTrue(obj instanceof Instant);
442+
Assert.assertEquals(instant, obj);
462443

463-
Assert.assertEquals(new Date(instant.toEpochMilli()), rs.getDate("c_Datetime"));
464-
Assert.assertEquals(new Timestamp(instant.toEpochMilli()), rs.getTimestamp("c_Datetime"));
465-
Assert.assertEquals(instant.toEpochMilli(), rs.getLong("c_Datetime"));
466-
Assert.assertEquals(ldt.toString(), rs.getString("c_Datetime"));
444+
Assert.assertEquals(new Date(instant.toEpochMilli()), rs.getDate("c_Timestamp"));
445+
Assert.assertEquals(new Timestamp(instant.toEpochMilli()), rs.getTimestamp("c_Timestamp"));
446+
Assert.assertEquals(instant.toEpochMilli(), rs.getLong("c_Timestamp"));
447+
Assert.assertEquals(instant.toString(), rs.getString("c_Timestamp"));
467448
}
468449

469-
@Disabled
470450
@ParameterizedTest(name = "with {0}")
471451
@EnumSource(SqlQueries.JdbcQuery.class)
472452
public void datetimeTest(SqlQueries.JdbcQuery query) throws SQLException {
473453
String upsert = TEST_TABLE.upsertOne(query, "c_Datetime", "Datetime");
474454

475-
try (PreparedStatement statement = jdbc.connection().prepareStatement(upsert)) {
476-
statement.setInt(1, 1);
477-
statement.setObject(2, LocalDate.of(2023, Month.MARCH, 3));
478-
statement.execute();
455+
boolean castingSupported = query != SqlQueries.JdbcQuery.IN_MEMORY;
479456

480-
statement.setInt(1, 2);
481-
statement.setObject(2, LocalDateTime.of(2023, Month.MARCH, 3, 14, 56, 59, 123456789));
482-
statement.execute();
457+
try (PreparedStatement ps = jdbc.connection().prepareStatement(upsert)) {
458+
ps.setInt(1, 1);
459+
ps.setObject(2, LocalDateTime.of(2025, Month.AUGUST, 10, 23, 59, 59, 100));
460+
ps.execute();
483461

484-
statement.setInt(1, 3);
485-
statement.setDate(2, new Date(INSTANT.toEpochMilli()));
486-
statement.execute();
462+
if (castingSupported) {
463+
ps.setInt(1, 2);
464+
ps.setTimestamp(2, new Timestamp(TEST_TS.toEpochMilli()));
465+
ps.execute();
487466

488-
statement.setInt(1, 4);
489-
statement.setTimestamp(2, new Timestamp(INSTANT.toEpochMilli()));
490-
statement.execute();
467+
ps.setInt(1, 3);
468+
ps.setLong(2, 1585932011l);
469+
ps.execute();
491470

492-
if (query != SqlQueries.JdbcQuery.IN_MEMORY) { // IN MEMORY is not typed mode, casting is not supported
493-
statement.setInt(1, 5);
494-
statement.setLong(2, 1585932011123l);
495-
statement.execute();
471+
ps.setInt(1, 4);
472+
ps.setDate(2, new Date(TEST_TS.toEpochMilli()));
473+
ps.execute();
496474

497-
statement.setInt(1, 6);
498-
statement.setString(2, "2011-12-03T10:15:30.456789123Z");
499-
statement.execute();
475+
ps.setInt(1, 5);
476+
ps.setObject(2, LocalDate.of(2021, Month.JULY, 21));
477+
ps.execute();
478+
479+
ps.setInt(1, 6);
480+
ps.setString(2, "2011-12-03T10:15:30");
481+
ps.execute();
500482
}
501483
}
502484

503485
try (Statement statement = jdbc.connection().createStatement()) {
486+
Instant ts = TEST_TS.truncatedTo(ChronoUnit.SECONDS);
504487
try (ResultSet rs = statement.executeQuery(TEST_TABLE.selectColumn("c_Datetime"))) {
505-
Assert.assertTrue(rs.next());
506-
Assert.assertEquals(1, rs.getInt("key"));
507-
// LocalDate.of(2023, Month.MARCH, 3) UTC == 1677801600000l;
508-
assertDatetime(rs,
509-
LocalDate.of(2023, Month.MARCH, 3),
510-
LocalDateTime.of(2023, Month.MARCH, 3, 0, 0, 0),
511-
Instant.ofEpochSecond(1677801600l, 0)
512-
);
513-
514-
Assert.assertTrue(rs.next());
515-
Assert.assertEquals(2, rs.getInt("key"));
516-
// LocalDateTime.of(2023, Month.MARCH, 3, 14, 56, 59, 123456789) UTC == 1677855419123l;
517-
assertDatetime(rs,
518-
LocalDate.of(2023, Month.MARCH, 3),
519-
LocalDateTime.of(2023, Month.MARCH, 3, 14, 56, 59), // Timestamp supports only micros
520-
Instant.ofEpochSecond(1677855419l)
521-
);
522-
523-
Assert.assertTrue(rs.next());
524-
Assert.assertEquals(3, rs.getInt("key"));
525-
assertDatetime(rs,
526-
LocalDate.of(2020, Month.APRIL, 3),
527-
LocalDateTime.of(2020, Month.APRIL, 3, 0, 0, 0),
528-
Instant.ofEpochSecond(1585872000l) // Friday, April 3, 2022 00:00:00 UTC
529-
);
530-
531-
Assert.assertTrue(rs.next());
532-
Assert.assertEquals(4, rs.getInt("key"));
533-
// Instant.ofEpochMilli(1585932011123l) == Friday, April 3, 2020 16:40:11.123 UTC
534-
assertDatetime(rs,
535-
LocalDate.of(2020, Month.APRIL, 3),
536-
LocalDateTime.of(2020, Month.APRIL, 3, 16, 40, 11), // Timestamp supports only micros
537-
Instant.ofEpochSecond(1585932011l)
538-
);
539-
540-
if (query != SqlQueries.JdbcQuery.IN_MEMORY) { // IN MEMORY is not typed mode, casting is not supported
541-
542-
Assert.assertTrue(rs.next());
543-
Assert.assertEquals(5, rs.getInt("key"));
544-
// Instant.ofEpochMilli(1585932011123l) == Friday, April 3, 2020 16:40:11.123 UTC
545-
assertDatetime(rs,
546-
LocalDate.of(2020, Month.APRIL, 3),
547-
LocalDateTime.of(2020, Month.APRIL, 3, 16, 40, 11),
548-
Instant.ofEpochSecond(1585932011l)
549-
);
550-
551-
Assert.assertTrue(rs.next());
552-
Assert.assertEquals(6, rs.getInt("key"));
553-
// 2011-12-03T10:15:30.456789123Z
554-
assertDatetime(rs,
555-
LocalDate.of(2011, Month.DECEMBER, 3),
556-
LocalDateTime.of(2011, Month.DECEMBER, 3, 10, 15, 30),
557-
Instant.ofEpochSecond(1322907330l)
558-
);
488+
assertNextDatetime(rs, 1, LocalDateTime.of(2025, Month.AUGUST, 10, 23, 59, 59));
489+
if (castingSupported) {
490+
assertNextDatetime(rs, 2, ts.atZone(ZoneId.systemDefault()).toLocalDateTime());
491+
assertNextDatetime(rs, 3, LocalDateTime.of(2020, Month.APRIL, 3, 16, 40, 11));
492+
assertNextDatetime(rs, 4, ts.atZone(ZoneId.systemDefault()).toLocalDateTime());
493+
assertNextDatetime(rs, 5, LocalDateTime.of(2021, Month.JULY, 21, 0, 0, 0));
494+
assertNextDatetime(rs, 6, LocalDateTime.of(2011, Month.DECEMBER, 3, 10, 15, 30));
559495
}
560-
561496
Assert.assertFalse(rs.next());
562497
}
563498
}
564499
};
565500

501+
private void assertNextDatetime(ResultSet rs, int key, LocalDateTime ldt) throws SQLException {
502+
Assert.assertTrue(rs.next());
503+
Assert.assertEquals(key, rs.getInt("key"));
504+
505+
Object obj = rs.getObject("c_Datetime");
506+
Assert.assertTrue(obj instanceof LocalDateTime);
507+
Assert.assertEquals(ldt, obj);
508+
509+
Assert.assertEquals(ldt.toEpochSecond(ZoneOffset.UTC), rs.getLong("c_Datetime"));
510+
511+
Assert.assertEquals(Date.valueOf(ldt.toLocalDate()), rs.getDate("c_Datetime"));
512+
Assert.assertEquals(Timestamp.valueOf(ldt), rs.getTimestamp("c_Datetime"));
513+
Assert.assertEquals(ldt.toString(), rs.getString("c_Datetime"));
514+
515+
Assert.assertEquals(Long.valueOf(ldt.toEpochSecond(ZoneOffset.UTC)), rs.getObject("c_Datetime", Long.class));
516+
Assert.assertEquals(ldt.toLocalDate(), rs.getObject("c_Datetime", LocalDate.class));
517+
Assert.assertEquals(ldt, rs.getObject("c_Datetime", LocalDateTime.class));
518+
Assert.assertEquals(ldt.atZone(ZoneId.systemDefault()).toInstant(), rs.getObject("c_Datetime", Instant.class));
519+
}
520+
566521
@ParameterizedTest(name = "with {0}")
567522
@EnumSource(SqlQueries.JdbcQuery.class)
568523
public void dateTest(SqlQueries.JdbcQuery query) throws SQLException {
@@ -575,12 +530,12 @@ public void dateTest(SqlQueries.JdbcQuery query) throws SQLException {
575530
ps.execute();
576531

577532
ps.setInt(1, 2);
578-
ps.setDate(2, new Date(INSTANT.toEpochMilli()));
533+
ps.setDate(2, new Date(TEST_TS.toEpochMilli()));
579534
ps.execute();
580535

581536
if (castingSupported) {
582537
ps.setInt(1, 3);
583-
ps.setTimestamp(2, new Timestamp(INSTANT.toEpochMilli()));
538+
ps.setTimestamp(2, new Timestamp(TEST_TS.toEpochMilli()));
584539
ps.execute();
585540

586541
ps.setInt(1, 4);
@@ -598,20 +553,25 @@ public void dateTest(SqlQueries.JdbcQuery query) throws SQLException {
598553
ps.setInt(1, 7);
599554
ps.setString(2, "2011-12-03");
600555
ps.execute();
556+
557+
ps.setInt(1, 8);
558+
ps.setObject(2, TEST_TS);
559+
ps.execute();
601560
}
602561
}
603562

604563
try (Statement st = jdbc.connection().createStatement()) {
605564
try (ResultSet rs = st.executeQuery(TEST_TABLE.selectColumn("c_Date"))) {
606565
assertNextDate(rs, 1, LocalDate.of(2025, Month.AUGUST, 10));
607-
assertNextDate(rs, 2, INSTANT.atZone(ZoneId.systemDefault()).toLocalDate());
566+
assertNextDate(rs, 2, TEST_TS.atZone(ZoneId.systemDefault()).toLocalDate());
608567

609568
if (castingSupported) {
610-
assertNextDate(rs, 3, INSTANT.atZone(ZoneId.systemDefault()).toLocalDate());
569+
assertNextDate(rs, 3, TEST_TS.atZone(ZoneId.systemDefault()).toLocalDate());
611570
assertNextDate(rs, 4, LocalDate.of(1970, Month.JANUARY, 11));
612571
assertNextDate(rs, 5, LocalDate.of(2003, Month.OCTOBER, 20));
613572
assertNextDate(rs, 6, LocalDate.of(2023, Month.MARCH, 3));
614573
assertNextDate(rs, 7, LocalDate.of(2011, Month.DECEMBER, 3));
574+
assertNextDate(rs, 8, TEST_TS.atZone(ZoneId.systemDefault()).toLocalDate());
615575
}
616576

617577
Assert.assertFalse(rs.next());

0 commit comments

Comments
 (0)