Skip to content

fix(calendar): pass timeZone to events.list to fix all-day event date shift#661

Open
jorj-pineda wants to merge 4 commits intogoogleworkspace:mainfrom
jorj-pineda:fix/579-allday-event-date-shift
Open

fix(calendar): pass timeZone to events.list to fix all-day event date shift#661
jorj-pineda wants to merge 4 commits intogoogleworkspace:mainfrom
jorj-pineda:fix/579-allday-event-date-shift

Conversation

@jorj-pineda
Copy link
Copy Markdown

Description

Fixes #579

All-day events in gws calendar +agenda were displaying incorrect dates,
shifted backwards by up to a day for users in non-UTC timezones (e.g.
Asia/Seoul, UTC+9).

Root cause: The events.list API call was not passing a timeZone
parameter, so the Google Calendar API interpreted all-day event boundaries
using the calendar's default timezone rather than the user's resolved
account timezone.

Changes:

  • Pass the resolved account timezone to the events.list API call via
    the timeZone query parameter
  • Extract extract_event_times() helper that properly handles date
    (all-day) vs dateTime (timed) fields — all-day events use the bare
    date string to avoid any timezone shifting
  • Add allDay field to each event in the output
  • Add 4 unit tests covering all-day, timed, missing fields, and the
    regression case

Checklist

  • My code follows the AGENTS.md guidelines (no generated google-* crates)
  • I have run cargo fmt --all to format the code
  • I have run cargo clippy -- -D warnings and resolved all warnings
  • I have added tests that prove my fix is effective
  • I have provided a changeset file

@googleworkspace-bot googleworkspace-bot added the area: core Core CLI parsing, commands, error handling, utilities label Apr 1, 2026
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, 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 an issue where all-day calendar events in the +agenda command were displaying incorrect dates for users in non-UTC timezones. By explicitly passing the user's timezone to the Google Calendar API and improving how event start and end times are parsed, the fix ensures that all-day events remain anchored to the correct date regardless of the user's local timezone offset.

Highlights

  • Timezone Handling: Updated the events.list API call to include the timeZone parameter, ensuring all-day events are interpreted correctly based on the user's account timezone.
  • Event Time Extraction: Introduced a new helper function extract_event_times to reliably distinguish between all-day and timed events, preventing date shifts.
  • Output Schema: Added an allDay boolean field to the event output to improve data clarity for consumers.
  • Testing: Added four new unit tests to verify correct handling of all-day events, timed events, missing fields, and regression scenarios.
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.

Footnotes

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

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Apr 1, 2026

🦋 Changeset detected

Latest commit: 6091bd2

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@googleworkspace/cli Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

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 addresses an issue where all-day calendar events displayed incorrect dates in the agenda by passing the user's timezone to the Google Calendar API and introducing a helper function to extract event times. Review feedback highlights that the logic for detecting all-day events is inconsistent with the goal of prioritizing the 'date' field when both 'date' and 'dateTime' are present. Furthermore, a regression test was found to be inadequate as it does not include both fields to properly verify the intended prioritization logic.

Comment on lines +216 to +250
fn extract_event_times(event: &Value) -> (String, String, bool) {
let start_obj = event.get("start");
let end_obj = event.get("end");

// All-day events carry a `date` field with no `dateTime`.
let all_day = start_obj
.map(|s| s.get("date").is_some() && s.get("dateTime").is_none())
.unwrap_or(false);

let start = start_obj
.and_then(|s| {
if all_day {
s.get("date")
} else {
s.get("dateTime").or_else(|| s.get("date"))
}
})
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();

let end = end_obj
.and_then(|s| {
if all_day {
s.get("date")
} else {
s.get("dateTime").or_else(|| s.get("date"))
}
})
.and_then(|v| v.as_str())
.unwrap_or("")
.to_string();

(start, end, all_day)
}
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

The logic in extract_event_times for detecting all-day events and extracting their values is redundant and inconsistent with the stated goal of preferring the date field when both date and dateTime are present.

Currently, all_day is only true if dateTime is absent. If both are present, all_day becomes false, and the extraction logic then prefers dateTime. This contradicts the comment on line 212 and the intent of the regression test on line 845. Additionally, the extraction of the end time is fragile because it relies on the all_day flag derived solely from the start object.

A simpler and more robust approach is to prefer the date field if it exists, which correctly identifies all-day events and avoids timezone shifts as intended.

fn extract_event_times(event: &Value) -> (String, String, bool) {
    let start_obj = event.get("start");
    let end_obj = event.get("end");

    // Prefer 'date' (all-day) over 'dateTime' (timed) to avoid timezone shifts.
    let start_date = start_obj.and_then(|s| s.get("date")).and_then(|v| v.as_str());
    let start_time = start_obj.and_then(|s| s.get("dateTime")).and_then(|v| v.as_str());
    let all_day = start_date.is_some();

    let start = start_date.or(start_time).unwrap_or("").to_string();
    let end = end_obj
        .and_then(|s| s.get("date").or_else(|| s.get("dateTime")))
        .and_then(|v| v.as_str())
        .unwrap_or("")
        .to_string();

    (start, end, all_day)
}

Comment on lines +845 to +856
fn extract_event_times_all_day_prefers_date_over_datetime() {
// Regression: if both `date` and `dateTime` exist on an all-day
// event, the bare date must win so no timezone shift occurs.
let event = json!({
"start": { "date": "2026-03-23" },
"end": { "date": "2026-03-24" },
"summary": "Mixed"
});
let (start, _end, all_day) = extract_event_times(&event);
assert!(all_day);
assert_eq!(start, "2026-03-23", "bare date must not be shifted");
}
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

This regression test does not actually test the scenario where both date and dateTime are present, as the mock JSON only contains the date field. To properly verify that the bare date is preferred over dateTime, the test case should include both fields in the input.

    #[test]
    fn extract_event_times_all_day_prefers_date_over_datetime() {
        // Regression: if both 'date' and 'dateTime' exist on an all-day
        // event, the bare date must win so no timezone shift occurs.
        let event = json!({
            "start": { "date": "2026-03-23", "dateTime": "2026-03-23T10:00:00Z" },
            "end": { "date": "2026-03-24", "dateTime": "2026-03-24T10:00:00Z" },
            "summary": "Mixed"
        });
        let (start, end, all_day) = extract_event_times(&event);
        assert!(all_day);
        assert_eq!(start, "2026-03-23", "bare date must not be shifted");
        assert_eq!(end, "2026-03-24");
    }

@googleworkspace-bot
Copy link
Copy Markdown
Collaborator

/gemini review

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 fixes an issue where all-day calendar events displayed incorrect dates in the +agenda command. It introduces a helper function extract_event_times that correctly prioritizes the date field for all-day events to prevent timezone offsets. Additionally, the user's timezone is now passed as a query parameter to the Calendar API. Unit tests were added to verify the new logic. I have no feedback to provide.

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

Labels

area: core Core CLI parsing, commands, error handling, utilities

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] All-day events show incorrect start date in calendar +agenda

2 participants