@@ -542,6 +542,54 @@ class Events {
542542 return rows ;
543543 }
544544
545+ /**
546+ * Parses time in 12-hour format (e.g., "9:30pm") and converts to 24-hour format
547+ * @param {string } timeStr - Time string in 12-hour format (e.g., "9:30pm", "10am")
548+ * @returns {{hours: number, minutes: number} } Object with hours (0-23) and minutes (0-59) in 24-hour format
549+ */
550+ static parseTime12Hour ( timeStr ) {
551+ const trimmed = timeStr . trim ( ) . toLowerCase ( ) ;
552+ const isPM = trimmed . includes ( 'pm' ) ;
553+ const isAM = trimmed . includes ( 'am' ) ;
554+
555+ // Validate that time has am/pm indicator
556+ if ( ! isPM && ! isAM ) {
557+ console . warn ( `Time string "${ timeStr } " missing am/pm indicator, defaulting to PM` ) ;
558+ }
559+
560+ // Remove am/pm and any spaces
561+ const timeOnly = trimmed . replace ( / a m | p m / g, '' ) . trim ( ) ;
562+
563+ // Split hours and minutes
564+ const parts = timeOnly . split ( ':' ) ;
565+ let hours = parseInt ( parts [ 0 ] ) ;
566+ const minutes = parts [ 1 ] ? parseInt ( parts [ 1 ] ) : 0 ;
567+
568+ // Validate parsed values
569+ if ( isNaN ( hours ) || hours < 1 || hours > 12 ) {
570+ console . error ( `Invalid hours value in time string "${ timeStr } "` ) ;
571+ hours = 12 ; // Default to noon/midnight
572+ }
573+ if ( isNaN ( minutes ) || minutes < 0 || minutes > 59 ) {
574+ console . error ( `Invalid minutes value in time string "${ timeStr } "` ) ;
575+ minutes = 0 ; // Default to :00
576+ }
577+
578+ // Convert to 24-hour format
579+ if ( isPM && hours !== 12 ) {
580+ hours += 12 ;
581+ } else if ( isAM && hours === 12 ) {
582+ hours = 0 ;
583+ } else if ( ! isPM && ! isAM ) {
584+ // Default to PM if no indicator
585+ if ( hours !== 12 ) {
586+ hours += 12 ;
587+ }
588+ }
589+
590+ return { hours, minutes } ;
591+ }
592+
545593 /**
546594 * Generates and returns a google maps info window
547595 *
@@ -554,22 +602,27 @@ class Events {
554602 this . cachedInfoWindow = new google . maps . InfoWindow ( { } ) ;
555603 if ( event ) {
556604 const time = event . time . split ( '-' ) ;
557- const start = new Date ( `${ event . date } ${ time [ 0 ] } ` ) ;
605+
606+ // Parse start time properly
607+ const startTime = Events . parseTime12Hour ( time [ 0 ] ) ;
608+ const start = new Date ( event . date ) ;
609+ start . setHours ( startTime . hours , startTime . minutes , 0 , 0 ) ;
558610 const startDate = start . toLocaleDateString ( 'sv-SE' ) ; // outputs yyyy-mm-dd
559- let endToken ;
611+
612+ let end ;
560613 if ( time [ 1 ] ) {
561- // Is event overnight?
562- if ( time [ 1 ] . includes ( 'am' ) && time [ 0 ] . includes ( 'pm' ) ) {
563- let endDate = new Date ( start ) ;
564- endDate . setDate ( endDate . getDate ( ) + 1 ) ;
565- endToken = ` ${ endDate . toLocaleDateString ( 'sv-SE' ) . replace ( / - / gi , '/' ) } ${ time [ 1 ] } ` ;
566- } else { // same day
567- endToken = ` ${ startDate . replace ( / - / gi , '/' ) } ${ time [ 1 ] } ` ;
614+ const endTime = Events . parseTime12Hour ( time [ 1 ] ) ;
615+ end = new Date ( event . date ) ;
616+ end . setHours ( endTime . hours , endTime . minutes , 0 , 0 ) ;
617+
618+ // Is event overnight? (end time is earlier than start time)
619+ if ( end < start ) {
620+ end . setDate ( end . getDate ( ) + 1 ) ;
568621 }
569- } else { // default 1 hour duration
570- endToken = start . getTime ( ) + 60 * 60 * 1000 ;
622+ } else {
623+ // default 1 hour duration
624+ end = new Date ( start . getTime ( ) + 60 * 60 * 1000 ) ;
571625 }
572- const end = new Date ( endToken ) ;
573626 const headerContent = document . createElement ( 'div' ) ;
574627 headerContent . innerHTML = `
575628 <h2><a target="_blank" href="${ event . url } " title="Event Page">${ event . title } </a></h2>
0 commit comments