How to write a regex for a date-time string

Viewed 43

dateTime = "SATURDAY1200PM1230PMWEEKLY"

Desired Result: "12:00 PM - 12:30 PM"

I tried doing this: let str = "SATURDAY600PM630PMWEEKLY".split(/[^A-Z][0-9]{3,4}(A|P)M/);

But I keep getting an array with chars/numbers. I am unsure if split is the way to go here.

3 Answers

Try a match approach:

var dateTime = "SATURDAY1200PM1230PMWEEKLY";
var ts = dateTime.match(/\d{3,4}[AP]M/g)
                 .map(x => x.replace(/(\d{1,2})(\d{2})([AP]M)/, "$1:$2 $3"))
                 .join(" - ");
console.log(ts);

As the programming language was not given I will provide a straightforward solution in Ruby which I expect could be converted easily to most other languages.

str = "SATURDAY1130AM130PMWEEKLY"
rgx = /\A[A-Z]+(\d{1,2})(\d{2})([AP]M)(\d{1,2})(\d{2})([AP]M)[A-Z]+\z/
m = str.match(rgx)
  #=> #<MatchData "1130AM130PM" 1:"11" 2:"30" 3:"AM" 4:"1" 5:"30" 6:"PM">
"%s:%s %s - %s:%s %s" % [$1, $2, $3, $4, $5, $6]
  #=> "11:30 AM - 1:30 PM"

Demo


The regular expression could be broken down as follows.

\A         # match beginning of string
[A-Z]+     # match one or more uppercase letters
(\d{1,2})  # match 1 or 2 digits, save to capture group 1
(\d{2})    # match 2 digits, save to capture group 2  
([AP]M)    # match 'AM' or 'PM', save to capture group 3
(\d{1,2})  # match 1 or 2 digits, save to capture group 4
(\d{2})    # match 2 digits, save to capture group 5  
([AP]M)    # match 'AM' or 'PM', save to capture group 6
[A-Z]+     # match one or more uppercase letters
\z         # match end of string

The last statement could also be written:

"%s:%s %s - %s:%s %s" % m.captures
  #=> "11:30 AM - 1:30 PM"

which of course is specific to Ruby.


Another way is to make use of a language's date-time library. Again, this could be done as follows in Ruby.

require 'time'
s1, s2 = str.scan(/\d{3,4}[AP]M/).map do |s|
  s.sub(/(?=\d{2}[AP])/, ' ')
end
  #=> ["11 30AM", "1 30PM"]
t1 = DateTime.strptime(s1, '%I %M%p')
  #=> #<DateTime: 2022-02-01T11:30:00+00:00
  #   ((2459612j,41400s,0n),+0s,2299161j)>
t2 = DateTime.strptime(s2, '%I %M%p')
  #=> #<DateTime: 2022-02-01T13:30:00+00:00
  #   ((2459612j,48600s,0n),+0s,2299161j)>
t1.strftime('%l:%M %p') + " - " + t2.strftime('%l:%M %p')
  #=> "11:30 AM -  1:30 PM"

If you are wondering why .map do |s| s.sub(/(?=\d{2}[AP])/, ' ') end is needed in calculating s1 and s2 try removing it and changing the format string to '%I%M%p'.

Solution is use match and then convert resoult to your string

let str = "SATURDAY600PM630PMWEEKLY"
    .match(/[\d]{3,4}(A|P)M/g)
    .map((time) => {
      const AMPM = time.slice(-2);
      const m = time.slice(-4,-2);
      const h = time.slice(0,-4);
      return `${h}:${m} ${AMPM}`;
    })
    .join(' - ')

console.log(str)

Related