Skip to content

Commit

Permalink
fix: exporting data with local timezone
Browse files Browse the repository at this point in the history
fixes #978
  • Loading branch information
TheSlimvReal authored Sep 9, 2021
1 parent aedee69 commit 6731962
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 7 deletions.
50 changes: 49 additions & 1 deletion src/app/core/export/export-service/export.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { School } from "../../../child-dev-project/schools/model/school";
import { ChildSchoolRelation } from "../../../child-dev-project/children/model/childSchoolRelation";
import { ExportColumnConfig } from "./export-column-config";
import { defaultAttendanceStatusTypes } from "../../config/default-config/default-attendance-status-types";
import moment from "moment";

describe("ExportService", () => {
let service: ExportService;
Expand Down Expand Up @@ -165,7 +166,9 @@ describe("ExportService", () => {
const columnValues = rows[1].split(ExportService.SEPARATOR_COL);
expect(columnValues).toHaveSize(3 + 1); // Properties + _id
expect(columnValues).toContain('"' + testEnumValue.label + '"');
expect(columnValues).toContain(new Date(testDate).toISOString());
expect(columnValues).toContain(
'"' + moment(new Date(testDate)).toISOString(true) + '"'
);
expect(columnValues).toContain('"true"');
});

Expand Down Expand Up @@ -264,6 +267,32 @@ describe("ExportService", () => {
]);
});

it("should export a date according to the local format", async () => {
// Create date at midnight on first of january 2021
const dateString = "2021-01-01";
const dateObject = new Date(dateString);
dateObject.setHours(0, 0, 0);

const exportData = [
{
date: dateObject,
number: 10,
string: "someString",
},
];

const csv = await service.createCsv(exportData);

const results = csv.split(ExportService.SEPARATOR_ROW);
// Format: yyyy-mm-ddThh:mm:ss.mmm+hh:mm
const expectedDateFormat =
dateString + "T00:00:00.000" + getTimezoneOffset(dateObject);
expect(results).toEqual([
'"date","number","string"',
`"${expectedDateFormat}","10","someString"`,
]);
});

async function createChildInDB(name: string): Promise<Child> {
const child = new Child();
child.name = name;
Expand Down Expand Up @@ -308,4 +337,23 @@ describe("ExportService", () => {

return school;
}

/**
* Returns the timezone offset in hours and minutes.
* E.g. german date object => "+02:00" or "+01:00" depending on time of the year
* @param date object for which the offset should be calculated
*/
function getTimezoneOffset(date: Date): string {
// from https://usefulangle.com/post/30/javascript-get-date-time-with-offset-hours-minutes
const offset = date.getTimezoneOffset();

const offsetHrs = parseInt(Math.abs(offset / 60).toString(), 10);
const offsetMin = Math.abs(offset % 60);

const hrsString = offsetHrs > 10 ? offsetHrs.toString() : "0" + offsetHrs;
const minString = offsetMin > 10 ? offsetMin.toString() : "0" + offsetMin;

const sign = offset > 0 ? "-" : "+";
return sign + hrsString + ":" + minString;
}
});
17 changes: 11 additions & 6 deletions src/app/core/export/export-service/export.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Papa } from "ngx-papaparse";
import { entityListSortingAccessor } from "../../entity-components/entity-subrecord/entity-subrecord/sorting-accessor";
import { ExportColumnConfig } from "./export-column-config";
import { QueryService } from "../../../features/reporting/query.service";
import moment from "moment";

/**
* Prepare data for export in csv format.
Expand Down Expand Up @@ -35,11 +36,10 @@ export class ExportService {
* @param config (Optional) config specifying which fields should be exported
* @returns string a valid CSV string of the input data
*/
async createCsv(data: any[], config?: ExportColumnConfig[]): Promise<string> {
if (!config) {
config = this.generateExportConfigFromData(data);
}

async createCsv(
data: any[],
config: ExportColumnConfig[] = this.generateExportConfigFromData(data)
): Promise<string> {
const flattenedExportRows: ExportRow[] = [];
for (const dataRow of data) {
const extendedExportableRows = await this.generateExportRows(
Expand All @@ -53,7 +53,12 @@ export class ExportService {
const readableExportRow = flattenedExportRows.map((row) => {
const readableRow = {};
Object.keys(row).forEach((key) => {
readableRow[key] = entityListSortingAccessor(row, key);
if (row[key] instanceof Date) {
// Export data according to local timezone offset
readableRow[key] = moment(row[key]).toISOString(true);
} else {
readableRow[key] = entityListSortingAccessor(row, key);
}
});
return readableRow;
});
Expand Down

0 comments on commit 6731962

Please sign in to comment.