@@ -12,6 +12,8 @@ import org.apache.poi.ss.usermodel.Sheet
12
12
import org.apache.poi.ss.usermodel.Workbook
13
13
import org.apache.poi.ss.usermodel.WorkbookFactory
14
14
import org.apache.poi.ss.util.CellReference
15
+ import org.apache.poi.util.LocaleUtil
16
+ import org.apache.poi.util.LocaleUtil.getUserTimeZone
15
17
import org.apache.poi.xssf.usermodel.XSSFWorkbook
16
18
import org.jetbrains.kotlinx.dataframe.AnyFrame
17
19
import org.jetbrains.kotlinx.dataframe.AnyRow
@@ -29,7 +31,8 @@ import java.io.OutputStream
29
31
import java.net.URL
30
32
import java.time.LocalDate
31
33
import java.time.LocalDateTime
32
- import java.util.*
34
+ import java.util.Calendar
35
+ import java.util.Date
33
36
34
37
public class Excel : SupportedFormat {
35
38
override fun readDataFrame (stream : InputStream , header : List <String >): AnyFrame = DataFrame .readExcel(stream)
@@ -215,8 +218,10 @@ public fun <T> DataFrame<T>.writeExcel(
215
218
val createHelper = wb.creationHelper
216
219
val cellStyleDate = wb.createCellStyle()
217
220
val cellStyleDateTime = wb.createCellStyle()
221
+ val cellStyleTime = wb.createCellStyle()
218
222
cellStyleDate.dataFormat = createHelper.createDataFormat().getFormat(" dd.mm.yyyy" )
219
223
cellStyleDateTime.dataFormat = createHelper.createDataFormat().getFormat(" dd.mm.yyyy hh:mm:ss" )
224
+ cellStyleTime.dataFormat = createHelper.createDataFormat().getFormat(" hh:mm:ss" )
220
225
221
226
columns.forEachRow {
222
227
val row = sheet.createRow(i)
@@ -232,9 +237,23 @@ public fun <T> DataFrame<T>.writeExcel(
232
237
is LocalDate , is kotlinx.datetime.LocalDate -> {
233
238
cell.cellStyle = cellStyleDate
234
239
}
235
- is LocalDateTime , is kotlinx.datetime. LocalDateTime , is Calendar , is Date -> {
240
+ is Calendar , is Date -> {
236
241
cell.cellStyle = cellStyleDateTime
237
242
}
243
+ is LocalDateTime -> {
244
+ if (any.year < 1900 ) {
245
+ cell.cellStyle = cellStyleTime
246
+ } else {
247
+ cell.cellStyle = cellStyleDateTime
248
+ }
249
+ }
250
+ is kotlinx.datetime.LocalDateTime -> {
251
+ if (any.year < 1900 ) {
252
+ cell.cellStyle = cellStyleTime
253
+ } else {
254
+ cell.cellStyle = cellStyleDateTime
255
+ }
256
+ }
238
257
else -> {}
239
258
}
240
259
}
@@ -259,16 +278,16 @@ private fun Cell.setCellValueByGuessedType(any: Any) {
259
278
this .setCellValue(any)
260
279
}
261
280
is LocalDateTime -> {
262
- this .setCellValue (any)
281
+ this .setTime (any)
263
282
}
264
283
is Boolean -> {
265
284
this .setCellValue(any)
266
285
}
267
286
is Calendar -> {
268
- this .setCellValue (any.time)
287
+ this .setDate (any.time)
269
288
}
270
289
is Date -> {
271
- this .setCellValue (any)
290
+ this .setDate (any)
272
291
}
273
292
is RichTextString -> {
274
293
this .setCellValue(any)
@@ -280,7 +299,7 @@ private fun Cell.setCellValueByGuessedType(any: Any) {
280
299
this .setCellValue(any.toJavaLocalDate())
281
300
}
282
301
is kotlinx.datetime.LocalDateTime -> {
283
- this .setCellValue (any.toJavaLocalDateTime())
302
+ this .setTime (any.toJavaLocalDateTime())
284
303
}
285
304
// Another option would be to serialize everything else to string,
286
305
// but people can convert columns to string with any serialization framework they want
@@ -290,3 +309,25 @@ private fun Cell.setCellValueByGuessedType(any: Any) {
290
309
}
291
310
}
292
311
}
312
+
313
+ /* *
314
+ * Set LocalDateTime value correctly also if date have zero value in Excel.
315
+ * Zero date is usually used fore storing time component only,
316
+ * is displayed as 00.01.1900 in Excel and as 30.12.1899 in LibreOffice Calc and also in POI.
317
+ * POI can not set 1899 year directly.
318
+ */
319
+ private fun Cell.setTime (localDateTime : LocalDateTime ) {
320
+ this .setCellValue(DateUtil .getExcelDate(localDateTime.plusDays(1 )) - 1.0 )
321
+ }
322
+
323
+ /* *
324
+ * Set Date value correctly also if date have zero value in Excel.
325
+ * Zero date is usually used fore storing time component only,
326
+ * is displayed as 00.01.1900 in Excel and as 30.12.1899 in LibreOffice Calc and also in POI.
327
+ * POI can not set 1899 year directly.
328
+ */
329
+ private fun Cell.setDate (date : Date ) {
330
+ val calStart = LocaleUtil .getLocaleCalendar()
331
+ calStart.time = date
332
+ this .setTime(calStart.toInstant().atZone(getUserTimeZone().toZoneId()).toLocalDateTime())
333
+ }
0 commit comments