Skip to content

Commit 0430206

Browse files
KopilovKopilov
authored andcommitted
Zero date support
1 parent ea0150c commit 0430206

File tree

1 file changed

+47
-6
lines changed
  • src/main/kotlin/org/jetbrains/kotlinx/dataframe/io

1 file changed

+47
-6
lines changed

src/main/kotlin/org/jetbrains/kotlinx/dataframe/io/xlsx.kt

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ import org.apache.poi.ss.usermodel.Sheet
1212
import org.apache.poi.ss.usermodel.Workbook
1313
import org.apache.poi.ss.usermodel.WorkbookFactory
1414
import org.apache.poi.ss.util.CellReference
15+
import org.apache.poi.util.LocaleUtil
16+
import org.apache.poi.util.LocaleUtil.getUserTimeZone
1517
import org.apache.poi.xssf.usermodel.XSSFWorkbook
1618
import org.jetbrains.kotlinx.dataframe.AnyFrame
1719
import org.jetbrains.kotlinx.dataframe.AnyRow
@@ -29,7 +31,8 @@ import java.io.OutputStream
2931
import java.net.URL
3032
import java.time.LocalDate
3133
import java.time.LocalDateTime
32-
import java.util.*
34+
import java.util.Calendar
35+
import java.util.Date
3336

3437
public class Excel : SupportedFormat {
3538
override fun readDataFrame(stream: InputStream, header: List<String>): AnyFrame = DataFrame.readExcel(stream)
@@ -215,8 +218,10 @@ public fun <T> DataFrame<T>.writeExcel(
215218
val createHelper = wb.creationHelper
216219
val cellStyleDate = wb.createCellStyle()
217220
val cellStyleDateTime = wb.createCellStyle()
221+
val cellStyleTime = wb.createCellStyle()
218222
cellStyleDate.dataFormat = createHelper.createDataFormat().getFormat("dd.mm.yyyy")
219223
cellStyleDateTime.dataFormat = createHelper.createDataFormat().getFormat("dd.mm.yyyy hh:mm:ss")
224+
cellStyleTime.dataFormat = createHelper.createDataFormat().getFormat("hh:mm:ss")
220225

221226
columns.forEachRow {
222227
val row = sheet.createRow(i)
@@ -232,9 +237,23 @@ public fun <T> DataFrame<T>.writeExcel(
232237
is LocalDate, is kotlinx.datetime.LocalDate -> {
233238
cell.cellStyle = cellStyleDate
234239
}
235-
is LocalDateTime, is kotlinx.datetime.LocalDateTime, is Calendar, is Date -> {
240+
is Calendar, is Date -> {
236241
cell.cellStyle = cellStyleDateTime
237242
}
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+
}
238257
else -> {}
239258
}
240259
}
@@ -259,16 +278,16 @@ private fun Cell.setCellValueByGuessedType(any: Any) {
259278
this.setCellValue(any)
260279
}
261280
is LocalDateTime -> {
262-
this.setCellValue(any)
281+
this.setTime(any)
263282
}
264283
is Boolean -> {
265284
this.setCellValue(any)
266285
}
267286
is Calendar -> {
268-
this.setCellValue(any.time)
287+
this.setDate(any.time)
269288
}
270289
is Date -> {
271-
this.setCellValue(any)
290+
this.setDate(any)
272291
}
273292
is RichTextString -> {
274293
this.setCellValue(any)
@@ -280,7 +299,7 @@ private fun Cell.setCellValueByGuessedType(any: Any) {
280299
this.setCellValue(any.toJavaLocalDate())
281300
}
282301
is kotlinx.datetime.LocalDateTime -> {
283-
this.setCellValue(any.toJavaLocalDateTime())
302+
this.setTime(any.toJavaLocalDateTime())
284303
}
285304
// Another option would be to serialize everything else to string,
286305
// but people can convert columns to string with any serialization framework they want
@@ -290,3 +309,25 @@ private fun Cell.setCellValueByGuessedType(any: Any) {
290309
}
291310
}
292311
}
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

Comments
 (0)