DEV Community

Cover image for A timezone problem on react-native-paper-date (1day-off)
vatana7
vatana7

Posted on • Edited on

2

A timezone problem on react-native-paper-date (1day-off)

Today problem is that I encountered an issue while using react-native-paper-dates and the weekdays appear on the Calendar Modal was not correct. It was off by 1 day, for example today is 15th July 2024 and the 15th was supposed to appear on Monday column but instead it was on the Sunday column instead.

Eventually I figure out that the problem had something to do with Intl.DateTimeFormat because I’ve tried running the below code on 2 environment; mine and a Javascript runtime on Mozilla.dev (I know it’s so silly but I tried lol).

console.log(Intl.DateTimeFormat().resolvedOptions().timeZone);
//"UTC" on my local development env
//"Asia/Phnom_Penh" on Mozilla.dev
Enter fullscreen mode Exit fullscreen mode

Now I got my clue, so I whine to my co-worker and he mentioned that Javascript’s Intl isn’t stable for our app. So he sent me this formatjs link here that mentioned Javascript’s Engine does not expose default timezone so there’s no way to get default timezone from it; and our React native app is using Hermes Engine, which I assume it doesn’t expose anything about timezone to Javascript’s Intl so that’s why it always default to “UTC” when I try to run console.log(Intl.DateTimeFormat().resolvedOptions().timeZone) .

Now that I got my answer; I simply try the code below and the issue is resolved. By having a proper timezone, the weekdays are now correct on every column on the Calendar Modal.

import '@formatjs/intl-datetimeformat/polyfill'
import '@formatjs/intl-datetimeformat/add-all-tz.js'

//If this statement doesn't work, use expo-localization's getCalendar()
const timezone = Intl.DateTimeFormat().resolvedOptions().timeZone

if ('__setDefaultTimeZone' in Intl.DateTimeFormat) {
  Intl.DateTimeFormat.__setDefaultTimeZone('America/Los_Angeles')
}

//For my case, I have to use expo-localization
const timezone = Localization.getCalendars()[0].timezone
Enter fullscreen mode Exit fullscreen mode

Heroku

Simplify your DevOps and maximize your time.

Since 2007, Heroku has been the go-to platform for developers as it monitors uptime, performance, and infrastructure concerns, allowing you to focus on writing code.

Learn More

Top comments (2)

Collapse
 
fawwazalkarmy profile image
Fawwaz Alkarmy

I'm having the same issue with react-native-paper-dates the day on the calendar is always 1 day off, i tried to implement your solution but it always gives me this error (Cannot read property 'prototype' of undefined, js engine: hermes)
this is my entry file code where i used it, if you could help with the exact steps i need to follow or if i'm missing something

import "@formatjs/intl-datetimeformat/polyfill";
import "@formatjs/intl-datetimeformat/add-all-tz";
import { getCalendars } from "expo-localization";
import React, { useCallback, useEffect } from "react";
import { PaperProvider } from "react-native-paper";
import {
  SafeAreaProvider,
  initialWindowMetrics,
} from "react-native-safe-area-context";
import Root from "./src/navigation/root/Root";
import { StatusBar } from "expo-status-bar";
import { useCustomFonts } from "./src/hooks/helpers/useCustomFonts";
import { Provider } from "react-redux";
import { persister, store } from "./src/redux/store";
import { PersistGate } from "redux-persist/integration/react";
import ToastManager from "toastify-react-native";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { GlobalStyle } from "./src/styles/globalStyles";
import { useAppSelector } from "./src/hooks/redux/reduxHook";
import { pxHp } from "./src/utilities/layout";
import { darkTheme, lightTheme, pinkTheme } from "./src/styles/themes/themes";
import { View } from "react-native";
import { GestureHandlerRootView } from "react-native-gesture-handler";
import { I18nextProvider } from "react-i18next";
import i18n from "./src/locale/config";
import * as SplashScreen from "expo-splash-screen";
import useGoogleSignIn from "./src/hooks/helpers/useGoogleSignIn";
import useRtl from "./src/hooks/helpers/useRtl";
import * as Linking from "expo-linking";

const queryClient: QueryClient = new QueryClient();

function AppContent() {
  const { timeZone } = getCalendars()[0];

  const appActiveTheme = useAppSelector((state) => state.app.appActiveTheme);

  useGoogleSignIn();
  useRtl();

  const url = Linking.useURL();

  if (url) {
    const { hostname, path, queryParams } = Linking.parse(url);

    console.log(
      `Linked to app with hostname: ${hostname}, path: ${path} and data: ${JSON.stringify(
        queryParams
      )}`
    );
  }

  const paperTheme =
    appActiveTheme === "Light"
      ? { ...lightTheme }
      : appActiveTheme === "Dark"
      ? { ...darkTheme }
      : { ...pinkTheme };

  const globalStyle = GlobalStyle(paperTheme);

  useEffect(() => {
    if ("__setDefaultTimeZone" in Intl.DateTimeFormat) {
      //@ts-ignore
      Intl.DateTimeFormat.__setDefaultTimeZone(timeZone);
    }
  }, [timeZone]);

  return (
    <GestureHandlerRootView>
      <PaperProvider theme={paperTheme}>
        <SafeAreaProvider initialMetrics={initialWindowMetrics}>
          <StatusBar animated backgroundColor={"#000"} />
          <QueryClientProvider client={queryClient}>
            <Root />
          </QueryClientProvider>
        </SafeAreaProvider>

        <ToastManager
          textStyle={globalStyle.toastText}
          position="center"
          style={{ minHeight: pxHp(90), maxHeight: "auto" }}
        />
      </PaperProvider>
    </GestureHandlerRootView>
  );
}

SplashScreen.preventAutoHideAsync();

export default function App() {
  const { fontsLoaded } = useCustomFonts();

  const onLayoutRootView = useCallback(async () => {
    if (fontsLoaded) {
      await SplashScreen.hideAsync();
    }
  }, [fontsLoaded]);

  if (!fontsLoaded) {
    return null;
  }

  return (
    <Provider store={store}>
      <PersistGate persistor={persister} loading={<></>}>
        <View style={{ flex: 1 }} onLayout={onLayoutRootView}>
          <I18nextProvider i18n={i18n}>
            <AppContent />
          </I18nextProvider>
        </View>
      </PersistGate>
    </Provider>
  );
}

Enter fullscreen mode Exit fullscreen mode
Collapse
 
vatana7 profile image
vatana7 • Edited

Maybe you can try to set up Expo properly or something? I don't seem to encounter that error message of yours.

Qodo Takeover

Introducing Qodo Gen 1.0: Transform Your Workflow with Agentic AI

Rather than just generating snippets, our agents understand your entire project context, can make decisions, use tools, and carry out tasks autonomously.

Read full post

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay