Skip to main content
How To Build A Forum:

Forum Series Part 7: Time Zones using the local_time Gem

24

Episode 31 · November 6, 2014

A look into times, timezones, and how to handle it better with javascript

Gems Frontend Javascript Timezones


Transcripts

In today's episode, we're going to talk about time zones a little bit, then use the local time gem to handle displaying local times based upon the dates and times that we have saved in our application. What happens with your Rails application, when you save a date time, you always want to save that in your database as a UTC time stamp, because that's sort of the de-facto standard. All of the time zones are based off of UTC, plus or minus a certain number of hours. So if we set that as the default in the database, we'll be able to just calculate the difference based on the time zone that the user's in.

Let's go to our app/views/forum_posts/_forum_post.html.erb, the time stamps for each of those forum posts that we created. I'm going to paste this in here

on <%= forum_post.created_at.strftime("%B %d, %Y at %l:%M %p") %>

Which displays the month, the date, the year, the hour, the minute and the AM/PM operator. So you can refresh the page and you'll see that these posts were posted by me on October 23, 2014 at 2:47 PM, and this is going to be a UTC time stamp. So one thing that's really useful for writing these time formats out is the website strfti.me, all of the different formatting options that you have and use that to manipulate what you display, so you can even include the %Z and display the time zone there, and it's probably useful is we show that here, when we refresh our forum, you can see that it's definitely the UTC time stamp, so definitely bookmark strfti.me because it's almost invaluable and you don't have to do much and you can double check to make sure that your format is correct really easily in its own application.

Coming back to our forum, you can see that we have a prettier time, but it's still in UTC format, so how do we go change that?

Inside your application.rb, there's usually this line:

# config.time_zone = 'Central Time (US & Canada)'

and you can delete this (# symbol) and set it up so that by default, your application will run in that time, so then Active Record, as the comment says here, will convert times to this zone for you.

If we save this and we restart our Rails server, and then we go back to Chrome and refresh our page, you'll see that now we have 7:47 CDT, so this is automatically converted the time zone to central time for us, and that will be global. The problem is when you have users that are in different time zones, so for us this is great and handles things, but you know what, it's the internet and people come from all around the world, and need to see times that are more convenient to them, they need to actually know that it's in their time zone. So this global format is fine but it's not the best thing that we need to make our application really really nice. So I'm going to comment this back out, restart our Rails server again, and we're going to take a look at the local time gem.

The local_time gem is written by Basecamp, and what it does, is it generates times for you and then when you print them out in your views, it will generate a time tag, so these time tags, rather than what I've written here, which is just text on the page in the html, these will actually render html tags called time tags, and then it will set a bunch of different attributes here.

So it sets a JavaScript parsable datetime string so that JavaScript can parse it, and the you can see that it has a data-local and a data-format, so this format will be used by the JavaScript to render out this string inside that the user will be able to see it. So we'll be able to add these data attributes that are hidden in the html, and basically control what gets displayed. They also have lots of awesome features here, such as formatting, that you can override, as well as time_ago which if your familiar with something like Twitter, you'll see that this tweet was sent one second ago, 32 seconds ago, yesterday, Tuesday and so on. So as time goes further away, you can see that these posts are a little bit less accurate, so if it's the current year, you can save the year, you don't need to display it, but as time goes on, you can do all of that.

This gem is incredibly useful for this, and it allows us to set these up so that when you view this in your browser, depending on what your browser's timestamp is, you'll get the right date.

If we go to our Gemfile and add the gem 'local_time', here, we can see that I've got a few gems from previous things so you can ignore those, or check out those episodes, but the gem local_time currently the version is 1.0.0 and we'll install that and run bundle and restart our Rails server. Once this is done, we'll refresh the page and make sure that we get the UTC timestamps again, and we'll be able to verify that I've reset the global application time and that has happened, so we're back at 12:47 PM UTC and with this local time gem, it's really really simple.

If we scroll down to the installation section here, all you have to do is add the gem, run bundle install, and then add //= require local_time into your application.js file. Let's go down below Turbolinks and paste that in, and now we can refresh our page. Nothing changed, the JavaScript is now loaded, though, as we can see in the source here, we'll see the local time JavaScript and you can see exactly what they do as well if you're interested in the gem or the JavaScript and how it works.

If we come back here, I really prefer the local time_ago, and we'll play with a few of these different features.

If we go back to our app/views/forum_posts/_forum_post.html.erb, we can change this to:

<%= local_time_ago forum_post.created_at %>

Now when we refresh the page, we'll get the on inside of our texts now so we don't need to include that anymore, and we'll get on October 3rd, because that was a few days ago. Now if we create a new post, we can see that it says now: "a second ago", if we wait a little bit, we can start to see that it changes to be little bit more specific. This will continue updating and be pretty accurate as well as allowing you to hover over it and see the exact time in browser tool tips of when it was posted. And also, if you noticed there, it said CST, which means that it knew that our local time zone is central time because our application is still running in UTC time. This is really neat, it's created this time html tag, we've passed in the time as the datetime parameter, and then this title is what you saw in the hover state here, as well as the text on the page being a little bit different. So this doesn't update in real time, of course, but when you refresh the page, it loads and then runs through every single time tag on the page that fits that format, and we'll continue updating that for you. That's really really neat.

If you want regular times, you can change this to

<%= local_time forum_post.created_at %>

and leave out the ago part, and you'll see that it gets basically the same format that we had before. It leaves out the time zones because they're not really that relevant when you actually have correct times like this, based upon your browser, and you can actually trust that the time is what you expect it to be, so that's something that can become very very useful when your teams are spread across the world, everybody will know what time relative to them it is, and then they can figure out the translation of what that is in a different time zone if they need to. But most of the time, you're concerned about you and your time of where it's at and where you are.

Now the last thing that I want to point out here is that if you inspect this page you'll see that the time tag here is generated but it gets tweaked by the JavaScript like we mentioned before. Now the original output of this is designed so that the JavaScript can always look at these attributes, so it knows what style you want to display, (time_ago), and then it also knows the time. So this title is what gets added dynamically as well as the text inside of the time tag and those two aspects will never show up in the html, (the JavaScript will generate it).

What happens is your output of this time tag will show a generic thing, such as the exact time in UTC time, and then it allows your Rails application to cache this, so you might save it in a file, you might save it in a fragment or in memcache d or whatever, and it doesn't matter because the JavaScript is the one actually looking at this time and converting it to the correct time. So this is really neat, in that sense that you can save this, and it can be cached, and you don't have to worry about it because this will always display the right thing, and you don't have to break the cache, which is a big problem when it comes to keeping caches in sync. So imagine if you had two different users and you weren't using this and you wanted to display the time in the time zone, you would have to break the cache every time someone else viewed that page or you'd have to save multiple caches for different time zones which is overwhelming, so since you wouldn't get benefit out of that, the design here is to save a generic html tag, and then use JavaScript to manipulate it for the user. That is something that is a very wise choice here, and something you can probably take and implement in application in other areas and say which ones are good cases where this needs to be manipulated specifically of the user, and if we keep the html generate generic, then we can generate a version that the user needs to see with JavaScript, so that is a little tip on caching that just comes along with talking about time zones.

I hope you enjoyed this episode, and I will see you in the next one.

Transcript written by Miguel

Loading...

Subscribe to the newsletter

Join 18,000+ developers who get early access to new screencasts, articles, guides, updates, and more.

By clicking this button, you agree to the GoRails Terms of Service and Privacy Policy.

More of a social being? We're also on Twitter and YouTube.