Conversation
- Rename extension slug to in-the-time-zone - Prepare extension for Raycast Store - updates timezones - init - Initial commit
|
Congratulations on your new Raycast extension! 🚀 We're currently experiencing a high volume of incoming requests. As a result, the initial review may take up to 10-15 business days. Once the PR is approved and merged, the extension will be available on our Store. |
Greptile SummaryThis PR adds a new "In The (Time) Zone" Raycast extension that provides a color-coded timeline view for comparing multiple cities across time zones, with keyboard-driven time scrubbing and sunrise/sunset metadata. The architecture is clean — preferences are wired through correctly, city IDs are namespaced to avoid collision, and the Two logic bugs in
Additional minor items:
Confidence Score: 2/5
Important Files Changed
Last reviewed commit: "Use scrub preference..." |
| "name": "defaultScrubMinutes", | ||
| "type": "dropdown", | ||
| "title": "Default Scrub Minutes", | ||
| "description": "Arrow keys scrub this many minutes.", | ||
| "data": [ | ||
| { | ||
| "title": "5 minutes", | ||
| "value": "5" | ||
| }, | ||
| { | ||
| "title": "10 minutes", | ||
| "value": "10" | ||
| }, | ||
| { | ||
| "title": "15 minutes", | ||
| "value": "15" | ||
| }, | ||
| { | ||
| "title": "30 minutes", | ||
| "value": "30" | ||
| }, | ||
| { | ||
| "title": "60 minutes", | ||
| "value": "60" | ||
| } | ||
| ], | ||
| "default": "30", | ||
| "required": false |
There was a problem hiding this comment.
defaultScrubMinutes preference is defined but never used. The code hardcodes ±60 minutes and ±30 minutes for arrow key scrubbing (see in-the-time-zone.tsx:217-234 and timeline-view.tsx:95-118). Either remove this unused preference or implement it using getPreferenceValues<Preferences>().
| "name": "defaultScrubMinutes", | ||
| "type": "dropdown", | ||
| "title": "Default Scrub Minutes", | ||
| "description": "Arrow keys scrub this many minutes.", | ||
| "data": [ | ||
| { | ||
| "title": "5 minutes", | ||
| "value": "5" | ||
| }, | ||
| { | ||
| "title": "10 minutes", | ||
| "value": "10" | ||
| }, | ||
| { | ||
| "title": "15 minutes", | ||
| "value": "15" | ||
| }, | ||
| { | ||
| "title": "30 minutes", | ||
| "value": "30" | ||
| }, | ||
| { | ||
| "title": "60 minutes", | ||
| "value": "60" | ||
| } | ||
| ], | ||
| "default": "30", | ||
| "required": false |
There was a problem hiding this comment.
defaultScrubMinutes preference is never used - arrow keys hardcode ±60 and ±30 minutes in in-the-time-zone.tsx:217-234 and timeline-view.tsx:95-118. Either remove this preference or implement it using getPreferenceValues<Preferences>().
| interface Preferences { | ||
| defaultScrubMinutes: string; | ||
| optionScrubMinutes: string; | ||
| } |
There was a problem hiding this comment.
Remove manual Preferences interface - auto-generated in raycast-env.d.ts
| interface Preferences { | |
| defaultScrubMinutes: string; | |
| optionScrubMinutes: string; | |
| } | |
| import { DateTime } from "luxon"; |
Context Used: Rule from dashboard - What: Don't manually define Preferences for getPreferenceValues() or commends Argument interfa... (source)
|
This pull request has been automatically marked as stale because it did not have any recent activity. It will be closed if no further activity occurs in the next 7 days to keep our backlog clean 😊 |
0xdhrv
left a comment
There was a problem hiding this comment.
Thanks for your contribution 🔥
We already have an extension in the Store that deals with Team Timezone. Could we consider enhancing the existing extension below instead of creating another one?
You can extend the existing extension by adding new commands to it, since it seems to have related functionality.
If there are unique features or workflows you’re aiming to add, we’d love to hear them and see if they can be integrated into this to avoid duplication and improve discoverability.
This would help avoid duplication and keep related functionality consolidated in one place.
As mentioned in our extension guidelines here ↗
Hi @0xdhrv thanks for your comment. If you look at the apps they're fundamentally different. Timezone buddy tries to have the concept of keeping track of your friends in different time zones. My app is designed to figure out what time it is in other time zones, then scrub effectively left and right to figure out the overlaps of reasonable times between different different time zones (thus the name, "in-the-timezone"). Use case:
Fundamentally, it requires taking existing time, and scrubbing back and forth to find the corresponding time across the zones. This does not exist in the others and is philosophically different in it's operations and use. I understand that you forsee an overlap, but I think they're fundamentally different use cases and adding to it would change the philosophy of these two apps. Let me know if you'd like me to define mine more clearly. |
|
This pull request has been automatically marked as stale because it did not have any recent activity. It will be closed if no further activity occurs in the next 7 days to keep our backlog clean 😊 |
|
@0xdhrv or any other admin , please let me know what the plan is and if I can provide further clarification. Again as I mentioned above I think these are different use cases. |
| function getDayDiff(localTime: DateTime, baseTime: DateTime): string { | ||
| // Compare calendar dates in their respective timezones | ||
| // Using ordinal (day-of-year) ensures we compare calendar days, not absolute timestamps | ||
| const localDays = localTime.year * 365 + localTime.ordinal; | ||
| const baseDays = baseTime.year * 365 + baseTime.ordinal; | ||
| const diff = localDays - baseDays; | ||
|
|
||
| if (diff === 0) return ""; | ||
| if (diff > 0) return ` +${diff}`; | ||
| return ` ${diff}`; | ||
| } |
There was a problem hiding this comment.
Leap-year bug produces wrong day offset
The formula year * 365 + ordinal does not account for leap years (which have 366 days), causing an off-by-one error when the two cities straddle a Dec 31 → Jan 1 boundary in a leap year.
Concrete example: base is 2024-12-31 (ordinal = 366), local is 2025-01-01 (ordinal = 1):
baseDays = 2024 × 365 + 366 = 739126localDays = 2025 × 365 + 1 = 739126diff = 0— shows "same day" instead of+1
Replace with Luxon's own diff to stay correct across all year boundaries:
| function getDayDiff(localTime: DateTime, baseTime: DateTime): string { | |
| // Compare calendar dates in their respective timezones | |
| // Using ordinal (day-of-year) ensures we compare calendar days, not absolute timestamps | |
| const localDays = localTime.year * 365 + localTime.ordinal; | |
| const baseDays = baseTime.year * 365 + baseTime.ordinal; | |
| const diff = localDays - baseDays; | |
| if (diff === 0) return ""; | |
| if (diff > 0) return ` +${diff}`; | |
| return ` ${diff}`; | |
| } | |
| function getDayDiff(localTime: DateTime, baseTime: DateTime): string { | |
| const diff = Math.round( | |
| localTime.startOf("day").valueOf() / 86400000 - baseTime.startOf("day").valueOf() / 86400000 | |
| ); | |
| if (diff === 0) return ""; | |
| if (diff > 0) return ` +${diff}`; | |
| return ` ${diff}`; | |
| } |
| const isLast = rowIndex === rows.length - 1; | ||
|
|
||
| // Build label: CityName [padded] TimeLabel [padded] GMT Delta | ||
| const isBase = row.offsetMinutes === 0; |
There was a problem hiding this comment.
(base) label shown for any city with the same UTC offset
isBase is determined by whether the city's offset from the base is zero, not by whether it actually is the base city. Two cities that happen to share the same UTC offset at the selected time (e.g. London and UTC in winter) will both display (base), which is misleading.
Pass the base city ID through the config or compare against the baseCityId directly:
| const isBase = row.offsetMinutes === 0; | |
| const isBase = zoneId === baseCityId || (!baseCityId && row.offsetMinutes === 0 && rowIndex === 0); |
(Alternatively, thread baseCityId as an extra field on each row object to keep the check explicit.)
| <Action | ||
| title="Reset to Now" | ||
| icon={Icon.Clock} | ||
| onAction={() => onSetBaseISO(getNextHour())} |
There was a problem hiding this comment.
"Reset to Now" advances to the next full hour, not the current time
getNextHour() rounds up to the next full hour (e.g. at 2:45 PM it returns 3:00 PM). Both the README ("Use Cmd+N to reset to current time") and the action title "Reset to Now" imply the view returns to the actual current moment, which it does not.
If the intent is to snap to the nearest whole hour as a scheduling convenience, consider renaming the action (e.g. "Reset to Next Hour") and updating the README accordingly. If the intent genuinely is to reset to now, replace getNextHour() with new Date().toISOString() (same fix applies in in-the-time-zone.tsx line 221).
Description
In The (Time) Zone helps you coordinate across time zones effortlessly. See at a glance when your team is available with a color-coded timeline view.
Features:
Timeline View — See all your cities at once with working hours highlighted
Time Scrubbing — Use arrow keys to shift time and instantly see how it affects everyone
Smart Colors — Green (9-5 working), Yellow (7-9, 5-12 marginal), Red (12-7 sleeping)
Sunrise/Sunset — Know when the sun rises and sets in each city
Any City — Search and add any city in the world
Perfect for remote teams, scheduling international meetings, or planning calls with friends abroad.
Screencast
Checklist
npm run buildand tested this distribution build in Raycastassetsfolder are used by the extension itselfREADMEare placed outside of themetadatafolder