(core) Set DateTime timezone during xlsx import

Summary:
DateTime columns had a blank timezone after xlsx imports because the
timezone was not included in the column type. We now append the
document's timezone to the type of all imported DateTime columns.

Test Plan: Server test.

Reviewers: jarek

Reviewed By: jarek

Differential Revision: https://phab.getgrist.com/D3896
This commit is contained in:
George Gevoian 2023-05-23 22:53:20 -04:00
parent d5b8240c07
commit ff03d32688
3 changed files with 19 additions and 0 deletions

View File

@ -98,6 +98,14 @@ export function formatRelBounds(periods: IPeriod[]): string {
); );
} }
/**
* Returns a new timestamp that is the UTC equivalent of the original local `timestamp`, offset
* according to the delta between`timezone` and UTC.
*/
export function localTimestampToUTC(timestamp: number, timezone: string): number {
return moment.unix(timestamp).utc().tz(timezone, true).unix();
}
function formatDay(quantity: number, refUnit: IPeriod['unit']): string { function formatDay(quantity: number, refUnit: IPeriod['unit']): string {
if (refUnit === 'week') { if (refUnit === 'week') {

View File

@ -11,6 +11,7 @@ import {ApplyUAResult, DataSourceTransformed, ImportOptions, ImportResult, Impor
import {ApiError} from 'app/common/ApiError'; import {ApiError} from 'app/common/ApiError';
import {BulkColValues, CellValue, fromTableDataAction, UserAction} from 'app/common/DocActions'; import {BulkColValues, CellValue, fromTableDataAction, UserAction} from 'app/common/DocActions';
import * as gutil from 'app/common/gutil'; import * as gutil from 'app/common/gutil';
import {localTimestampToUTC} from 'app/common/RelativeDates';
import {DocStateComparison} from 'app/common/UserAPI'; import {DocStateComparison} from 'app/common/UserAPI';
import {guessColInfoForImports} from 'app/common/ValueGuesser'; import {guessColInfoForImports} from 'app/common/ValueGuesser';
import {ParseFileResult, ParseOptions} from 'app/plugin/FileParserAPI'; import {ParseFileResult, ParseOptions} from 'app/plugin/FileParserAPI';
@ -689,6 +690,7 @@ function getMergeFunction({type}: MergeStrategy): MergeFunction {
* columns using the values set for the column ids. * columns using the values set for the column ids.
* For columns of type Any, guess the type and parse data according to it, or mark as empty * For columns of type Any, guess the type and parse data according to it, or mark as empty
* formula columns when they should be empty. * formula columns when they should be empty.
* For columns of type DateTime, add the document timezone to the type.
*/ */
function cleanColumnMetadata(columns: GristColumn[], tableData: unknown[][], activeDoc: ActiveDoc) { function cleanColumnMetadata(columns: GristColumn[], tableData: unknown[][], activeDoc: ActiveDoc) {
return columns.map((c, index) => { return columns.map((c, index) => {
@ -706,6 +708,15 @@ function cleanColumnMetadata(columns: GristColumn[], tableData: unknown[][], act
Object.assign(newCol, colMetadata); Object.assign(newCol, colMetadata);
} }
} }
const timezone = activeDoc.docData!.docInfo().timezone;
if (c.type === "DateTime" && timezone) {
newCol.type = `DateTime:${timezone}`;
for (const [i, localTimestamp] of tableData[index].entries()) {
if (typeof localTimestamp !== 'number') { continue; }
tableData[index][i] = localTimestampToUTC(localTimestamp, timezone);
}
}
return newCol; return newCol;
}); });
} }

BIN
test/fixtures/uploads/DateTimeData.xlsx vendored Normal file

Binary file not shown.