File size: 2,440 Bytes
2e50ccd
 
 
 
 
 
 
 
 
 
 
 
 
9d442c9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2e50ccd
 
 
9d442c9
 
 
 
 
2e50ccd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
export function formatPrice(usd: number): string {
  return `$${Math.round(usd).toLocaleString()}`;
}

export function formatDuration(minutes: number): string {
  const h = Math.floor(minutes / 60);
  const m = minutes % 60;
  if (h === 0) return `${m}m`;
  if (m === 0) return `${h}h`;
  return `${h}h ${m}m`;
}

export function formatTime(isoString: string): string {
  // Extract HH:MM directly from ISO string to preserve the airport's
  // local timezone. new Date() would convert to the browser's timezone.
  const match = isoString.match(/T(\d{2}):(\d{2})/);
  if (!match) {
    return isoString;
  }
  const hours = parseInt(match[1], 10);
  const minutes = match[2];
  const ampm = hours >= 12 ? 'PM' : 'AM';
  const displayHour = hours % 12 || 12;
  return `${displayHour}:${minutes} ${ampm}`;
}

/** Minutes since midnight extracted from ISO string (airport local time). */
export function getLocalMinuteOfDay(isoString: string): number {
  const match = isoString.match(/T(\d{2}):(\d{2})/);
  if (!match) return 0;
  return parseInt(match[1], 10) * 60 + parseInt(match[2], 10);
}

/** Number of calendar days between two ISO date-times (in their local timezones). */
export function daysBetween(isoA: string, isoB: string): number {
  const dateA = isoA.split('T')[0];
  const dateB = isoB.split('T')[0];
  return Math.round(
    (new Date(dateB).getTime() - new Date(dateA).getTime()) / 86400000,
  );
}

export function formatDate(isoString: string): string {
  // Parse from the date portion of the ISO string (airport local date)
  const datePart = isoString.split('T')[0];
  const [y, m, d] = datePart.split('-').map(Number);
  const dt = new Date(y, m - 1, d); // local-date-only, no TZ conversion
  return dt.toLocaleDateString('en-US', {
    weekday: 'short',
    month: 'short',
    day: 'numeric',
  });
}

export function formatStops(stops: number): string {
  if (stops === 0) return 'Nonstop';
  if (stops === 1) return '1 stop';
  return `${stops} stops`;
}

export function cabinClassLabel(cls: string): string {
  const labels: Record<string, string> = {
    economy: 'Economy',
    premium_economy: 'Premium Economy',
    business: 'Business',
    first: 'First',
  };
  return labels[cls] || cls;
}

export function tripTypeLabel(t: string): string {
  const labels: Record<string, string> = {
    round_trip: 'Round trip',
    one_way: 'One way',
    multi_city: 'Multi-city',
  };
  return labels[t] || t;
}