mirror of
https://github.com/mauriceboe/TREK.git
synced 2026-10-18 21:16:47 +00:00
fix(planner): Google hours that share a half of the day convert whole to 24h
Google writes a range that stays in one half of the day with the meridiem on the closing time only, "1:00 – 3:00 PM" for one to three in the afternoon. The 24-hour conversion only saw times carrying their own AM/PM, so the opener stayed "1:00" beside a converted "15:00". The closing meridiem is handed back to an opener that has none before converting; a range spelled on both sides, the 12h display and lines without a meridiem are untouched. Closes #2412
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
import { describe, it, expect } from 'vitest'
|
||||
import { convertHoursLine, isUnknownHoursLine, splitHoursLine } from './placeHoursFormat'
|
||||
|
||||
describe('convertHoursLine', () => {
|
||||
it('FE-PLANNER-HOURS-001: a range that stays in one half of the day carries the meridiem back to its opener', () => {
|
||||
// Google writes "1:00 – 3:00 PM" for one to three in the afternoon (#2412). The
|
||||
// opener used to stay "1:00" next to a converted "15:00".
|
||||
expect(convertHoursLine('Wednesday: 1:00 – 3:00 PM, 5:00 – 8:00 PM', '24h'))
|
||||
.toBe('Wednesday: 13:00 – 15:00, 17:00 – 20:00')
|
||||
})
|
||||
|
||||
it('FE-PLANNER-HOURS-002: a range spelled on both sides is converted as written', () => {
|
||||
expect(convertHoursLine('Monday: 11:00 AM – 1:00 PM', '24h')).toBe('Monday: 11:00 – 13:00')
|
||||
expect(convertHoursLine('Friday: 5:00 PM – 2:00 AM', '24h')).toBe('Friday: 17:00 – 02:00')
|
||||
})
|
||||
|
||||
it('FE-PLANNER-HOURS-003: twelve stays twelve in the afternoon and turns to zero after midnight', () => {
|
||||
expect(convertHoursLine('Sunday: 12:00 – 3:00 PM', '24h')).toBe('Sunday: 12:00 – 15:00')
|
||||
expect(convertHoursLine('Sunday: 12:00 – 1:00 AM', '24h')).toBe('Sunday: 00:00 – 01:00')
|
||||
})
|
||||
|
||||
it('FE-PLANNER-HOURS-004: a morning range keeps its morning', () => {
|
||||
expect(convertHoursLine('Tuesday: 8:00 – 11:30 AM', '24h')).toBe('Tuesday: 08:00 – 11:30')
|
||||
})
|
||||
|
||||
it('FE-PLANNER-HOURS-005: a plain hyphen separates the same way the en dash does', () => {
|
||||
expect(convertHoursLine('Thursday: 1:00-3:00 PM', '24h')).toBe('Thursday: 13:00-15:00')
|
||||
})
|
||||
|
||||
it('FE-PLANNER-HOURS-006: the 12h display and lines without a meridiem are untouched', () => {
|
||||
expect(convertHoursLine('Wednesday: 1:00 – 3:00 PM', '12h')).toBe('Wednesday: 1:00 – 3:00 PM')
|
||||
expect(convertHoursLine('Montag: 11:30–23:00', '24h')).toBe('Montag: 11:30–23:00')
|
||||
expect(convertHoursLine('Saturday: Open 24 hours', '24h')).toBe('Saturday: Open 24 hours')
|
||||
expect(convertHoursLine('', '24h')).toBe('')
|
||||
})
|
||||
|
||||
it('FE-PLANNER-HOURS-007: 24h lines become 12h, with the German "Uhr" dropped', () => {
|
||||
expect(convertHoursLine('Montag: 09:00 – 21:00 Uhr', '12h')).toBe('Montag: 9:00 AM – 9:00 PM')
|
||||
expect(convertHoursLine('Monday: 00:30 – 12:00', '12h')).toBe('Monday: 12:30 AM – 12:00 PM')
|
||||
})
|
||||
})
|
||||
|
||||
describe('splitHoursLine', () => {
|
||||
it('FE-PLANNER-HOURS-008: splits on the first colon only, the fullwidth one included', () => {
|
||||
expect(splitHoursLine('Monday: 09:00-18:00')).toEqual(['Monday', '09:00-18:00'])
|
||||
expect(splitHoursLine('月曜日:9:00~18:00')).toEqual(['月曜日', '9:00~18:00'])
|
||||
expect(splitHoursLine('Open 24 hours')).toEqual(['', 'Open 24 hours'])
|
||||
})
|
||||
})
|
||||
|
||||
describe('isUnknownHoursLine', () => {
|
||||
it('FE-PLANNER-HOURS-009: a bare question mark is the tag saying nothing', () => {
|
||||
expect(isUnknownHoursLine(' ? ')).toBe(true)
|
||||
expect(isUnknownHoursLine('09:00-18:00')).toBe(false)
|
||||
})
|
||||
})
|
||||
@@ -31,8 +31,18 @@ export function convertHoursLine(line: string, timeFormat: string): string {
|
||||
})
|
||||
}
|
||||
if (timeFormat !== '12h' && hasAmPm) {
|
||||
// Google spells a range that stays in one half of the day with the meridiem on
|
||||
// the closing time only: "1:00 – 3:00 PM" is one to three in the afternoon. The
|
||||
// conversion below only sees times that carry their own AM/PM, so the opener
|
||||
// stayed "1:00" next to a "15:00" (#2412). Hand the closing meridiem back to an
|
||||
// opener that has none. It fires only where nothing but the dash sits between
|
||||
// the two times, so "11:00 AM – 1:00 PM" keeps both halves as written.
|
||||
const paired = line.replace(
|
||||
/(\d{1,2}:\d{2})(\s*[–—-]\s*)(\d{1,2}:\d{2}\s*)(AM|PM)\b/gi,
|
||||
(_, open, sep, close, p) => `${open} ${p}${sep}${close}${p}`,
|
||||
)
|
||||
// 12h → 24h: "10:00 AM" → "10:00", "9:00 PM" → "21:00"
|
||||
return line.replace(/(\d{1,2}):(\d{2})\s*(AM|PM)/gi, (_, h, m, p) => {
|
||||
return paired.replace(/(\d{1,2}):(\d{2})\s*(AM|PM)/gi, (_, h, m, p) => {
|
||||
let hour = Number.parseInt(h)
|
||||
if (p.toUpperCase() === 'PM' && hour !== 12) hour += 12
|
||||
if (p.toUpperCase() === 'AM' && hour === 12) hour = 0
|
||||
|
||||
Reference in New Issue
Block a user