View Javadoc
1   /*
2   Copyright (c) 2018 James Ahlborn
3   
4   Licensed under the Apache License, Version 2.0 (the "License");
5   you may not use this file except in compliance with the License.
6   You may obtain a copy of the License at
7   
8       http://www.apache.org/licenses/LICENSE-2.0
9   
10  Unless required by applicable law or agreed to in writing, software
11  distributed under the License is distributed on an "AS IS" BASIS,
12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  See the License for the specific language governing permissions and
14  limitations under the License.
15  */
16  
17  package com.healthmarketscience.jackcess;
18  
19  import java.text.DateFormat;
20  import java.text.SimpleDateFormat;
21  import java.time.Instant;
22  import java.time.LocalDate;
23  import java.time.LocalDateTime;
24  import java.time.ZoneId;
25  import java.time.ZonedDateTime;
26  import java.time.format.DateTimeFormatter;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  import java.util.Calendar;
30  import java.util.Date;
31  import java.util.List;
32  import java.util.TimeZone;
33  
34  import static com.healthmarketscience.jackcess.Database.*;
35  import static com.healthmarketscience.jackcess.DatabaseBuilder.*;
36  import static com.healthmarketscience.jackcess.TestUtil.*;
37  import com.healthmarketscience.jackcess.impl.ColumnImpl;
38  import com.healthmarketscience.jackcess.impl.DatabaseImpl;
39  import static com.healthmarketscience.jackcess.impl.JetFormatTest.*;
40  import static org.junit.jupiter.api.Assertions.*;
41  import org.junit.jupiter.api.Test;
42  
43  /**
44   *
45   * @author James Ahlborn
46   */
47  public class LocalDateTimeTest
48  {
49  
50    @Test
51    public void testWriteAndReadLocalDate() throws Exception {
52      for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
53        try (Database db = createMem(fileFormat)) {
54  
55          db.setDateTimeType(DateTimeType.LOCAL_DATE_TIME);
56  
57          Table table = newTable("test")
58            .addColumn(newColumn("name", DataType.TEXT))
59            .addColumn(newColumn("date", DataType.SHORT_DATE_TIME))
60            .toTable(db);
61  
62          // since jackcess does not really store millis, shave them off before
63          // storing the current date/time
64          long curTimeNoMillis = (System.currentTimeMillis() / 1000L);
65          curTimeNoMillis *= 1000L;
66  
67          DateFormat df = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
68          List<Date> dates =
69            new ArrayList<Date>(
70                Arrays.asList(
71                    df.parse("19801231 00:00:00"),
72                    df.parse("19930513 14:43:27"),
73                    null,
74                    df.parse("20210102 02:37:00"),
75                    new Date(curTimeNoMillis)));
76  
77          Calendar c = Calendar.getInstance();
78          for(int year = 1801; year < 2050; year +=3) {
79            for(int month = 0; month <= 12; ++month) {
80              for(int day = 1; day < 29; day += 3) {
81                c.clear();
82                c.set(Calendar.YEAR, year);
83                c.set(Calendar.MONTH, month);
84                c.set(Calendar.DAY_OF_MONTH, day);
85                dates.add(c.getTime());
86              }
87            }
88          }
89  
90          ((DatabaseImpl)db).getPageChannel().startWrite();
91          try {
92            for(Date d : dates) {
93              table.addRow("row " + d, d);
94            }
95          } finally {
96            ((DatabaseImpl)db).getPageChannel().finishWrite();
97          }
98  
99          List<LocalDateTime> foundDates = new ArrayList<LocalDateTime>();
100         for(Row row : table) {
101           foundDates.add(row.getLocalDateTime("date"));
102         }
103 
104         assertEquals(dates.size(), foundDates.size());
105         for(int i = 0; i < dates.size(); ++i) {
106           Date expected = dates.get(i);
107           LocalDateTime found = foundDates.get(i);
108           assertSameDate(expected, found);
109         }
110 
111       }
112     }
113   }
114 
115   @Test
116   public void testAncientLocalDates() throws Exception
117   {
118     ZoneId zoneId = ZoneId.of("America/New_York");
119     DateTimeFormatter sdf = DateTimeFormatter.ofPattern("uuuu-MM-dd");
120 
121     List<String> dates = Arrays.asList("1582-10-15", "1582-10-14",
122                                        "1492-01-10", "1392-01-10");
123 
124     for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
125       try (Database db = createMem(fileFormat)) {
126         db.setZoneId(zoneId);
127         db.setDateTimeType(DateTimeType.LOCAL_DATE_TIME);
128 
129         Table table = newTable("test")
130           .addColumn(newColumn("name", DataType.TEXT))
131           .addColumn(newColumn("date", DataType.SHORT_DATE_TIME))
132           .toTable(db);
133 
134         for(String dateStr : dates) {
135           LocalDate ld = LocalDate.parse(dateStr, sdf);
136           table.addRow("row " + dateStr, ld);
137         }
138 
139         List<String> foundDates = new ArrayList<String>();
140         for(Row row : table) {
141           foundDates.add(sdf.format(row.getLocalDateTime("date")));
142         }
143 
144         assertEquals(dates, foundDates);
145 
146       }
147     }
148 
149     for (final TestDB testDB : TestDB.getSupportedForBasename(Basename.OLD_DATES)) {
150       try (Database db = openCopy(testDB)) {
151         db.setDateTimeType(DateTimeType.LOCAL_DATE_TIME);
152 
153         Table t = db.getTable("Table1");
154 
155         List<String> foundDates = new ArrayList<String>();
156         for(Row row : t) {
157           foundDates.add(sdf.format(row.getLocalDateTime("DateField")));
158         }
159 
160         assertEquals(dates, foundDates);
161 
162       }
163     }
164 
165   }
166 
167   @Test
168   public void testZoneId() throws Exception
169   {
170     ZoneId zoneId = ZoneId.of("America/New_York");
171     doTestZoneId(zoneId);
172 
173     zoneId = ZoneId.of("Australia/Sydney");
174     doTestZoneId(zoneId);
175   }
176 
177   private static void doTestZoneId(final ZoneId zoneId) throws Exception
178   {
179     final TimeZone tz = TimeZone.getTimeZone(zoneId);
180     ColumnImpl col = new ColumnImpl(null, null, DataType.SHORT_DATE_TIME, 0, 0, 0) {
181       @Override
182       public TimeZone getTimeZone() { return tz; }
183       @Override
184       public ZoneId getZoneId() { return zoneId; }
185       @Override
186       public ColumnImpl.DateTimeFactory getDateTimeFactory() {
187         return getDateTimeFactory(DateTimeType.LOCAL_DATE_TIME);
188       }
189     };
190 
191     SimpleDateFormat df = new SimpleDateFormat("yyyy.MM.dd");
192     df.setTimeZone(tz);
193 
194     long startDate = df.parse("2012.01.01").getTime();
195     long endDate = df.parse("2013.01.01").getTime();
196 
197     Calendar curCal = Calendar.getInstance(tz);
198     curCal.setTimeInMillis(startDate);
199 
200     DateTimeFormatter sdf = DateTimeFormatter.ofPattern("uuuu.MM.dd HH:mm:ss");
201 
202     while(curCal.getTimeInMillis() < endDate) {
203       Date curDate = curCal.getTime();
204       LocalDateTime curLdt = LocalDateTime.ofInstant(
205           Instant.ofEpochMilli(curDate.getTime()), zoneId);
206       LocalDateTime newLdt = ColumnImpl.ldtFromLocalDateDouble(
207           col.toDateDouble(curDate));
208       if(!curLdt.equals(newLdt)) {
209         System.out.println("FOO " + curLdt + " " + newLdt);
210         assertEquals(sdf.format(curLdt), sdf.format(newLdt));
211       }
212       curCal.add(Calendar.MINUTE, 30);
213     }
214   }
215 
216   @Test
217   public void testWriteAndReadTemporals() throws Exception {
218     ZoneId zoneId = ZoneId.of("America/New_York");
219     for (final FileFormat fileFormat : SUPPORTED_FILEFORMATS) {
220       try (Database db = createMem(fileFormat)) {
221         db.setZoneId(zoneId);
222         db.setDateTimeType(DateTimeType.LOCAL_DATE_TIME);
223 
224         Table table = newTable("test")
225           .addColumn(newColumn("name", DataType.TEXT))
226           .addColumn(newColumn("date", DataType.SHORT_DATE_TIME))
227           .toTable(db);
228 
229         // since jackcess does not really store millis, shave them off before
230         // storing the current date/time
231         long curTimeNoMillis = (System.currentTimeMillis() / 1000L);
232         curTimeNoMillis *= 1000L;
233 
234         DateFormat df = new SimpleDateFormat("yyyyMMdd HH:mm:ss");
235         List<Date> tmpDates =
236           new ArrayList<Date>(
237               Arrays.asList(
238                   df.parse("19801231 00:00:00"),
239                   df.parse("19930513 14:43:27"),
240                   df.parse("20210102 02:37:00"),
241                   new Date(curTimeNoMillis)));
242 
243         List<Object> objs = new ArrayList<Object>();
244         List<LocalDateTime> expected = new ArrayList<LocalDateTime>();
245         for(Date d : tmpDates) {
246           Instant inst = Instant.ofEpochMilli(d.getTime());
247           objs.add(inst);
248           ZonedDateTime zdt = inst.atZone(zoneId);
249           objs.add(zdt);
250           LocalDateTime ldt = zdt.toLocalDateTime();
251           objs.add(ldt);
252 
253           for(int i = 0; i < 3; ++i) {
254             expected.add(ldt);
255           }
256         }
257 
258         ((DatabaseImpl)db).getPageChannel().startWrite();
259         try {
260           for(Object o : objs) {
261             table.addRow("row " + o, o);
262           }
263         } finally {
264           ((DatabaseImpl)db).getPageChannel().finishWrite();
265         }
266 
267         List<LocalDateTime> foundDates = new ArrayList<LocalDateTime>();
268         for(Row row : table) {
269           foundDates.add(row.getLocalDateTime("date"));
270         }
271 
272         assertEquals(expected, foundDates);
273 
274       }
275     }
276   }
277 
278 }