Skip to content

Commit 1f5a81b

Browse files
authored
Fix DateTime export to csv with culture info (dotnet#7358)
1 parent 08b55c1 commit 1f5a81b

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

src/Microsoft.Data.Analysis/DataFrame.IO.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -719,6 +719,9 @@ private static void AppendValuesToRecord(StringBuilder record, IEnumerable value
719719
case decimal:
720720
record.AppendFormat(cultureInfo, "{0:G31}", value);
721721
continue;
722+
case DateTime:
723+
record.Append(((DateTime)value).ToString(cultureInfo));
724+
continue;
722725
case string stringCell:
723726
if (NeedsQuotes(stringCell, separator))
724727
{

test/Microsoft.Data.Analysis.Tests/DataFrame.IOTests.cs

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
using System.Threading.Tasks;
2020
using Xunit.Abstractions;
2121
using Microsoft.ML.TestFramework;
22+
using Microsoft.VisualStudio.TestPlatform.PlatformAbstractions.Interfaces;
2223

2324
namespace Microsoft.Data.Analysis.Tests
2425
{
@@ -1017,16 +1018,15 @@ public void TestSaveCsvWithCultureInfoRomanianAndSemiColon()
10171018
DataFrame.SaveCsv(dataFrame, csvStream, separator: separator, cultureInfo: cultureInfo);
10181019

10191020
csvStream.Seek(0, SeekOrigin.Begin);
1020-
DataFrame readIn = DataFrame.LoadCsv(csvStream, separator: separator);
1021+
DataFrame readIn = DataFrame.LoadCsv(csvStream, separator: separator, cultureInfo: cultureInfo);
10211022

10221023
Assert.Equal(dataFrame.Rows.Count, readIn.Rows.Count);
10231024
Assert.Equal(dataFrame.Columns.Count, readIn.Columns.Count);
10241025
Assert.Equal(1F, readIn[1, 0]);
10251026

1026-
// LoadCsv does not support culture info, therefore decimal point comma (,) is seen as thousand separator and is ignored when read
1027-
Assert.Equal(11F, readIn[1, 1]);
1028-
Assert.Equal(12F, readIn[1, 2]);
1029-
Assert.Equal(129999992F, readIn[1, 3]);
1027+
Assert.Equal(1.1F, readIn[1, 1]);
1028+
Assert.Equal(1.2F, readIn[1, 2]);
1029+
Assert.Equal(1.3F, readIn[1, 3]);
10301030

10311031
Assert.Equal(1F, readIn[1, 4]);
10321032
Assert.Equal(1F, readIn[1, 5]);
@@ -1079,6 +1079,63 @@ public void TestSaveCsvWithCultureInfoRomanianAndComma()
10791079
Assert.Throws<ArgumentException>(() => DataFrame.SaveCsv(dataFrame, csvStream, separator: separator, cultureInfo: cultureInfo));
10801080
}
10811081

1082+
[Fact]
1083+
public void TestSaveCsvWithCultureInfoAndDateTimeColumn()
1084+
{
1085+
using MemoryStream csvStream = new MemoryStream();
1086+
var dateColumn = new DateTimeDataFrameColumn("Date", 3);
1087+
DataFrame dataFrame = new DataFrame();
1088+
dataFrame.Columns.Add(dateColumn);
1089+
dateColumn[0] = DateTime.Today;
1090+
dateColumn[1] = DateTime.Today.AddDays(1);
1091+
dateColumn[2] = null;
1092+
1093+
var cultureInfo = new CultureInfo("en-US");
1094+
cultureInfo.DateTimeFormat.LongDatePattern = "yyyy-MM-dd";
1095+
cultureInfo.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd";
1096+
cultureInfo.DateTimeFormat.LongTimePattern = "HH:mm:ss";
1097+
cultureInfo.DateTimeFormat.ShortTimePattern = "HH:mm:ss";
1098+
1099+
DataFrame.SaveCsv(dataFrame, csvStream, cultureInfo: cultureInfo, header: false);
1100+
1101+
csvStream.Seek(0, SeekOrigin.Begin);
1102+
1103+
StreamReader reader = new StreamReader(csvStream);
1104+
var text = reader.ReadToEnd().Split(["\r\n", "\r", "\n"], StringSplitOptions.None);
1105+
1106+
Assert.Equal(dateColumn[0].Value.ToString(cultureInfo), text[0]);
1107+
Assert.Equal(dateColumn[1].Value.ToString(cultureInfo), text[1]);
1108+
Assert.True(string.IsNullOrEmpty(text[2]));
1109+
}
1110+
1111+
[Fact]
1112+
public void TestSaveAndReadCsvWithCultureInfoAndDateTimeColumn()
1113+
{
1114+
using MemoryStream csvStream = new MemoryStream();
1115+
var dateColumn = new DateTimeDataFrameColumn("Date", 3);
1116+
DataFrame dataFrame = new DataFrame();
1117+
dataFrame.Columns.Add(dateColumn);
1118+
dateColumn[0] = DateTime.Today;
1119+
dateColumn[1] = DateTime.Today.AddDays(1);
1120+
dateColumn[2] = DateTime.Today.AddDays(2);
1121+
1122+
var cultureInfo = new CultureInfo("en-US");
1123+
cultureInfo.DateTimeFormat.LongDatePattern = "yyyy-MM-dd";
1124+
cultureInfo.DateTimeFormat.ShortDatePattern = "yyyy-MM-dd";
1125+
cultureInfo.DateTimeFormat.LongTimePattern = "HH:mm:ss";
1126+
cultureInfo.DateTimeFormat.ShortTimePattern = "HH:mm:ss";
1127+
1128+
DataFrame.SaveCsv(dataFrame, csvStream, cultureInfo: cultureInfo, header: true);
1129+
1130+
csvStream.Seek(0, SeekOrigin.Begin);
1131+
1132+
DataFrame readIn = DataFrame.LoadCsv(csvStream, cultureInfo: cultureInfo);
1133+
1134+
Assert.Equal(dateColumn[0], readIn[0, 0]);
1135+
Assert.Equal(dateColumn[1], readIn[1, 0]);
1136+
Assert.Equal(dateColumn[2], readIn[2, 0]);
1137+
}
1138+
10821139
[Fact]
10831140
public void TestSaveCsvWithNoHeader()
10841141
{

0 commit comments

Comments
 (0)