Viktoriia 2 недель назад
Родитель
Сommit
9d5501ff1d
2 измененных файлов с 99 добавлено и 0 удалено
  1. 1 0
      App.tsx
  2. 98 0
      src/utils/dayjsTimezoneFix.ts

+ 1 - 0
App.tsx

@@ -1,3 +1,4 @@
+import './src/utils/dayjsTimezoneFix';
 import 'react-native-gesture-handler';
 import 'expo-splash-screen';
 import { QueryClientProvider } from '@tanstack/react-query';

+ 98 - 0
src/utils/dayjsTimezoneFix.ts

@@ -0,0 +1,98 @@
+/**
+ * Fixes random / broken date selection in react-native-ui-datepicker (range mode).
+ * https://github.com/farhoudshapouran/react-native-ui-datepicker/issues/260
+ */
+import dayjs from 'dayjs';
+import utc from 'dayjs/plugin/utc';
+import timezone from 'dayjs/plugin/timezone';
+
+dayjs.extend(utc);
+dayjs.extend(timezone);
+
+let proto: any;
+dayjs.extend((_option, DayjsClass) => {
+  proto = DayjsClass.prototype;
+});
+
+let defaultTimezone: string | undefined;
+const originalSetDefault = dayjs.tz.setDefault;
+dayjs.tz.setDefault = (tz?: string) => {
+  defaultTimezone = tz;
+  originalSetDefault(tz);
+};
+
+type Parts = {
+  year: number;
+  month: number;
+  day: number;
+  hour: number;
+  minute: number;
+  second: number;
+};
+
+const dtfCache: Record<string, Intl.DateTimeFormat> = {};
+const getDateTimeFormat = (tz?: string) => {
+  const key = String(tz);
+  if (!dtfCache[key]) {
+    dtfCache[key] = new Intl.DateTimeFormat('en-US', {
+      hour12: false,
+      timeZone: tz,
+      year: 'numeric',
+      month: '2-digit',
+      day: '2-digit',
+      hour: '2-digit',
+      minute: '2-digit',
+      second: '2-digit'
+    });
+  }
+  return dtfCache[key];
+};
+
+const getParts = (timestamp: number, tz?: string): Parts => {
+  const result: Record<string, number> = {};
+  for (const { type, value } of getDateTimeFormat(tz).formatToParts(new Date(timestamp))) {
+    if (type !== 'literal') result[type] = parseInt(value, 10);
+  }
+  return {
+    year: result.year,
+    month: result.month,
+    day: result.day,
+    hour: result.hour === 24 ? 0 : result.hour,
+    minute: result.minute,
+    second: result.second
+  };
+};
+
+proto.tz = function (tz: string | undefined = defaultTimezone, keepLocalTime = false) {
+  if (!this.isValid()) return this;
+
+  const oldOffset = this.utcOffset();
+  const timestamp = this.valueOf();
+  const p = getParts(timestamp, tz);
+  const wallClockAsUtc = Date.UTC(p.year, p.month - 1, p.day, p.hour, p.minute, p.second);
+  const offset = Math.round((wallClockAsUtc - Math.floor(timestamp / 1000) * 1000) / 60000);
+
+  let ins;
+  if (!offset) {
+    ins = this.utcOffset(0, keepLocalTime);
+  } else {
+    const wallClock = new Date(
+      p.year,
+      p.month - 1,
+      p.day,
+      p.hour,
+      p.minute,
+      p.second,
+      this.millisecond()
+    );
+    ins = (dayjs as any)(wallClock, { locale: this.$L }).utcOffset(offset, true);
+    if (keepLocalTime) {
+      ins = ins.add(oldOffset - ins.utcOffset(), 'minute');
+    }
+  }
+
+  ins.$x.$timezone = tz;
+  return ins;
+};
+
+export {};