Skip to content

fix(web): use user profile timezone for date range filtering#32119

Closed
Theysua wants to merge 0 commit into
langgenius:mainfrom
Theysua:main
Closed

fix(web): use user profile timezone for date range filtering#32119
Theysua wants to merge 0 commit into
langgenius:mainfrom
Theysua:main

Conversation

@Theysua
Copy link
Copy Markdown
Contributor

@Theysua Theysua commented Feb 9, 2026

close #32121

1. What was the problem?

When running Dify in a local development environment (e.g., Docker), the host machine's time might differ from the database's UTC time due to time drift or timezone misconfiguration.
For example, the host machine might think it's February 8th , while the data in the database is timestamped February 9th (UTC).

Previously, when a user clicked the "Today" filter button, the frontend code naively relied on the browser/system local time ( dayjs() ) to calculate the start and end query parameters.

  • Scenario: The user clicks "Today".
  • Old Behavior: The browser (host) says "It's Feb 8th", so the query requests data for Feb 8th.
  • Result: The query returns empty results because the relevant data in the database is actually on Feb 9th.

2. What did I fix?

I modified the date calculation logic in the frontend to enforce the use of the User Profile Timezone instead of the local system time.

  • The code now uses dayjs().tz(userProfile.timezone) to determine the current date relative to the user's configured settings.
  • New Behavior: Even if the host computer says "Feb 8th", if the user's profile is set to a timezone where it is already "Feb 9th" (or aligns with the server data), the query will correctly request data for Feb 9th .
  • This ensures that date range filters (Today, Last 7 days, etc.) work universally, regardless of the local machine's clock drift or timezone differences.

Modified Components:

  1. Log List ( app/components/app/log/index.tsx ) : Updated start and end param generation.

  2. Chart View ( overview/chart-view.tsx ) : Updated chart data initialization logic.

  3. Time Range Pickers :

    • overview/long-time-range-picker.tsx
    • overview/time-range-picker/index.tsx
    • overview/time-range-picker/range-selector.tsx [!IMPORTANT]
  4. Make sure you have read our https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md

  5. Ensure there is an associated issue and you have been assigned to it

  6. Use the correct syntax to link this PR: Fixes # .

Summary

This PR fixes a bug where date range filters returned empty results in environments with time drift or timezone mismatches (e.g., local Docker vs. host). It forces the frontend to calculate date ranges based on the user's configured profile timezone, ensuring queries align with the stored data.

Screenshots

Before
de045d0f649ae4be9df11d078eeb5b5e
2eb66b05e0bd0051ea67c585e3fa6d6e

After
image

Checklist

  • This change requires a documentation update, included: https://github.com/langgenius/dify-docs (Not strictly required as this is a bug fix, but good to note timezone behavior)
  • I understand that this PR may be closed in case there was no previous discussion or issues.
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran make lint and make type-check (backend) and cd web && npx lint-staged (frontend) to appease the lint gods.

@dosubot dosubot Bot added the size:M This PR changes 30-99 lines, ignoring generated files. label Feb 9, 2026
@github-actions github-actions Bot added the web This relates to changes on the web. label Feb 9, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello @Theysua, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request addresses a critical bug where date range filters in the application would return empty results due to mismatches between the local system's time and the database's UTC timestamps, particularly in development environments like Docker. By enforcing the use of the user's configured profile timezone for all date calculations, the changes ensure that frontend queries accurately reflect the intended time periods, leading to consistent and correct data retrieval regardless of environmental time differences.

Highlights

  • Date Calculation Logic: The frontend's date calculation logic has been updated to consistently use the user's profile timezone, resolving issues caused by local system time discrepancies.
  • Timezone Integration: The dayjs library is now extended with utc and timezone plugins, and date operations explicitly leverage dayjs().tz(userProfile.timezone) to ensure accuracy across different environments.
  • Universal Date Range Filters: Date range filters such as 'Today' and 'Last 7 days' now function reliably, aligning query parameters with the user's configured timezone and the database's UTC timestamps.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/chart-view.tsx
    • Imported and extended dayjs with utc and timezone plugins.
    • Integrated useAppContext to access userProfile for timezone information.
    • Updated initial period state to calculate start and end dates using the user's profile timezone.
  • web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/long-time-range-picker.tsx
    • Imported useAppContext to retrieve user profile data.
    • Removed the global today variable and now dynamically calculate today within handleSelect using the user's profile timezone.
    • Added userProfile?.timezone to the dependency array of the handleSelect callback.
  • web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/time-range-picker/index.tsx
    • Imported useAppContext to access user profile data.
    • Removed the global today variable and now dynamically calculate today within the component using the user's profile timezone.
  • web/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/time-range-picker/range-selector.tsx
    • Imported useAppContext to retrieve user profile data.
    • Removed the global today variable and now dynamically calculate today within handleSelectRange using the user's profile timezone.
    • Added userProfile?.timezone to the dependency array of the handleSelectRange callback.
  • web/app/components/app/log/index.tsx
    • Imported and extended dayjs with utc and timezone plugins.
    • Integrated useAppContext to access userProfile for timezone information.
    • Modified start and end date calculations for query parameters to use the user's profile timezone.
Activity
  • There has been no human activity on this pull request since its creation.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request aims to fix a bug where date range filters were using the local system time instead of the user's configured timezone, leading to incorrect data being displayed. The approach of using dayjs().tz(userProfile.timezone) is correct. However, I've found a couple of instances where the implementation doesn't fully resolve the issue due to how React's useState hook initializes state from props/context that might not be available on the initial render. My review includes suggestions to address this by using the useEffect hook for state initialization. I've also included a minor suggestion to improve code readability.

Comment on lines 44 to 47
const [period, setPeriod] = useState<PeriodParams>(IS_CLOUD_EDITION
? { name: t('filter.period.today', { ns: 'appLog' }), query: { start: today.startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } }
: { name: t('filter.period.last7days', { ns: 'appLog' }), query: { start: today.subtract(7, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } },
? { name: t('filter.period.today', { ns: 'appLog' }), query: { start: dayjs().tz(userProfile?.timezone).startOf('day').format(queryDateFormat), end: dayjs().tz(userProfile?.timezone).endOf('day').format(queryDateFormat) } }
: { name: t('filter.period.last7days', { ns: 'appLog' }), query: { start: dayjs().tz(userProfile?.timezone).subtract(7, 'day').startOf('day').format(queryDateFormat), end: dayjs().tz(userProfile?.timezone).endOf('day').format(queryDateFormat) } },
)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There's a potential issue here with the initialization of the period state. The useState initializer is executed only on the first render. At that point, userProfile might not be fully loaded, and userProfile?.timezone could be undefined. This would cause dayjs().tz() to fall back to the local system's timezone, which is the exact bug this PR aims to fix. When userProfile eventually loads, this state won't be re-initialized.

To fix this, you could consider initializing the state with null and then setting it inside a useEffect hook that depends on userProfile?.timezone. This ensures the initial period is always calculated with the correct timezone. You would then need to handle the null state, for example by showing a loading indicator until the state is set.

Additionally, dayjs().tz(userProfile?.timezone) is called multiple times. Defining a today variable within the effect would make the code cleaner.

Comment thread web/app/components/app/log/index.tsx Outdated
Comment on lines +88 to +89
start: dayjs().tz(userProfile?.timezone).subtract(TIME_PERIOD_MAPPING[debouncedQueryParams.period].value, 'day').startOf('day').format('YYYY-MM-DD HH:mm'),
end: dayjs().tz(userProfile?.timezone).endOf('day').format('YYYY-MM-DD HH:mm'),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

For better readability and to avoid redundant calls, you could extract dayjs().tz(userProfile?.timezone) into a today variable before constructing the query object and use it in both start and end date calculations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs revision for anti-slop size:M This PR changes 30-99 lines, ignoring generated files. web This relates to changes on the web.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Date range filters (Today, Last 7 days) return no data when host time differs from user profile timezone (Time Drift)

1 participant