fix: fix date format (#686)

* fix: fix date format

* fix: fix date format

* fix: export date

* fix: get current timezone

* fix: datetime render

* fix: gmt

* fix: gmt date

* fix: utf offset

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
SemmyWong 2022-07-28 17:32:31 +08:00 committed by GitHub
parent 95e799880c
commit 165ab2b876
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 112 additions and 86 deletions

View File

@ -37,6 +37,12 @@ export interface ApplicationOptions {
plugins?: any[]; plugins?: any[];
} }
export const getCurrentTimezone = () => {
const timezoneOffset = new Date().getTimezoneOffset() / -60;
const timezone = String(timezoneOffset).padStart(2, '0') + ':00';
return (timezoneOffset > 0 ? '+' : '-') + timezone;
};
export type PluginCallback = () => Promise<any>; export type PluginCallback = () => Promise<any>;
export class Application { export class Application {
@ -51,6 +57,7 @@ export class Application {
baseURL: process.env.API_BASE_URL, baseURL: process.env.API_BASE_URL,
headers: { headers: {
'X-Hostname': window?.location?.hostname, 'X-Hostname': window?.location?.hostname,
'X-Timezone': getCurrentTimezone(),
}, },
...options.apiClient, ...options.apiClient,
}); });

View File

@ -1,10 +1,10 @@
import React from 'react'; import { connect, mapProps, mapReadPretty } from '@formily/react';
import { DatePicker as AntdDatePicker } from 'antd'; import { DatePicker as AntdDatePicker } from 'antd';
import type { import type {
DatePickerProps as AntdDatePickerProps, DatePickerProps as AntdDatePickerProps,
RangePickerProps as AntdRangePickerProps, RangePickerProps as AntdRangePickerProps
} from 'antd/lib/date-picker'; } from 'antd/lib/date-picker';
import { connect, mapProps, mapReadPretty } from '@formily/react'; import React from 'react';
import { ReadPretty } from './ReadPretty'; import { ReadPretty } from './ReadPretty';
import { mapDateFormat } from './util'; import { mapDateFormat } from './util';

View File

@ -1,5 +1,6 @@
import { usePrefixCls } from '@formily/antd/lib/__builtins__'; import { usePrefixCls } from '@formily/antd/lib/__builtins__';
import { isArr } from '@formily/shared'; import { isArr } from '@formily/shared';
import { getDefaultFormat, str2moment } from '@nocobase/utils/client';
import type { import type {
DatePickerProps as AntdDatePickerProps, DatePickerProps as AntdDatePickerProps,
RangePickerProps as AntdRangePickerProps RangePickerProps as AntdRangePickerProps
@ -7,7 +8,6 @@ import type {
import cls from 'classnames'; import cls from 'classnames';
import moment from 'moment'; import moment from 'moment';
import React from 'react'; import React from 'react';
import { getDefaultFormat, str2moment } from './util';
type Composed = { type Composed = {
DatePicker: React.FC<AntdDatePickerProps>; DatePicker: React.FC<AntdDatePickerProps>;
@ -38,7 +38,7 @@ ReadPretty.DateRangePicker = (props: any) => {
if (!m) { if (!m) {
return ''; return '';
} }
const labels = m.map(m => m.format(format)); const labels = m.map((m) => m.format(format));
return isArr(labels) ? labels.join('~') : labels; return isArr(labels) ? labels.join('~') : labels;
}; };
return ( return (

View File

@ -1,5 +1,6 @@
import { str2moment } from '@nocobase/utils';
import moment from 'moment'; import moment from 'moment';
import { moment2str, str2moment } from '../util'; import { moment2str } from '../util';
describe('str2moment', () => { describe('str2moment', () => {
describe('string value', () => { describe('string value', () => {

View File

@ -1,18 +1,6 @@
import type { DatePickerProps } from 'antd/lib/date-picker'; import { getDefaultFormat, str2moment, toGmt, toLocal } from '@nocobase/utils/client';
import moment from 'moment'; import moment from 'moment';
const toGmt = (value: moment.Moment | moment.Moment[]) => {
if (!value) {
return value;
}
if (Array.isArray(value)) {
return value.map((val) => `${val.format('YYYY-MM-DD')}T${val.format('HH:mm:ss.SSS')}Z`);
}
if (moment.isMoment(value)) {
return `${value.format('YYYY-MM-DD')}T${value.format('HH:mm:ss.SSS')}Z`;
}
};
const toStringByPicker = (value, picker) => { const toStringByPicker = (value, picker) => {
if (picker === 'year') { if (picker === 'year') {
return value.format('YYYY') + '-01-01T00:00:00.000Z'; return value.format('YYYY') + '-01-01T00:00:00.000Z';
@ -41,45 +29,6 @@ const toGmtByPicker = (value: moment.Moment | moment.Moment[], picker?: any) =>
} }
}; };
const toLocal = (value: moment.Moment | moment.Moment[]) => {
if (!value) {
return value;
}
if (Array.isArray(value)) {
return value.map((val) => val.toISOString());
}
if (moment.isMoment(value)) {
return value.toISOString();
}
};
export interface Str2momentOptions {
gmt?: boolean;
picker?: 'year' | 'month' | 'week' | 'quarter';
}
const toMoment = (val: any, options?: Str2momentOptions) => {
if (moment.isMoment(val)) {
return val;
}
const { gmt, picker } = options;
if (gmt || picker) {
val = val.replace('T', ' ').replace('Z', '');
return moment(val);
}
return moment(val);
};
export const str2moment = (value?: string | string[], options: Str2momentOptions = {}): any => {
return Array.isArray(value)
? value.map((val) => {
return toMoment(val, options);
})
: value
? toMoment(value, options)
: value;
};
export interface Moment2strOptions { export interface Moment2strOptions {
showTime?: boolean; showTime?: boolean;
gmt?: boolean; gmt?: boolean;
@ -97,28 +46,6 @@ export const moment2str = (value?: moment.Moment | moment.Moment[], options: Mom
return toGmtByPicker(value, picker); return toGmtByPicker(value, picker);
}; };
export const getDefaultFormat = (props: DatePickerProps & { dateFormat: string; timeFormat: string }) => {
if (props.format) {
return props.format;
}
if (props.dateFormat) {
if (props['showTime']) {
return `${props.dateFormat} ${props.timeFormat || 'HH:mm:ss'}`;
}
return props.dateFormat;
}
if (props['picker'] === 'month') {
return 'YYYY-MM';
} else if (props['picker'] === 'quarter') {
return 'YYYY-\\QQ';
} else if (props['picker'] === 'year') {
return 'YYYY';
} else if (props['picker'] === 'week') {
return 'YYYY-wo';
}
return props['showTime'] ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
};
export const mapDateFormat = function () { export const mapDateFormat = function () {
return (props: any) => { return (props: any) => {
const format = getDefaultFormat(props) as any; const format = getDefaultFormat(props) as any;

View File

@ -14,5 +14,9 @@
"deepmerge": "^4.2.2", "deepmerge": "^4.2.2",
"flat-to-nested": "^1.1.1" "flat-to-nested": "^1.1.1"
}, },
"peerDependencies": {
"moment": "2.x",
"rc-input-number": "7.x"
},
"gitHead": "7e9556e489007577fc0ed89063b3a9ce2f9aae53" "gitHead": "7e9556e489007577fc0ed89063b3a9ce2f9aae53"
} }

View File

@ -1,3 +1,4 @@
export * from './date';
export * from './merge'; export * from './merge';
export * from './number'; export * from './number';
export * from './registry'; export * from './registry';

View File

@ -0,0 +1,78 @@
import moment from 'moment';
export interface Str2momentOptions {
gmt?: boolean;
picker?: 'year' | 'month' | 'week' | 'quarter';
utcOffset?: any;
}
export const getDefaultFormat = (props: any) => {
if (props.format) {
return props.format;
}
if (props.dateFormat) {
if (props['showTime']) {
return `${props.dateFormat} ${props.timeFormat || 'HH:mm:ss'}`;
}
return props.dateFormat;
}
if (props['picker'] === 'month') {
return 'YYYY-MM';
} else if (props['picker'] === 'quarter') {
return 'YYYY-\\QQ';
} else if (props['picker'] === 'year') {
return 'YYYY';
} else if (props['picker'] === 'week') {
return 'YYYY-wo';
}
return props['showTime'] ? 'YYYY-MM-DD HH:mm:ss' : 'YYYY-MM-DD';
};
export const toGmt = (value: moment.Moment | moment.Moment[]) => {
if (!value) {
return value;
}
if (Array.isArray(value)) {
return value.map((val) => `${val.format('YYYY-MM-DD')}T${val.format('HH:mm:ss.SSS')}Z`);
}
if (moment.isMoment(value)) {
return `${value.format('YYYY-MM-DD')}T${value.format('HH:mm:ss.SSS')}Z`;
}
};
export const toLocal = (value: moment.Moment | moment.Moment[]) => {
if (!value) {
return value;
}
if (Array.isArray(value)) {
return value.map((val) => val.toISOString());
}
if (moment.isMoment(value)) {
return value.toISOString();
}
};
const toMoment = (val: any, options?: Str2momentOptions) => {
if (!val) {
return;
}
const offset = options.utcOffset || -1 * new Date().getTimezoneOffset();
if (moment.isMoment(val)) {
return val.utcOffset(offset);
}
const { gmt, picker } = options;
if (gmt || picker) {
return moment(val).utcOffset(0);
}
return moment(val).utcOffset(offset);
};
export const str2moment = (value?: string | string[], options: Str2momentOptions = {}): any => {
return Array.isArray(value)
? value.map((val) => {
return toMoment(val, options);
})
: value
? toMoment(value, options)
: value;
};

View File

@ -1,3 +1,4 @@
export * from './date';
export * from './merge'; export * from './merge';
export * from './mixin'; export * from './mixin';
export * from './mixin/AsyncEmitter'; export * from './mixin/AsyncEmitter';

View File

@ -1,3 +1,4 @@
export * from './date';
export * from './merge'; export * from './merge';
export * from './mixin'; export * from './mixin';
export * from './mixin/AsyncEmitter'; export * from './mixin/AsyncEmitter';

View File

@ -1,5 +1,4 @@
import { toFixedByStep } from '@nocobase/utils'; import { getDefaultFormat, str2moment } from '@nocobase/utils';
import moment from 'moment';
export async function _(field, row, ctx, column?: any) { export async function _(field, row, ctx, column?: any) {
if (column?.dataIndex.length > 1) { if (column?.dataIndex.length > 1) {
@ -34,7 +33,14 @@ export async function _(field, row, ctx, column?: any) {
export async function datetime(field, row, ctx) { export async function datetime(field, row, ctx) {
const value = row.get(field.name); const value = row.get(field.name);
return moment(value).format(field.showTime ? `${field.dateFormat} ${field.timeFormat}` : field.dateFormat); if (!value) {
return '';
}
const utcOffset = ctx.get('X-Timezone');
const props = field.options?.uiSchema?.['x-component-props'] ?? {};
const format = getDefaultFormat(props);
const m = str2moment(value, { ...props, utcOffset });
return m ? m.format(format) : '';
} }
export async function percent(field, row, ctx) { export async function percent(field, row, ctx) {