Repository: triggerdotdev/trigger.dev
Pull request #2010: formatDateTimeISO() fix
Author: login: matt-aitken
Created: 2025-05-01T16:14:44Z | Merged: 2025-05-01T16:35:55Z

We use the `formatDateTimeISO()` function to format dates in our new date tooltip which lets you copy ISO dates. 

They need to be in this format:

```
2025-01-15T06:01:19.000-08:00
2025-04-29T14:01:19.123Z
```

Previously they weren't respecting the timezone correctly and were in the wrong format too. I've added some tests as well.

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->
## Summary by CodeRabbit

- **Bug Fixes**
	- Improved date and time formatting to correctly handle various time zones and daylight saving transitions, ensuring accurate ISO-like output.

- **Tests**
	- Added comprehensive tests to verify correct formatting across multiple time zones, including daylight saving periods and offset handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/apps/webapp/app/components/primitives/DateTime.tsx b/apps/webapp/app/components/primitives/DateTime.tsx
index 11a7ab990e1..7d75bc73511 100644
--- a/apps/webapp/app/components/primitives/DateTime.tsx
+++ b/apps/webapp/app/components/primitives/DateTime.tsx
@@ -98,7 +98,45 @@ export function formatDateTime(
 }
 
 export function formatDateTimeISO(date: Date, timeZone: string): string {
-  return new Date(date.toLocaleString("en-US", { timeZone })).toISOString();
+  // Special handling for UTC
+  if (timeZone === "UTC") {
+    return date.toISOString();
+  }
+
+  // Get the date parts in the target timezone
+  const dateFormatter = new Intl.DateTimeFormat("en-US", {
+    timeZone,
+    year: "numeric",
+    month: "2-digit",
+    day: "2-digit",
+    hour: "2-digit",
+    minute: "2-digit",
+    second: "2-digit",
+    hour12: false,
+  });
+
+  // Get the timezone offset for this specific date
+  const timeZoneFormatter = new Intl.DateTimeFormat("en-US", {
+    timeZone,
+    timeZoneName: "longOffset",
+  });
+
+  const dateParts = Object.fromEntries(
+    dateFormatter.formatToParts(date).map(({ type, value }) => [type, value])
+  );
+
+  const timeZoneParts = timeZoneFormatter.formatToParts(date);
+  const offset =
+    timeZoneParts.find((part) => part.type === "timeZoneName")?.value.replace("GMT", "") ||
+    "+00:00";
+
+  // Format: YYYY-MM-DDThh:mm:ss.sss±hh:mm
+  return (
+    `${dateParts.year}-${dateParts.month}-${dateParts.day}T` +
+    `${dateParts.hour}:${dateParts.minute}:${dateParts.second}.${String(
+      date.getMilliseconds()
+    ).padStart(3, "0")}${offset}`
+  );
 }
 
 // New component that only shows date when it changes
diff --git a/apps/webapp/test/components/DateTime.test.ts b/apps/webapp/test/components/DateTime.test.ts
new file mode 100644
index 00000000000..103f416eb9f
--- /dev/null
+++ b/apps/webapp/test/components/DateTime.test.ts
@@ -0,0 +1,54 @@
+import { describe, it, expect } from "vitest";
+import { formatDateTimeISO } from "~/components/primitives/DateTime";
+
+describe("formatDateTimeISO", () => {
+  it("should format UTC dates with Z suffix", () => {
+    const date = new Date("2025-04-29T14:01:19.000Z");
+    const result = formatDateTimeISO(date, "UTC");
+    expect(result).toBe("2025-04-29T14:01:19.000Z");
+  });
+
+  describe("British Time (Europe/London)", () => {
+    it("should format with +01:00 during BST (summer)", () => {
+      // BST - British Summer Time (last Sunday in March to last Sunday in October)
+      const summerDate = new Date("2025-07-15T14:01:19.000Z");
+      const result = formatDateTimeISO(summerDate, "Europe/London");
+      expect(result).toBe("2025-07-15T15:01:19.000+01:00");
+    });
+
+    it("should format with +00:00 during GMT (winter)", () => {
+      // GMT - Greenwich Mean Time (winter)
+      const winterDate = new Date("2025-01-15T14:01:19.000Z");
+      const result = formatDateTimeISO(winterDate, "Europe/London");
+      expect(result).toBe("2025-01-15T14:01:19.000+00:00");
+    });
+  });
+
+  describe("US Pacific Time (America/Los_Angeles)", () => {
+    it("should format with -07:00 during PDT (summer)", () => {
+      // PDT - Pacific Daylight Time (second Sunday in March to first Sunday in November)
+      const summerDate = new Date("2025-07-15T14:01:19.000Z");
+      const result = formatDateTimeISO(summerDate, "America/Los_Angeles");
+      expect(result).toBe("2025-07-15T07:01:19.000-07:00");
+    });
+
+    it("should format with -08:00 during PST (winter)", () => {
+      // PST - Pacific Standard Time (winter)
+      const winterDate = new Date("2025-01-15T14:01:19.000Z");
+      const result = formatDateTimeISO(winterDate, "America/Los_Angeles");
+      expect(result).toBe("2025-01-15T06:01:19.000-08:00");
+    });
+  });
+
+  it("should preserve milliseconds", () => {
+    const date = new Date("2025-04-29T14:01:19.123Z");
+    const result = formatDateTimeISO(date, "UTC");
+    expect(result).toBe("2025-04-29T14:01:19.123Z");
+  });
+
+  it("should preserve milliseconds, not UTC", () => {
+    const date = new Date("2025-04-29T14:01:19.123Z");
+    const result = formatDateTimeISO(date, "Europe/London");
+    expect(result).toBe("2025-04-29T15:01:19.123+01:00");
+  });
+});


Reviews:
user: login: nicktrn
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-05-01T16:17:14Z
user: login: coderabbitai[bot]
body: **Actionable comments posted: 2**

<details>
<summary>🧹 Nitpick comments (1)</summary><blockquote>

<details>
<summary>apps/webapp/test/components/DateTime.test.ts (1)</summary><blockquote>

`1-48`: **Additional test cases to consider**

The test suite is comprehensive for standard use cases, but could benefit from additional edge cases.


Consider adding these test cases to make the suite more robust:

1. Test with an invalid timezone to ensure graceful handling
2. Test with dates before 1970 (negative timestamps)
3. Test with dates at DST transition boundaries

```javascript
it("should handle invalid timezones gracefully", () => {
  const date = new Date("2025-04-29T14:01:19.123Z");
  const result = formatDateTimeISO(date, "Invalid/Timezone");
  // Should fall back to UTC or handle gracefully
  expect(result).toBe("2025-04-29T14:01:19.123Z");
});

it("should handle pre-1970 dates correctly", () => {
  const date = new Date("1969-12-31T23:59:59.123Z");
  const result = formatDateTimeISO(date, "UTC");
  expect(result).toBe("1969-12-31T23:59:59.123Z");
});
```

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between aacec569d0d49ff4323f046cd178cc3d4a9212e1 and 5cf6fdf335a3725f141dabb3077b5d288782b27c.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `apps/webapp/app/components/primitives/DateTime.tsx` (1 hunks)
* `apps/webapp/test/components/DateTime.test.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (1)</summary>

<details>
<summary>apps/webapp/test/components/DateTime.test.ts (1)</summary><blockquote>

<details>
<summary>apps/webapp/app/components/primitives/DateTime.tsx (1)</summary>

* `formatDateTimeISO` (100-138)

</details>

</blockquote></details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (7)</summary>

* GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
* GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
* GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
* GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
* GitHub Check: units / 🧪 Unit Tests
* GitHub Check: typecheck / typecheck
* GitHub Check: Analyze (javascript-typescript)

</details>

<details>
<summary>🔇 Additional comments (3)</summary><blockquote>

<details>
<summary>apps/webapp/test/components/DateTime.test.ts (3)</summary>

`4-9`: **Good test coverage for UTC with Z suffix**

The test correctly verifies that UTC dates are formatted with the "Z" suffix using `toISOString()`.

---

`11-25`: **Comprehensive testing for Europe/London timezone**

Good test coverage for Europe/London timezone during both BST (summer) and GMT (winter) with the correct offset handling.

---

`27-41`: **Thorough testing for America/Los_Angeles timezone**

The tests correctly verify the formatting for America/Los_Angeles timezone during both PDT (summer) and PST (winter) with the proper timezone offsets.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-01T16:17:40Z

Review comments:
diff_hunk: @@ -98,7 +98,43 @@ export function formatDateTime(
 }
 
 export function formatDateTimeISO(date: Date, timeZone: string): string {
-  return new Date(date.toLocaleString("en-US", { timeZone })).toISOString();
+  // Special handling for UTC
+  if (timeZone === "UTC") {
+    return date.toISOString();
+  }
+
+  // Get the date parts in the target timezone
+  const dateFormatter = new Intl.DateTimeFormat("en-US", {
+    timeZone,
+    year: "numeric",
+    month: "2-digit",
+    day: "2-digit",
+    hour: "2-digit",
+    minute: "2-digit",
+    second: "2-digit",
+    hour12: false,
+  });
+
+  // Get the timezone offset for this specific date
+  const timeZoneFormatter = new Intl.DateTimeFormat("en-US", {
+    timeZone,
+    timeZoneName: "longOffset",
+  });
+
+  const dateParts = Object.fromEntries(
+    dateFormatter.formatToParts(date).map(({ type, value }) => [type, value])
+  );
+
+  const timeZoneParts = timeZoneFormatter.formatToParts(date);
+  const offset =
+    timeZoneParts.find((part) => part.type === "timeZoneName")?.value.replace("GMT", "") ||
+    "+00:00";
+
+  // Format: YYYY-MM-DDThh:mm:ss.sss±hh:mm
+  return (
+    `${dateParts.year}-${dateParts.month}-${dateParts.day}T` +
+    `${dateParts.hour}:${dateParts.minute}:${dateParts.second}.000${offset}`
+  );
 }
path: apps/webapp/app/components/primitives/DateTime.tsx
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Timezone handling improved but milliseconds are lost**

The implementation correctly handles timezone offsets by using `Intl.DateTimeFormat` to format date parts and extract timezone offsets. However, there's an issue with milliseconds handling.


The milliseconds are hardcoded to `.000` in line 136, which means the original milliseconds from the input date are lost for non-UTC timezones. Only UTC dates (handled by `toISOString()`) will preserve milliseconds.

```diff
- `${dateParts.hour}:${dateParts.minute}:${dateParts.second}.000${offset}`
+ `${dateParts.hour}:${dateParts.minute}:${dateParts.second}.${String(date.getMilliseconds()).padStart(3, '0')}${offset}`
```


Consider adding validation for the `timeZone` parameter to handle invalid timezones gracefully:

```diff
export function formatDateTimeISO(date: Date, timeZone: string): string {
+  // Validate timeZone
+  try {
+    // Quick validation by trying to use the timeZone
+    new Intl.DateTimeFormat("en-US", { timeZone });
+  } catch (e) {
+    console.warn(`Invalid timezone: ${timeZone}, falling back to UTC`);
+    timeZone = "UTC";
+  }

  // Special handling for UTC
  if (timeZone === "UTC") {
    return date.toISOString();
  }
  
  // Rest of the function...
}
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export function formatDateTimeISO(date: Date, timeZone: string): string {
  // Validate timeZone
  try {
    // Quick validation by trying to use the timeZone
    new Intl.DateTimeFormat("en-US", { timeZone });
  } catch (e) {
    console.warn(`Invalid timezone: ${timeZone}, falling back to UTC`);
    timeZone = "UTC";
  }

  // Special handling for UTC
  if (timeZone === "UTC") {
    return date.toISOString();
  }

  // Get the date parts in the target timezone
  const dateFormatter = new Intl.DateTimeFormat("en-US", {
    timeZone,
    year: "numeric",
    month: "2-digit",
    day: "2-digit",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false,
  });

  // Get the timezone offset for this specific date
  const timeZoneFormatter = new Intl.DateTimeFormat("en-US", {
    timeZone,
    timeZoneName: "longOffset",
  });

  const dateParts = Object.fromEntries(
    dateFormatter.formatToParts(date).map(({ type, value }) => [type, value])
  );

  const timeZoneParts = timeZoneFormatter.formatToParts(date);
  const offset =
    timeZoneParts.find((part) => part.type === "timeZoneName")?.value.replace("GMT", "") ||
    "+00:00";

  // Format: YYYY-MM-DDThh:mm:ss.sss±hh:mm
  return (
    `${dateParts.year}-${dateParts.month}-${dateParts.day}T` +
    `${dateParts.hour}:${dateParts.minute}:${dateParts.second}.${String(date.getMilliseconds()).padStart(3, '0')}${offset}`
  );
}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->

✅ Addressed in commit 04e1b34
created_at: 2025-05-01T16:17:39Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,48 @@
+import { describe, it, expect } from "vitest";
+import { formatDateTimeISO } from "~/components/primitives/DateTime";
+
+describe("formatDateTimeISO", () => {
+  it("should format UTC dates with Z suffix", () => {
+    const date = new Date("2025-04-29T14:01:19.000Z");
+    const result = formatDateTimeISO(date, "UTC");
+    expect(result).toBe("2025-04-29T14:01:19.000Z");
+  });
+
+  describe("British Time (Europe/London)", () => {
+    it("should format with +01:00 during BST (summer)", () => {
+      // BST - British Summer Time (last Sunday in March to last Sunday in October)
+      const summerDate = new Date("2025-07-15T14:01:19.000Z");
+      const result = formatDateTimeISO(summerDate, "Europe/London");
+      expect(result).toBe("2025-07-15T15:01:19.000+01:00");
+    });
+
+    it("should format with +00:00 during GMT (winter)", () => {
+      // GMT - Greenwich Mean Time (winter)
+      const winterDate = new Date("2025-01-15T14:01:19.000Z");
+      const result = formatDateTimeISO(winterDate, "Europe/London");
+      expect(result).toBe("2025-01-15T14:01:19.000+00:00");
+    });
+  });
+
+  describe("US Pacific Time (America/Los_Angeles)", () => {
+    it("should format with -07:00 during PDT (summer)", () => {
+      // PDT - Pacific Daylight Time (second Sunday in March to first Sunday in November)
+      const summerDate = new Date("2025-07-15T14:01:19.000Z");
+      const result = formatDateTimeISO(summerDate, "America/Los_Angeles");
+      expect(result).toBe("2025-07-15T07:01:19.000-07:00");
+    });
+
+    it("should format with -08:00 during PST (winter)", () => {
+      // PST - Pacific Standard Time (winter)
+      const winterDate = new Date("2025-01-15T14:01:19.000Z");
+      const result = formatDateTimeISO(winterDate, "America/Los_Angeles");
+      expect(result).toBe("2025-01-15T06:01:19.000-08:00");
+    });
+  });
+
+  it("should preserve milliseconds", () => {
+    const date = new Date("2025-04-29T14:01:19.123Z");
+    const result = formatDateTimeISO(date, "UTC");
+    expect(result).toBe("2025-04-29T14:01:19.123Z");
+  });
path: apps/webapp/test/components/DateTime.test.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Milliseconds test only works for UTC**

This test correctly verifies millisecond preservation for UTC dates, but doesn't test milliseconds for non-UTC timezones.


The current implementation of `formatDateTimeISO` hardcodes milliseconds to `.000` for non-UTC timezones, so this test only passes for UTC. Additional tests are needed for non-UTC timezones with milliseconds.

```diff
it("should preserve milliseconds", () => {
  const date = new Date("2025-04-29T14:01:19.123Z");
  const result = formatDateTimeISO(date, "UTC");
  expect(result).toBe("2025-04-29T14:01:19.123Z");
});

+it("should preserve milliseconds for non-UTC timezones", () => {
+  const date = new Date("2025-04-29T14:01:19.123Z");
+  const londonResult = formatDateTimeISO(date, "Europe/London");
+  // During BST (British Summer Time)
+  expect(londonResult).toBe("2025-04-29T15:01:19.123+01:00");
+  
+  const laResult = formatDateTimeISO(date, "America/Los_Angeles");
+  // During PDT (Pacific Daylight Time)
+  expect(laResult).toBe("2025-04-29T07:01:19.123-07:00");
+});
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  it("should preserve milliseconds", () => {
    const date = new Date("2025-04-29T14:01:19.123Z");
    const result = formatDateTimeISO(date, "UTC");
    expect(result).toBe("2025-04-29T14:01:19.123Z");
  });

  it("should preserve milliseconds for non-UTC timezones", () => {
    const date = new Date("2025-04-29T14:01:19.123Z");
    const londonResult = formatDateTimeISO(date, "Europe/London");
    // During BST (British Summer Time)
    expect(londonResult).toBe("2025-04-29T15:01:19.123+01:00");
    
    const laResult = formatDateTimeISO(date, "America/Los_Angeles");
    // During PDT (Pacific Daylight Time)
    expect(laResult).toBe("2025-04-29T07:01:19.123-07:00");
  });
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-05-01T16:17:40Z
author_association: CONTRIBUTOR

PR comments:
user: login: changeset-bot[bot]
created_at: 2025-05-01T16:14:47Z
body: ###  ⚠️  No Changeset found

Latest commit: 04e1b340562fe8b7411fdc2bb79229a22d539007

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**



[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/triggerdotdev/trigger.dev/new/datetime-copy-fix?filename=.changeset/poor-years-drive.md&value=---%0A%22%40fake-scope%2Ffake-pkg%22%3A%20patch%0A---%0A%0AformatDateTimeISO()%20fix%0A)


author_association: NONE
user: login: coderabbitai[bot]
created_at: 2025-05-01T16:14:51Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- walkthrough_start -->

"""
## Walkthrough

The changes introduce a revised implementation of the `formatDateTimeISO` function, enhancing its handling of time zones and date formatting. The function now manually constructs ISO-like date strings, accurately reflecting the specified time zone, including proper formatting of offsets and support for daylight saving time. Additionally, a new test suite has been added to rigorously verify the function's output across various time zones, including UTC, Europe/London, and America/Los_Angeles, as well as during daylight saving and standard time periods.

## Changes

| File(s)                                                                                 | Change Summary                                                                                                    |
|-----------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------|
| apps/webapp/app/components/primitives/DateTime.tsx                                      | Refactored `formatDateTimeISO` to manually format dates and handle time zone offsets and daylight saving time.    |
| apps/webapp/test/components/DateTime.test.ts                                            | Added comprehensive tests for `formatDateTimeISO` covering multiple time zones and daylight saving transitions.   |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Caller
    participant DateTime
    participant IntlFormatter

    Caller->>DateTime: formatDateTimeISO(date, timeZone)
    alt timeZone is "UTC"
        DateTime->>DateTime: Return date.toISOString()
    else Other timeZone
        DateTime->>IntlFormatter: Format date parts (year, month, day, hour, minute, second) in timeZone
        DateTime->>IntlFormatter: Get timezone offset string in timeZone
        DateTime->>DateTime: Construct ISO-like string with offset
        DateTime->>Caller: Return formatted string
    end
```

## Poem

> In the warren of code, a date hops anew,  
> With time zones and offsets, precision in view.  
> From London to L.A., and UTC’s embrace,  
> Each tick and each tock now falls into place.  
> With tests as our carrots, we check every zone—  
> The world’s time, now formatted, is perfectly shown!  
> 🕰️🐇
"""

<!-- walkthrough_end -->


---

<details>
<summary>📜 Recent review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between 5cf6fdf335a3725f141dabb3077b5d288782b27c and 04e1b340562fe8b7411fdc2bb79229a22d539007.

</details>

<details>
<summary>📒 Files selected for processing (2)</summary>

* `apps/webapp/app/components/primitives/DateTime.tsx` (1 hunks)
* `apps/webapp/test/components/DateTime.test.ts` (1 hunks)

</details>

<details>
<summary>🚧 Files skipped from review as they are similar to previous changes (2)</summary>

* apps/webapp/app/components/primitives/DateTime.tsx
* apps/webapp/test/components/DateTime.test.ts

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (7)</summary>

* GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - pnpm)
* GitHub Check: e2e / 🧪 CLI v3 tests (windows-latest - npm)
* GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - pnpm)
* GitHub Check: e2e / 🧪 CLI v3 tests (ubuntu-latest - npm)
* GitHub Check: units / 🧪 Unit Tests
* GitHub Check: typecheck / typecheck
* GitHub Check: Analyze (javascript-typescript)

</details>

</details>
<!-- internal state start -->


<!-- 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= -->

<!-- internal state end -->
<!-- finishing_touch_checkbox_start -->

<details open="true">
<summary>✨ Finishing Touches</summary>

- [ ] <!-- {"checkboxId": "7962f53c-55bc-4827-bfbf-6a18da830691"} --> 📝 Generate Docstrings

</details>

<!-- finishing_touch_checkbox_end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=triggerdotdev/trigger.dev&utm_content=2010):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

### Support

Need help? Create a ticket on our [support page](https://www.coderabbit.ai/contact-us/support) for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: CONTRIBUTOR