feat: datetimes with timezones

This commit is contained in:
2025-08-24 14:54:10 +04:00
parent d5be9ce61a
commit e5602551c5
7 changed files with 53 additions and 4 deletions

View File

@ -11,9 +11,11 @@ export default defineConfig({
{ {
name: "zod", name: "zod",
requests: true, requests: true,
responses: true,
definitions: true, definitions: true,
metadata: true, metadata: true,
dates: {
offset: true,
},
}, },
{ {
name: "@hey-api/sdk", name: "@hey-api/sdk",

View File

@ -25,6 +25,8 @@
"@tanstack/react-query": "^5.83.0", "@tanstack/react-query": "^5.83.0",
"axios": "^1.11.0", "axios": "^1.11.0",
"classnames": "^2.5.1", "classnames": "^2.5.1",
"date-fns": "^4.1.0",
"date-fns-tz": "^3.2.0",
"framer-motion": "^12.23.7", "framer-motion": "^12.23.7",
"i18n-iso-countries": "^7.14.0", "i18n-iso-countries": "^7.14.0",
"lexorank": "^1.0.5", "lexorank": "^1.0.5",

View File

@ -1,9 +1,10 @@
import { FC, useState } from "react"; import { FC, useState } from "react";
import { isEqual } from "lodash"; import { isEqual } from "lodash";
import { Button, Group, Stack, TextInput } from "@mantine/core"; import { Button, Group, Stack, Text, TextInput } from "@mantine/core";
import { useForm } from "@mantine/form"; import { useForm } from "@mantine/form";
import { DealsCrud } from "@/hooks/cruds/useDealsCrud"; import { DealsCrud } from "@/hooks/cruds/useDealsCrud";
import { DealSchema } from "@/lib/client"; import { DealSchema } from "@/lib/client";
import { utcDateTimeToLocalString } from "@/utils/datetime";
type Props = { type Props = {
dealsCrud: DealsCrud; dealsCrud: DealsCrud;
@ -36,8 +37,11 @@ const GeneralTab: FC<Props> = ({ deal, dealsCrud, onClose }) => {
label={"Название"} label={"Название"}
{...form.getInputProps("name")} {...form.getInputProps("name")}
/> />
<Group justify={"space-between"}> <Text>Создано: {utcDateTimeToLocalString(deal.createdAt)}</Text>
<Group> <Group
justify={"space-between"}
wrap={"nowrap"}>
<Group wrap={"nowrap"}>
<Button <Button
type={"submit"} type={"submit"}
disabled={isEqual(form.values, initialValues)} disabled={isEqual(form.values, initialValues)}

View File

@ -178,6 +178,10 @@ export type DealSchema = {
* Statusid * Statusid
*/ */
statusId: number; statusId: number;
/**
* Createdat
*/
createdAt: string;
}; };
/** /**

View File

@ -60,6 +60,9 @@ export const zDealSchema = z.object({
name: z.string(), name: z.string(),
lexorank: z.string(), lexorank: z.string(),
statusId: z.int(), statusId: z.int(),
createdAt: z.iso.datetime({
offset: true,
}),
}); });
/** /**

16
src/utils/datetime.ts Normal file
View File

@ -0,0 +1,16 @@
import { formatInTimeZone } from "date-fns-tz";
export const utcDateToLocal = (datetime: string | Date) => {
const userTZ = Intl.DateTimeFormat().resolvedOptions().timeZone;
const localTime = formatInTimeZone(datetime, userTZ, "yyyy-MM-dd HH:mm:ss");
return new Date(localTime);
};
export const localDateTimeToString = (datetime: string | Date) => {
const date = new Date(datetime);
return date.toLocaleString("ru").substring(0, 17);
};
export const utcDateTimeToLocalString = (datetime: string | Date) => {
return localDateTimeToString(utcDateToLocal(datetime));
};

View File

@ -6136,6 +6136,8 @@ __metadata:
axios: "npm:^1.11.0" axios: "npm:^1.11.0"
babel-loader: "npm:^10.0.0" babel-loader: "npm:^10.0.0"
classnames: "npm:^2.5.1" classnames: "npm:^2.5.1"
date-fns: "npm:^4.1.0"
date-fns-tz: "npm:^3.2.0"
eslint: "npm:^9.29.0" eslint: "npm:^9.29.0"
eslint-config-mantine: "npm:^4.0.3" eslint-config-mantine: "npm:^4.0.3"
eslint-plugin-eslint-comments: "npm:^3.2.0" eslint-plugin-eslint-comments: "npm:^3.2.0"
@ -6346,6 +6348,22 @@ __metadata:
languageName: node languageName: node
linkType: hard linkType: hard
"date-fns-tz@npm:^3.2.0":
version: 3.2.0
resolution: "date-fns-tz@npm:3.2.0"
peerDependencies:
date-fns: ^3.0.0 || ^4.0.0
checksum: 10c0/3f43300a4335d59f3515dc5196c66b4b56ef2af129eb82e4445ce0983e8ef31a5d038bc0406d669946bbbcf52ed953527527aa28b4a810995d6631a54655abcc
languageName: node
linkType: hard
"date-fns@npm:^4.1.0":
version: 4.1.0
resolution: "date-fns@npm:4.1.0"
checksum: 10c0/b79ff32830e6b7faa009590af6ae0fb8c3fd9ffad46d930548fbb5acf473773b4712ae887e156ba91a7b3dc30591ce0f517d69fd83bd9c38650fdc03b4e0bac8
languageName: node
linkType: hard
"debounce@npm:^1.2.1": "debounce@npm:^1.2.1":
version: 1.2.1 version: 1.2.1
resolution: "debounce@npm:1.2.1" resolution: "debounce@npm:1.2.1"