MTJ Hax

Ruby 1.8 strftime works differently on Linux and Windows

Posted in code, ruby, ruby on rails by mtjhax on December 27, 2010

Running Ruby 1.8 on Linux, cygwin, Mac, any POSIX environment:

now = Time.now
=> Mon Dec 27 18:28:28 -0500 2010
now.strftime("%l") # that's a lowercase "L"
=> " 6"

Under Windows using the exact same Ruby version and patch level:

now = Time.now
=> Mon Dec 27 18:28:28 -0500 2010
now.strftime("%l") # that's a lowercase "L"
=> ""

What? It turns out in Ruby 1.8 they cheated by simply calling the standard C strftime() function to implement Ruby’s strftime method. Because different compilers implement strftime() differently, compiling it under Windows results in a different set of supported % directives. Specifically, it looks like under Windows only the basic ANSI C version is implemented, but under POSIX compilers you get a mix of directives defined by ANSI and other standards like Gnu and Single Unix Specification. The “%l” directive was not even listed in the Ruby 1.8 docs — it worked by accident.

The good news is in Rails 1.9 they appear to have implemented their own strftime for consistency, instead of handing it off to the C compiler. If you need to fix this in the meantime, I provide the following monkey patch (which I simply place in my Rails config/initializers folder on any Windows developer machine):

# monkey patch Ruby strftime methods to implement
# %l directive that is missing in Windows Ruby
#
# as a monkey patch, just use this on your Windows
# development boxes to bridge the gap, it's not
# recommended for production
#
# notes:
# - you may want to add support for other missing directives
# - check your RUBY_PLATFORM and make sure it is in the regexp below
#
if RUBY_PLATFORM =~ /mingw32|mingw64|mswin32|mswin64/

  class Time
    alias_method :original_strftime, :strftime
    def strftime(fmt)
      hour12 = "%2d" % ((hour + 11) % 12 + 1)
      original_strftime(fmt.gsub(/%l/, hour12))
    end
  end
 
  class Date
    alias_method :original_strftime, :strftime
    def strftime(fmt)
      hour12 = "%2d" % ((hour + 11) % 12 + 1)
      original_strftime(fmt.gsub(/%l/, hour12))
    end
  end

end
About these ads
Tagged with: , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: