using System.Globalization; using System.Text.RegularExpressions; using Core.Parsers.EventOccurrence; namespace GoogleSheetsScheduleImport; /// /// Parses time labels from the first column of schedule grids. /// public static class TimeCellParser { private static readonly Regex ClockRegex = new( @"^(?\d{1,2})(?::(?\d{2}))?\s*(?a\.?m\.?|p\.?m\.?|AM|PM|am|pm)\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase); public static bool TryParse(string? cellText, out TimeOnly time) { time = default; if (string.IsNullOrWhiteSpace(cellText)) return false; var t = cellText.Trim(); if (t.Equals("NOON", StringComparison.OrdinalIgnoreCase)) { time = new TimeOnly(12, 0); return true; } var m = ClockRegex.Match(t); if (m.Success) { var h = int.Parse(m.Groups["h"].Value, CultureInfo.InvariantCulture); var minute = m.Groups["m"].Success ? int.Parse(m.Groups["m"].Value, CultureInfo.InvariantCulture) : 0; var apStr = m.Groups["ap"].Value; var isPm = apStr.Contains('P', StringComparison.OrdinalIgnoreCase); var isAm = apStr.Contains('A', StringComparison.OrdinalIgnoreCase); if (isPm && h < 12) h += 12; if (isAm && h == 12) h = 0; time = new TimeOnly(h, minute); return true; } // Fallback: use core TimeParser if string already looks like parsed format try { time = TimeParser.Parse(t); return true; } catch (FormatException) { return false; } } }