2 examples

Incorrect timestamp

Incorrect or improperly formatted timestamp, causing errors.

[ FAQ1 ]

What is an incorrect timestamp?

An incorrect timestamp occurs when date or time values are inaccurately recorded, represented, or interpreted, causing inconsistencies such as incorrect timezone conversions, formatting mistakes, or system clock mismatches. Common reasons include misunderstanding of UTC versus local time, improper timestamp formatting, or synchronization errors resulting in clock skew across systems. Incorrect timestamps can lead to logic errors, incorrect scheduling, confusing data records, and unexpected application behavior.
[ FAQ2 ]

How to fix incorrect timestamp issues

To fix incorrect timestamp issues, clearly define and consistently apply standard timestamp formats (e.g., ISO 8601) and timezone conventions (typically UTC) across applications. Explicitly handle timezone conversions and ensure timestamps are accurately adjusted for local contexts where necessary. Regularly synchronize system clocks across distributed or networked environments to minimize clock skew. Use reliable date-time libraries and tools that simplify handling, conversion, and validation of timestamps, reducing the likelihood of errors and ensuring accurate date-time consistency.
diff block
+import { useState, useEffect, useCallback } from "react";
+import {
+ List,
+ ActionPanel,
+ Action,
+ showToast,
+ Toast,
+ Icon,
+ LocalStorage,
+ Clipboard,
+ getPreferenceValues,
+ open,
+} from "@raycast/api";
+import { SearchResult } from "exa-js";
+import exa from "./exa";
+import { typeid } from "typeid-js";
+import Fuse from "fuse.js";
+
+// Constants
+const STORAGE_KEY_PREFIX = "exa_similar";
+
+// Types
+interface SimilarSearch {
+ id: string;
+ url: string;
+ results: SearchResult<{ text: true }>[];
+ metadata?: Record<string, string>;
+ createdAt: Date;
+}
+
+interface Preferences {
+ apiKey: string;
+}
+
+// Utility functions
+function formatRelativeTime(date: Date): string {
+ // Make sure we have a valid date
+ if (!date || isNaN(date.getTime())) {
+ return "unknown time";
+ }
+
+ const now = new Date();
+ const diffMs = now.getTime() - date.getTime();
+ const diffSec = Math.floor(diffMs / 1000);
+ const diffMin = Math.floor(diffSec / 60);
+ const diffHour = Math.floor(diffMin / 60);
+ const diffDay = Math.floor(diffHour / 24);
+
+ if (diffSec < 60) return "just now";
+ if (diffMin < 60) return `${diffMin}m ago`;
+ if (diffHour < 24) return `${diffHour}h ago`;
+ if (diffDay < 7) return `${diffDay}d ago`;
+
+ // For older dates, show the actual date
+ return date.toLocaleDateString(undefined, {
+ year: "numeric",
+ month: "short",
+ day: "numeric",
+ });
+}
+
+// Main Component
+export default function Command() {
+ // State
+ const [searchText, setSearchText] = useState("");
+ const [selectedSearch, setSelectedSearch] = useState<SimilarSearch | null>(null);
+ const [allSearches, setAllSearches] = useState<SimilarSearch[]>([]);
+ const [pendingSearches, setPendingSearches] = useState<Record<string, boolean>>({});
+ const [isLoading, setIsLoading] = useState(true);
+ const [viewMode, setViewMode] = useState<"searches" | "results">("searches");
+ const [filteredResults, setFilteredResults] = useState<SearchResult<{ text: true }>[]>([]);
+ const [resultsSearchText, setResultsSearchText] = useState("");
+
+ // We don't need navigation pop since we're handling navigation with state
+
+ // Get preferences once
+ const preferences = getPreferenceValues<Preferences>();
+
+ // Load all saved similar searches
+ useEffect(() => {
+ async function loadSavedSearches() {
+ try {
+ setIsLoading(true);
+ const allItems = await LocalStorage.allItems();
+
+ const searches: SimilarSearch[] = Object.entries(allItems)
+ .filter(([key]) => key.startsWith(STORAGE_KEY_PREFIX))
+ .map(([_, value]) => {
+ const search = JSON.parse(value) as SimilarSearch;
+
+ // Ensure createdAt is a proper Date object
+ if (!search.createdAt) {
+ // Default to now if missing
+ search.createdAt = new Date();
+ } else if (typeof search.createdAt === "string") {
+ // Parse the date string into a Date object
+ search.createdAt = new Date(search.createdAt);
+ } else {
+ // If it's an object but not a proper Date instance, convert it
+ const timestamp =
+ search.createdAt instanceof Date
+ ? search.createdAt.getTime()
+ : new Date(search.createdAt as any).getTime();
+ search.createdAt = new Date(timestamp);
+ }
+
+ return search;
+ });
+
+ // Sort by timestamp (newest first)
+ searches.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime());
+ setAllSearches(searches);
+ } catch (error) {
+ console.error("Error loading saved similar searches:", error);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Failed to load saved similar searches",
+ });
+ } finally {
+ setIsLoading(false);
+ }
+ }
+
+ loadSavedSearches();
+ }, []);
+
+ // Update filtered results when selected search or results search text changes
+ useEffect(() => {
+ if (selectedSearch?.results) {
+ if (!resultsSearchText) {
+ setFilteredResults(selectedSearch.results);
+ return;
+ }
+
+ // Use Fuse.js for fuzzy searching
+ const fuse = new Fuse(selectedSearch.results, {
+ keys: ["title", "text", "url"],
+ threshold: 0.4,
+ includeScore: true,
+ });
+
+ const searchResults = fuse.search(resultsSearchText);
+ setFilteredResults(searchResults.map((result) => result.item));
+ }
+ }, [selectedSearch, resultsSearchText]);
+
+ // We'll handle navigation using the actionPanel back action instead of keyboard events
+
+ // Find similar pages
+ const findSimilar = useCallback(
+ async (url: string): Promise<void> => {
+ if (!url.trim()) return;
+
+ // Basic URL validation
+ if (!url.startsWith("http://") && !url.startsWith("https://")) {
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Invalid URL",
+ message: "Please enter a valid URL starting with http:// or https://",
+ });
+ return;
+ }
+
+ const finalUrl = url.trim();
+ const id = typeid(STORAGE_KEY_PREFIX).toString();
+
+ // Create similar search object with current timestamp
+ const currentTime = new Date();
+ const newSearch: SimilarSearch = {
+ id,
+ url: finalUrl,
+ results: [],
+ createdAt: currentTime,
+ };
+
+ // Add to pending searches
+ setPendingSearches((prev) => ({ ...prev, [id]: true }));
+
+ // Add to state immediately and select it
+ setAllSearches((prev) => [newSearch, ...prev]);
+ setSelectedSearch(newSearch);
+ setViewMode("results");
+ setResultsSearchText("");
+
+ // Clear search text
+ setSearchText("");
+
+ // Show toast
+ const toast = await showToast({
+ style: Toast.Style.Animated,
+ title: "Finding similar pages with Exa...",
+ });
+
+ try {
+ // Make API request
+ const start = performance.now();
+ const response = await exa.findSimilarAndContents(finalUrl, {
+ text: true,
+ numResults: 20,
+ });
+ const latencyMs = performance.now() - start;
+
+ // Update search with response
+ const updatedSearch = {
+ ...newSearch,
+ results: response.results as SearchResult<{ text: true }>[],
+ metadata: {
+ latencyMs: latencyMs.toFixed(0),
+ resultCount: response.results.length.toString(),
+ },
+ };
+
+ // Update state with the response
+ setAllSearches((prev) => prev.map((s) => (s.id === id ? updatedSearch : s)));
+ setSelectedSearch(updatedSearch);
+ setFilteredResults(updatedSearch.results);
+
+ // Prepare for storage - convert Date to ISO string for proper serialization
+ const searchToStore = {
+ ...updatedSearch,
+ createdAt: updatedSearch.createdAt.toISOString(),
+ };
+
+ // Save to local storage - ensure we're using a consistent key format
+ console.log(`Saving similar search with ID: ${id}`);
+ await LocalStorage.setItem(id, JSON.stringify(searchToStore));
+
+ // Update toast
+ toast.style = Toast.Style.Success;
+ toast.title = "Similar pages found";
+ toast.message = `${response.results.length} results in ${latencyMs.toFixed(0)}ms`;
+ } catch (error) {
+ console.error("Error finding similar pages:", error);
+
+ // Remove from state if failed
+ setAllSearches((prev) => prev.filter((s) => s.id !== id));
+ setSelectedSearch(null);
+ setViewMode("searches");
+
+ // Show error toast
+ toast.style = Toast.Style.Failure;
+ toast.title = "Error finding similar pages";
+ toast.message = error instanceof Error ? error.message : String(error);
+ } finally {
+ // Remove from pending searches
+ setPendingSearches((prev) => {
+ const newPending = { ...prev };
+ delete newPending[id];
+ return newPending;
+ });
+ }
+ },
+ [preferences],
+ );
+
+ // Delete a search
+ const deleteSearch = useCallback(
+ async (id: string): Promise<void> => {
+ try {
+ console.log(`Attempting to delete similar search with ID: ${id}`);
+
+ // First update in-memory state
+ setAllSearches((prev) => {
+ const filtered = prev.filter((s) => s.id !== id);
+ return filtered;
+ });
+
+ // Update selection if needed
+ if (selectedSearch?.id === id) {
+ setSelectedSearch(null);
+ setViewMode("searches");
+ }
+
+ // Clear this specific item from storage
+ try {
+ // Get all items from storage first
+ const allItems = await LocalStorage.allItems();
+
+ // Look for the specific key that contains our ID
+ for (const key of Object.keys(allItems)) {
+ if (key === id) {
+ console.log(`Found exact key match: ${key}`);
+ await LocalStorage.removeItem(key);
+ }
+ }
+
+ // Also try the prefixed version as fallback
+ await LocalStorage.removeItem(`${STORAGE_KEY_PREFIX}_${id}`);
+ await LocalStorage.removeItem(STORAGE_KEY_PREFIX + id);
+ } catch (storageError) {
+ console.error("Error accessing storage during delete:", storageError);
+ }
+
+ // Show success message - we show success even if storage fails, since UI state is updated
+ await showToast({
+ style: Toast.Style.Success,
+ title: "Search removed from history",
+ });
+ } catch (error) {
+ console.error("Error deleting search:", error);
+ await showToast({
+ style: Toast.Style.Failure,
+ title: "Failed to delete search",
+ message: error instanceof Error ? error.message : String(error),
+ });
+ }
+ },
+ [selectedSearch],
+ );
+
+ // Handle clipboard copy
+ const handleCopyText = useCallback(async (text: string) => {
+ await Clipboard.copy(text);
+ await showToast({
+ style: Toast.Style.Success,
+ title: "Copied to clipboard",
+ });
+ }, []);
+
+ // Open URL in browser
+ const handleOpenURL = useCallback(async (url: string) => {
+ await open(url);
+ }, []);
+
+ // Generate markdown for detail view
+ const generateResultMarkdown = useCallback((result: SearchResult<{ text: true }>): string => {
+ let md = `## ${result.title || "Untitled"}\n\n`;
+ md += `URL: ${result.url}\n\n`;
+
+ if (result.score) {
+ md += `Similarity: ${result.score.toFixed(2)}\n\n`;
+ }
+
+ if (result.publishedDate) {
+ md += `Published: ${new Date(result.publishedDate).toLocaleString()}\n\n`;
+ }
+
+ md += `---\n\n`;
+
+ if (result.text) {
+ md += result.text;
+ } else {
+ md += "_No content available_";
+ }
+
+ md += `\n\n[Open in Browser](${result.url})`;
+
+ // Add minimal metadata at the bottom
+ md += `\n\n${result.id}`;
+
+ return md;
+ }, []);
+
+ // View a search's results
+ const viewSearchResults = useCallback((search: SimilarSearch) => {
+ setSelectedSearch(search);
+ // If the search has results, select the first one to show detail view
+ if (search.results && search.results.length > 0) {
+ setFilteredResults(search.results);
+ }
+ setViewMode("results");
+ setResultsSearchText("");
+ }, []);
+
+ // Back to search list
+ const backToSearches = useCallback(() => {
+ setViewMode("searches");
+ setSelectedSearch(null);
+ setResultsSearchText("");
+ }, []);
+
+ // Handle search bar submission
+ const handleSubmit = useCallback(() => {
+ if (searchText.trim()) {
+ findSimilar(searchText);
+ }
+ }, [searchText, findSimilar]);
+
+ // Filter searches based on search text
+ const filteredSearches = allSearches.filter(
+ (search) => !searchText.trim() || search.url.toLowerCase().includes(searchText.toLowerCase()),
+ );
+
+ // Render Results View
+ if (viewMode === "results" && selectedSearch) {
+ return (
+ <List
+ isLoading={isLoading || pendingSearches[selectedSearch.id]}
+ searchBarPlaceholder="Filter results..."
+ onSearchTextChange={setResultsSearchText}
+ searchText={resultsSearchText}
+ navigationTitle={`Similar to "${selectedSearch.url}"`}
+ isShowingDetail
+ actions={
+ <ActionPanel>
+ <Action
+ title="Back to URL History"
+ icon={Icon.ArrowLeft}
+ onAction={backToSearches}
+ shortcut={{ modifiers: ["cmd"], key: "backspace" }}
+ />
+ <Action
+ title="Find Similar Again"
+ icon={Icon.Link}
+ onAction={() => findSimilar(selectedSearch.url)}
+ shortcut={{ modifiers: ["cmd"], key: "r" }}
+ />
+ </ActionPanel>
+ }
+ >
+ <List.Section title={`${filteredResults.length} Similar Pages`} subtitle={selectedSearch.url}>
+ {filteredResults.map((result) => (
+ <List.Item
+ key={result.id}
+ title={result.title || "Untitled"}
+ icon={Icon.Document}
+ accessories={[
+ { text: formatRelativeTime(result.publishedDate ? new Date(result.publishedDate) : new Date()) },
Greptile
greptile
style: Using new Date() as fallback could show incorrect timestamps - consider showing 'No date' instead
diff block
+import { useEffect, useState } from "react";
+import {
+ Action,
+ ActionPanel,
+ Icon,
+ List,
+ Toast,
+ showToast,
+ Color,
+ Clipboard,
+ Alert,
+ confirmAlert,
+ trash,
+ showInFinder,
+ useNavigation,
+ Form,
+ getPreferenceValues,
+} from "@raycast/api";
+import { showFailureToast } from "@raycast/utils";
+import fs from "fs-extra";
+import path from "path";
+import { exec } from "child_process";
+import { listAudioFiles, getAudioDuration } from "./utils/audio";
+import { saveTranscription, transcribeAudio, loadTranscription } from "./utils/ai/transcription";
+import { formatDate, formatDuration, formatFileSize } from "./utils/formatting";
+import { TranscriptionFile, TranscriptionResult, Preferences, TranscriptionModelId } from "./types";
+import { LANGUAGE_OPTIONS, TRANSCRIPTION_MODELS, buildCompletePrompt } from "./constants";
+
+export default function TranscriptionHistory() {
+ const { push } = useNavigation();
+ const [files, setFiles] = useState<TranscriptionFile[]>([]);
+ const [isLoading, setIsLoading] = useState(true);
+ const [searchText, setSearchText] = useState("");
+ const [isShowingDetails, setIsShowingDetails] = useState(true);
+
+ const parseRecordingDate = (fileName: string): Date => {
+ const regex = /recording-(.+)\.wav$/;
+ const dateMatch = regex.exec(fileName);
+ const dateStr = dateMatch
+ ? dateMatch[1].replace(/-/g, (match, offset) => {
+ if (offset === 10) return "T"; // After date
+ if (offset > 10) return offset === 13 || offset === 16 ? ":" : "."; // Time separators
+ return "-"; // Date separators
+ })
+ : "";
+
+ return dateStr ? new Date(dateStr) : new Date();
Greptile
greptile
style: Falling back to new Date() could lead to incorrect timestamps. Consider throwing an error if date parsing fails ```suggestion + if (!dateStr) throw new Error(`Invalid recording date format in filename: ${fileName}`); + return new Date(dateStr); ```