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:
parent
95e799880c
commit
165ab2b876
@ -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,
|
||||||
});
|
});
|
||||||
|
@ -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';
|
||||||
|
|
||||||
|
@ -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 (
|
||||||
|
@ -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', () => {
|
||||||
@ -7,12 +8,12 @@ describe('str2moment', () => {
|
|||||||
const m = str2moment('2022-06-21T00:00:00.000Z', { gmt: true });
|
const m = str2moment('2022-06-21T00:00:00.000Z', { gmt: true });
|
||||||
expect(m.format('YYYY-MM-DD HH:mm:ss')).toBe('2022-06-21 00:00:00');
|
expect(m.format('YYYY-MM-DD HH:mm:ss')).toBe('2022-06-21 00:00:00');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('local date', async () => {
|
test('local date', async () => {
|
||||||
const m = str2moment('2022-06-21T00:00:00.000Z');
|
const m = str2moment('2022-06-21T00:00:00.000Z');
|
||||||
expect(m.toISOString()).toBe('2022-06-21T00:00:00.000Z');
|
expect(m.toISOString()).toBe('2022-06-21T00:00:00.000Z');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('value is null', async () => {
|
test('value is null', async () => {
|
||||||
const m = str2moment(null);
|
const m = str2moment(null);
|
||||||
expect(m).toBeNull();
|
expect(m).toBeNull();
|
||||||
@ -31,7 +32,7 @@ describe('str2moment', () => {
|
|||||||
expect(m.format('YYYY-MM-DD HH:mm:ss')).toBe('2022-06-21 00:00:00');
|
expect(m.format('YYYY-MM-DD HH:mm:ss')).toBe('2022-06-21 00:00:00');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test('local date', async () => {
|
test('local date', async () => {
|
||||||
const arr = str2moment(['2022-06-21T00:00:00.000Z', '2022-06-21T00:00:00.000Z']);
|
const arr = str2moment(['2022-06-21T00:00:00.000Z', '2022-06-21T00:00:00.000Z']);
|
||||||
for (const m of arr) {
|
for (const m of arr) {
|
||||||
|
@ -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;
|
||||||
|
@ -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"
|
||||||
}
|
}
|
||||||
|
@ -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';
|
||||||
|
78
packages/core/utils/src/date.ts
Normal file
78
packages/core/utils/src/date.ts
Normal 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;
|
||||||
|
};
|
@ -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';
|
||||||
|
@ -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';
|
||||||
|
@ -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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user