For the date and datetime attributes in your Ruby on Rails application the likelihood is that you won’t use the cumbersome date_select and datetime_select helpers in your forms.
Instead you’re likely to choose a more user-friendly input that allows your users to either select from a dropdown or manually enter the desired date and time.
In addition, you’ll want to both display the date/time and accept values in the format familiar to your user based on their locale. This is particularly relevant when you have users in the US where the date format is month/day/year and users in other countries that use the day/month/year format.
Now your application needs to be able to parse these varying formats. To convert string values, ActiveRecord makes use of methods added to the String class by ActiveSupport (such as to_date) which in turn use Ruby parse methods (such as Date.parse). The Ruby parse methods expect the format to always be year/month/day or day/month/year so will fail to parse some valid month/day/year values:
I18n.locale = :"en-US" Album.new(released_at: "12/22/2022").released_at =# => nil
and interpret other month/day/year values incorrectly:
I18n.locale = :"en-US" Album.new(released_at: "02/06/2022").released_at # => Thu, 02 Jun 2022
This is where the Flexitime gem from Circle Software & Design comes to your aid. The gem is a Ruby date/time string parser with the intended purpose of converting a string value received from a UI or API into an ActiveSupport::TimeWithZone object. It offers the flexibility of deciphering date/time strings in the most common formats with the ability to self-determine the expected order of the date parts based on the locale.
So taking the examples above, Flexitime is able to correctly parse the input values based on the locale.
I18n.locale = :"en-US" Flexitime.parse("12/22/2022").to_date # => Thu, 22 Dec 2022 Flexitime.parse("02/06/2022").to_date # => Sun, 06 Feb 2022 I18n.locale = :"en-GB" Flexitime.parse("02/06/2022").to_date # => Thu, 02 Jun 2022
Flexitime uses ActiveSupport::TimeZone so it can parse times using the specified time zone.
Time.zone = "Europe/London" Flexitime.parse("01/06/2021 17:00") # => Tue, 01 Jun 2021 17:00:00.000000000 BST +01:00
Flexitime includes both configuration options and method arguments allowing you to manually set the expected ordering of the day and month parts (i.e. dd/mm or mm/dd) and specify a desired precision for the returned time object say, for example, when you only want to persist times to a minute precision without seconds.
Time.zone = "America/New_York" Flexitime.parse("01/06/2021 17:30", first_date_part: :month) # => Wed, 06 Jan 2021 17:30:00.000000000 EST -05:00 Flexitime.parse("2021-08-23T12:35:20.533314Z", precision: :min) # => Mon, 23 Aug 2021 08:35:00.000000000 EDT -04:00
Flexitime also caters for formats that are not recognised by and give unexpected results when using the built in Date.parse and Time.zone.parse, such as single digit days & months and two digit years in the day/month/year format and hours with a period separator.
Time.zone = "Europe/London" Time.zone.parse("1/8/22 8.15") # => Wed, 22 Aug 0001 00:00:00.000000000 LMT -00:01 Flexitime.parse("1/8/22 8.15") # => Mon, 01 Aug 2022 08:15:00.000000000 BST +01:00
Additionally, you lose nothing from using Flexitime because when it is unable to decipher a format it will attempt to parse the string using the TimeZone class.
Get in touch
Do you need help building user friendly date and time calendar functionality into your application? Or want more information about our Flexitime gem? We’re experts in developing Ruby on Rails applications and functionality so if you want to outsource some of your Ruby development or looking for some consultancy throughout your project, get in touch today on firstname.lastname@example.org or through our contact form.